Kinesisにデータを送る際にシャードを固定したくなりまして。
どういう仕組みで割り当てられているのか分かりづらく、誰か図示でもしてくれてれば理解早かったのになーと思ったので書きます。
AWS Kinesis
とりあえずデータを送りつけるところ。詳しいことは別の何かを見てください!
LambdaとかS3とかDynamoDBとか、その後のデータの処理はお好きにどうぞ。
シャード
シャードは、ストリーム内のデータレコードの一意に識別されたグループです。ストリームは複数のシャードで構成され、各シャードが容量の 1 単位になります。各シャードは 読み取りは最大 5 transactions per second、データ読み取りの最大合計レートは 2 MB per second と 書き込みについては最大 1,000 records per second、データの最大書き込み合計レートは 1 MB per second (including partition keys) をサポートできます。ストリームのデータ容量は、ストリームに指定したシャードの数によって決まります。ストリームの総容量はシャードの容量の合計です。
参考: https://docs.aws.amazon.com/ja_jp/streams/latest/dev/key-concepts.html
とのことです。
まあ、いっぱいデータ送られてくるのを並列で処理したいときはシャード増やしましょう、っていう話です。
シャードが多いほど、お金はかかるのでその点は要注意です。
分割のルール
本題。
Kinesisでは、Kinesisに対してデータを送信する元が「パーティションキー」という値を使ってデータを投げつけています。
パーティションキーは、ストリーム内のデータをシャード単位でグループ化するために使用されます。Streams サービスでは、ストリームに属するデータレコードを複数のシャードに配分するとき、各データレコードに関連付けられたパーティションキーを使用して、配分先のシャードを決定します。パーティションキーは最大 256 バイト長の Unicode 文字列です。MD5 ハッシュ関数を使用してパーティションキーを 128 ビットの整数値にマッピングし、関連付けられたデータレコードをシャードにマッピングします。パーティションキーは、ストリームにデータを入力するアプリケーションによって指定されます。
参考: https://docs.aws.amazon.com/ja_jp/streams/latest/dev/key-concepts.html
Kinesis側は、このパーティションキーに応じて、どのシャードに割り当てるかを決めてるというわけです。
128ビットの整数値
こいつ10進数のことみたいです。
整数ってだけだと何進数か判断できなくてちょっと悩みました。普通MD5って16進数だしね。
で、その割り当てのルールはというと。
パーティションキー: 最大256バイトのUnicode文字列
↓
Hash化して128bitの整数値にマッピング(ハッシュキーと呼ばれてます)
↓
Hash化された整数値(ハッシュキー)が割り当てられたシャードにデータが送られる
的な感じです。
MD5の最大値は16進数で
FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
なので、これを10進数にすると
340282366920938463463374607431768211455
なわけです。
数えられんわ。
とにかく、こうして128bitの10進数が得られました。
Kinesisのシャードは、1シャードの場合 0~340282366920938463463374607431768211455
のハッシュキーが割り当てられています。
0から最大値ということですね。どんなパーティションキーがきても、hash化された値は最大で 340282366920938463463374607431768211455
なので、必ず1つのシャードに送られます。
最大値をmとし、均等に分割すると、シャードを2分割する場合は0~m/2, m/2+1~mの2つに、3分割する場合は0~m/3, m/3+1~2m/3, 2m/3+1~mの3つに分けることになります。
均等である必要はないと思いますが、特別な理由が無い限りは均等に配分して良いのではないでしょうか。
もうちょっと具体的に言うと、2つに分割したい場合は、340282366920938463463374607431768211455を半分にしてあげれば良いので、
shard1: 0 ~ 170141183460469231731687303715884105727
shard2: 170141183460469231731687303715884105728 ~ 340282366920938463463374607431768211455
に割り当てます。
4つに均等に分割したい場合は、
shard1: 0 ~ 85070591730234615865843651857942052863
shard2: 85070591730234615865843651857942052864 ~ 170141183460469231731687303715884105727
shard3: 170141183460469231731687303715884105728 ~ 255211775190703847597530955573826158591
shard4: 255211775190703847597530955573826158592 ~ 340282366920938463463374607431768211455
となります。
(桁数の多い計算には http://keisan.casio.jp/calculator こちらを利用させていただきました。)
具体例
例として、 partition-key-0001
という文字列をパーティションキーとした場合に、均等に4分割されたシャードのどこに割り当てられるかを図示したものを貼ります。
-
partition-key-0001
という文字列をパーティションキーとする - MD5でハッシュ化すると、
b7681e2243f62f440887b6d38c002537
という16進数の値が得られる - 2の16進数を10進数にすると
243789333289005976465737331408549979447
となる - 3の結果は上記shard1~shard4の範囲のうちshard3に該当しているので、パーティションキーに
partition-key-0001
を指定したデータはshard3に投げられる
となります。
ちなみに私が現在所属しているプロジェクトでは、userごとにshardを固定したかったので、userIdをそのままパーティションキーとしています。
誰かの参考になれば幸いです。
おしまい。