AWS CLIを使ってKinesis Streamをリシャーディングしてみた

**2016/7/27 追記有り**

KinesisStreamのシャード分割・結合について、日本語の情報に不足を感じたので自分自身が戸惑った事象についてメモ。
環境やパスは適宜読み替えてください。

#CLIこと始め
この辺を参考にインストールしてどうぞ。
[AWS CLIをWindowsにインストール・初期設定する手順](https://www.lancork.net/2014/03/how-to-install-setting-aws-cli-on-windows/)
[Windows Server への AWS CLIのインストール](http://dev.classmethod.jp/cloud/aws/install-aws-cli-to-windows-server/)
※cmdとPSの違いがありますが、インストールすればどちらも使えるようになります。私は面倒なのでcmd生で。

#Streamの作成

```bat
# 作成
aws kinesis create-stream --stream-name MyStream --shard-count 1

# 確認
aws kinesis describe-stream --stream-name MyStream
# 作成中
{
    "StreamDescription": {
        "RetentionPeriodHours": 24,
        "StreamName": "MyStream",
        "Shards": [],
        "StreamARN": "arn:aws:kinesis:ap-northeast-1:{AccountId}:stream/MyStream",
        "EnhancedMonitoring": [
            {
                "ShardLevelMetrics": []
            }
        ],
        "StreamStatus": "CREATING"
    }
}
# 作成完了
{
    "StreamDescription": {
        "RetentionPeriodHours": 24,
        "StreamName": "MyStream",
        "Shards": [
            {
                "ShardId": "shardId-000000000000",
                "HashKeyRange": {
                    "EndingHashKey": "340282366920938463463374607431768211455",
                    "StartingHashKey": "0"
                },
                "SequenceNumberRange": {
                    "StartingSequenceNumber": "49564038576867200623943064147577467982341808408192090114"
                }
            }
        ],
        "StreamARN": "arn:aws:kinesis:ap-northeast-1:{AccountId}:stream/MyStream",
        "EnhancedMonitoring": [
            {
                "ShardLevelMetrics": []
            }
        ],
        "StreamStatus": "ACTIVE"
    }
}
```

#Put/Get
[この記事](http://qiita.com/oshiro/items/47e6052bbeb5954a69ed)を参考にお試しを。
本記事のメインはシャードの分割結合なのでココはサボります。

#Shardの分割
##基本構文
```
aws kinesis split-shard --stream-name MyStream --shard-to-split {ShardId} --new-starting-hash-key {HashKey}
```
**{ShardId}**
分割対象のシャードIDを指定します。
今回は作成したばかりの *shardId-000000000000* を使います。
**{HashKey}**
シャードを分割する位置・INDEXを指定します。
HashKeyはデカい数字で表わされるので、分割数によって手動で計算することになります。
今回は *340282366920938463463374607431768211455* がEndingHashKeyなので、

* 例えば２分割する場合は…170141183460469231731687303715884105727
* 例えば３分割する場合は…113427455640312821154458202477256070485

を指定すると良いでしょう。
*均等に分割すべきか否か、どんなメリットがあるかは不明です。
有識者の方のコメントを期待します。。*

桁数がバカでかいのでWindowsの電卓やExcelでは計算できません。
[ココ](http://keisan.casio.jp/calculator)辺りを活用してください。
桁数は42以上を指定で賄えるはずです。

##分割イメージ
上記で３分割する場合の話が出ましたが、分割したシャードには親子関係があります。
また一度の分割では１シャードを２つのシャードに分割にすることのみ可能で、
一発で３分割するようなことはできません。
例）shardId-000000000000を1:2で分割し、分割した2の方をさらに分割

```
　shardId-000000000000
　　┣ shardId-000000000001      [*]
　　┗ shardId-000000000002
　　　　┣ shardId-000000000003  [*]
　　　　┗ shardId-000000000004  [*]
```
※[*]マークのシャードがOPENシャードです。

```bat
# 分割してみた
aws kinesis describe-stream --stream-name MyStream
{
    "StreamDescription": {
        "RetentionPeriodHours": 24,
        "StreamName": "MyStream",
        "Shards": [
            {
                "ShardId": "shardId-000000000000",
                "HashKeyRange": {
                    "EndingHashKey": "340282366920938463463374607431768211455",
                    "StartingHashKey": "0"
                },
                "SequenceNumberRange": {
                    "EndingSequenceNumber": "49564038576878350996542329459147026915659220410261569538",
                    "StartingSequenceNumber": "49564038576867200623943064147577467982341808408192090114"
                }
            },
            {
                "ShardId": "shardId-000000000001",
                "HashKeyRange": {
                    "EndingHashKey": "113427455640312821154458202477256070484",
                    "StartingHashKey": "0"
                },
                "ParentShardId": "shardId-000000000000",
                "SequenceNumberRange": {
                    "StartingSequenceNumber": "49564042224577792002398560785433370121162354099113426962"
                }
            },
            {
                "ShardId": "shardId-000000000002",
                "HashKeyRange": {
                    "EndingHashKey": "340282366920938463463374607431768211455",
                    "StartingHashKey": "113427455640312821154458202477256070485"
                },
                "ParentShardId": "shardId-000000000000",
                "SequenceNumberRange": {
                    "EndingSequenceNumber": "49564042224611243120196356720144464772751719433901178914",
                    "StartingSequenceNumber": "49564042224600092747597091408574905839435002460619407394"
                }
            },
            {
                "ShardId": "shardId-000000000003",
                "HashKeyRange": {
                    "EndingHashKey": "226854911280625642308916404954512140969",
                    "StartingHashKey": "113427455640312821154458202477256070485"
                },
                "ParentShardId": "shardId-000000000002",
                "SequenceNumberRange": {
                    "StartingSequenceNumber": "49564042263514893119033028790554734225206400778978197554"
                }
            },
            {
                "ShardId": "shardId-000000000004",
                "HashKeyRange": {
                    "EndingHashKey": "340282366920938463463374607431768211455",
                    "StartingHashKey": "226854911280625642308916404954512140970"
                },
                "ParentShardId": "shardId-000000000002",
                "SequenceNumberRange": {
                    "StartingSequenceNumber": "49564042263537193864231559413696269943479049140484177986"
                }
            }
        ],
        "StreamARN": "arn:aws:kinesis:ap-northeast-1:{AccountId}:stream/MyStream",
        "EnhancedMonitoring": [
            {
                "ShardLevelMetrics": []
            }
        ],
        "StreamStatus": "ACTIVE"
    }
}
```

#Shardの結合
##基本構文
```
aws kinesis merge-shards --stream-name MyStream --shard-to-merge {ShardId1} --adjacent-shard-to-merge {ShardId2}
```
**{ShardId1}**
結合するシャードID１
**{ShardId2}**
結合するシャードID２

##結合できるもの
シャードの分割を行なう際に指定したHashKeyを境に、StartingHashKeyとEndingHashKeyがセットされます。
結合できるシャードは、**HashKeyが連番になるシャード群**となります。
また指定するシャードの順番も、**HashKeyがStart→Endと並ぶようにする**必要があります。
このとき、**親子関係や分割元は関係ありません**。

例）
結合できない：shardId-000000000001とshardId-000000000004
結合できる　：shardId-000000000001とshardId-000000000003
　　　　　　　shardId-000000000003とshardId-000000000004
※当然CLOSEDシャードは指定できません。

```bat
# 結合してみた１：1と3から5を作成
aws kinesis merge-shards --stream-name MyStream --shard-to-merge shardId-000000000001 --adjacent-shard-to-merge shardId-000000000003
{
    "StreamDescription": {
        ～略～
        "Shards": [
            ～略～
            {
                "ShardId": "shardId-000000000001",
                "HashKeyRange": {
                    "EndingHashKey": "113427455640312821154458202477256070484",
                    "StartingHashKey": "0"
                },
                "ParentShardId": "shardId-000000000000",
                "SequenceNumberRange": {
                    "EndingSequenceNumber": "49564042224588942374997826097002929054479099659697520658",
                    "StartingSequenceNumber": "49564042224577792002398560785433370121162354099113426962"
                }
            },
            ～略～
            {
                "ShardId": "shardId-000000000003",
                "HashKeyRange": {
                    "EndingHashKey": "226854911280625642308916404954512140969",
                    "StartingHashKey": "113427455640312821154458202477256070485"
                },
                "ParentShardId": "shardId-000000000002",
                "SequenceNumberRange": {
                    "EndingSequenceNumber": "49564042263526043491632294102124293158523138849139327026",
                    "StartingSequenceNumber": "49564042263514893119033028790554734225206400778978197554"
                }
            },
            ～略～
            {
                "ShardId": "shardId-000000000005",
                "HashKeyRange": {
                    "EndingHashKey": "226854911280625642308916404954512140969",
                    "StartingHashKey": "0"
                },
                "ParentShardId": "shardId-000000000001",
                "AdjacentParentShardId": "shardId-000000000003",
                "SequenceNumberRange": {
                    "StartingSequenceNumber": "49564042411993254650849917666899546484499220273098129490"
                }
            }
        ],
        ～略～
    }
}
# 結合してみた２：5と4から6を作成（順番に注意）
aws kinesis merge-shards --stream-name MyStream --shard-to-merge shardId-000000000005 --adjacent-shard-to-merge shardId-000000000004
{
    "StreamDescription": {
        ～略～
        "Shards": [
            ～略～
            {
                "ShardId": "shardId-000000000004",
                "HashKeyRange": {
                    "EndingHashKey": "340282366920938463463374607431768211455",
                    "StartingHashKey": "226854911280625642308916404954512140970"
                },
                "ParentShardId": "shardId-000000000002",
                "SequenceNumberRange": {
                    "EndingSequenceNumber": "49564042263548344236830824725265828876795820127274664002",
                    "StartingSequenceNumber": "49564042263537193864231559413696269943479049140484177986"
                }
            },
            {
                "ShardId": "shardId-000000000005",
                "HashKeyRange": {
                    "EndingHashKey": "226854911280625642308916404954512140969",
                    "StartingHashKey": "0"
                },
                "ParentShardId": "shardId-000000000001",
                "AdjacentParentShardId": "shardId-000000000003",
                "SequenceNumberRange": {
                    "EndingSequenceNumber": "49564042412004405023449182978469105417815962672586293330",
                    "StartingSequenceNumber": "49564042411993254650849917666899546484499220273098129490"
                }
            },
            {
                "ShardId": "shardId-000000000006",
                "HashKeyRange": {
                    "EndingHashKey": "340282366920938463463374607431768211455",
                    "StartingHashKey": "0"
                },
                "ParentShardId": "shardId-000000000005",
                "AdjacentParentShardId": "shardId-000000000004",
                "SequenceNumberRange": {
                    "StartingSequenceNumber": "49564042582928466597587144046770827044348944133067374690"
                }
            }
        ],
        ～略～
    }
}
```

#知りたかったこと！！
##分割・結合したあとどうなるの？
　ここまでの手順で、以下のような親子関係で7シャードが存在する状態となります。

```
　　shardId-000000000000
　　　┣ shardId-000000000001 ━━┓
　　　┗ shardId-000000000002　　 ┣ shardId-000000000005 ┓
　　　　　┣ shardId-000000000003 ┛　　　　　　　　　　　　┣ shardId-000000000006
　　　　　┗ shardId-000000000004 ━━━━━━━━━━━━━┛
```

　ポイントは、**分割・結合したシャードはCLOSED状態となり、新たに作成されたシャードがOPEN状態になる**ということです。
　よって**OPEN状態なのは_shardId-000000000006_のみ、それ以外はCLOSED状態**となります。
　[OPEN/CLOSEDの意味は公式から引用](https://docs.aws.amazon.com/ja_jp/streams/latest/dev/kinesis-using-sdk-java-after-resharding.html)
>* OPEN: リシャーディングオペレーションの前、親シャードは OPEN 状態にあります。つまり、データレコードはシャードへの追加とシャードからの取得のいずれも可能です。
>* CLOSED: リシャーディングオペレーションの後、親シャードは CLOSED 状態に移行します。つまり、データレコードはシャードに追加されなくなります。このシャードに追加されることになっていたデータレコードは、子シャードに追加されるようになります。ただし、データレコードは引き続き、制限された時間内にシャードから取得できます。
>* 期限切れ: ストリーム保持期間の有効期限が切れたら、親シャードのすべてのデータレコードの期限も切れてアクセスできなくなります。この時点で、シャード自体は EXPIRED 状態に移行します。getStreamDescription().getShards を呼び出してストリーム内のシャードを列挙しても、返されるシャードのリストには 状態のシャードは含まれません。EXPIREDストリームの保持期間の詳細については、「データ保持期間の変更」を参照してください。

　AWSのコンソールでは以下のように表示されるハズ
![image](https://qiita-image-store.s3.amazonaws.com/0/78880/eaffbf8a-f4ba-d3bf-8474-0f7e740c8d6c.png)


##料金はどこにかかるの？
　涙の数だけ強くなれるように、シャードの数だけ金がかかります。
　[料金構成](https://aws.amazon.com/jp/kinesis/streams/pricing/)
　よっていたずらに分割結合を繰り返すとその分だけ費用がかさむので気を付けましょう。
　また**CLOSEDのシャードにも料金がかかります**。

　CLOSEDシャードがEXPIREDになるのは、設定したデータレコードの保持期間が過ぎたタイミングです。
　*言い切ってますが確証なし。Amazonに確認中。*
　データレコードの保持期間はデフォルト24時間、最大168時間まで1時間単位で設定可能です。
　[データ保持期間の変更](https://docs.aws.amazon.com/ja_jp/streams/latest/dev/kinesis-extended-retention.html)
>Amazon Kinesis stream は 24 時間レコードを保持し、最大値は 168 時間です。

#その他
流れだけ分かったら、公式ドキュメントも熟読することをオススメします。
[ストリームをリシャーディングする](https://docs.aws.amazon.com/ja_jp/streams/latest/dev/kinesis-using-sdk-java-resharding.html)
大事なことがサラっと書かれていたりしますので。

#Thanks for
本記事を作成するにあたり、以下の記事を参考にさせてもらいました。
[AWS CLIを使って初めてAmazon Kinesisを使ってみた](http://qiita.com/toshihirock/items/86a7d5144ad54b18bf36)
[Kinesisの雰囲気をつかむためにawscliで操作する](http://qiita.com/oshiro/items/47e6052bbeb5954a69ed)
ありがとうございます！！

#あとしまつ
```bat
# 削除
aws kinesis delete-stream --stream-name MyStream
# 削除中
aws kinesis describe-stream --stream-name MyStream
{
    "StreamDescription": {
        "RetentionPeriodHours": 24,
        "StreamName": "MyStream",
        "Shards": [],
        "StreamARN": "arn:aws:kinesis:ap-northeast-1:{AccountId}:stream/MyStream",
        "EnhancedMonitoring": [
            {
                "ShardLevelMetrics": []
            }
        ],
        "StreamStatus": "DELETING"
    }
}
# 削除後
aws kinesis describe-stream --stream-name MyStream
An error occurred (ResourceNotFoundException) when calling the DescribeStream operation: Stream MyStream under account {AccountId} not found.
```


誤りや補足、その他ありましたらコメントください。
それではゴキゲンなAWSライフを！

P.S
しかしこのコードブロックに設定すべき適切なシンタックスハイライト、なんだろうな…
いまいち美しくない…

#2016/7/27 追記
>最初からShard数が2とかだったらどうなんの？

って同僚に聞かれたので調べました。

結論から言えば、**単純にStart/Endが連続したHashKeyを持つシャード0と1が作られる**だけです。
##Shard作成
```bat
C:\Users\Administrator>aws kinesis create-stream --stream-name MyStream2 --shard-count 2

C:\Users\Administrator>aws kinesis describe-stream --stream-name MyStream2
{
    "StreamDescription": {
        "RetentionPeriodHours": 24,
        "StreamName": "MyStream2",
        "Shards": [],
        "StreamARN": "arn:aws:kinesis:ap-northeast-1:{AccountId}:stream/MyStream2",
        "EnhancedMonitoring": [
            {
                "ShardLevelMetrics": []
            }
        ],
        "StreamStatus": "CREATING"
    }
}
C:\Users\Administrator>aws kinesis describe-stream --stream-name MyStream2
{
    "StreamDescription": {
        "RetentionPeriodHours": 24,
        "StreamName": "MyStream2",
        "Shards": [
            {
                "ShardId": "shardId-000000000000",
                "HashKeyRange": {
                    "EndingHashKey": "170141183460469231731687303715884105727",
                    "StartingHashKey": "0"
                },
                "SequenceNumberRange": {
                    "StartingSequenceNumber": "49564222136977019153325816905058856343758519904923287554"
                }
            },
            {
                "ShardId": "shardId-000000000001",
                "HashKeyRange": {
                    "EndingHashKey": "340282366920938463463374607431768211455",
                    "StartingHashKey": "170141183460469231731687303715884105728"
                },
                "SequenceNumberRange": {
                    "StartingSequenceNumber": "49564222136999319898524347528200392062031168266429267986"
                }
            }
        ],
        "StreamARN": "arn:aws:kinesis:ap-northeast-1:{AccountId}:stream/MyStream2",
        "EnhancedMonitoring": [
            {
                "ShardLevelMetrics": []
            }
        ],
        "StreamStatus": "ACTIVE"
    }
}
```
##Shard分割
```bat
C:\Users\Administrator>aws kinesis split-shard --stream-name MyStream2 --shard-to-split shardId-000000000001 --new-starting-hash-key 25521177519070384
7597530955573826158591

C:\Users\Administrator>aws kinesis describe-stream --stream-name MyStream2
{
    "StreamDescription": {
        "RetentionPeriodHours": 24,
        "StreamName": "MyStream2",
        "Shards": [
            {
                "ShardId": "shardId-000000000000",
                "HashKeyRange": {
                    "EndingHashKey": "170141183460469231731687303715884105727",
                    "StartingHashKey": "0"
                },
                "SequenceNumberRange": {
                    "StartingSequenceNumber": "49564222136977019153325816905058856343758519904923287554"
                }
            },
            {
                "ShardId": "shardId-000000000001",
                "HashKeyRange": {
                    "EndingHashKey": "340282366920938463463374607431768211455",
                    "StartingHashKey": "170141183460469231731687303715884105728"
                },
                "SequenceNumberRange": {
                    "EndingSequenceNumber": "49564222137010470271123612839769950995347893348609294354",
                    "StartingSequenceNumber": "49564222136999319898524347528200392062031168266429267986"
                }
            },
            {
                "ShardId": "shardId-000000000002",
                "HashKeyRange": {
                    "EndingHashKey": "255211775190703847597530955573826158590",
                    "StartingHashKey": "170141183460469231731687303715884105728"
                },
                "ParentShardId": "shardId-000000000001",
                "SequenceNumberRange": {
                    "StartingSequenceNumber": "49564222218017927204786101401399656546562681216977338402"
                }
            },
            {
                "ShardId": "shardId-000000000003",
                "HashKeyRange": {
                    "EndingHashKey": "340282366920938463463374607431768211455",
                    "StartingHashKey": "255211775190703847597530955573826158591"
                },
                "ParentShardId": "shardId-000000000001",
                "SequenceNumberRange": {
                    "StartingSequenceNumber": "49564222218040227949984632024541192264835329578483318834"
                }
            }
        ],
        "StreamARN": "arn:aws:kinesis:ap-northeast-1:{AccountId}:stream/MyStream2",
        "EnhancedMonitoring": [
            {
                "ShardLevelMetrics": []
            }
        ],
        "StreamStatus": "ACTIVE"
    }
}
```
##Shard結合
```bat
C:\Users\Administrator>aws kinesis merge-shards --stream-name MyStream2 --shard-to-merge shardId-000000000000 --adjacent-shard-to-merge shardId-000000
000002

C:\Users\Administrator>aws kinesis describe-stream --stream-name MyStream2
{
    "StreamDescription": {
        "RetentionPeriodHours": 24,
        "StreamName": "MyStream2",
        "Shards": [
            {
                "ShardId": "shardId-000000000000",
                "HashKeyRange": {
                    "EndingHashKey": "170141183460469231731687303715884105727",
                    "StartingHashKey": "0"
                },
                "SequenceNumberRange": {
                    "EndingSequenceNumber": "49564222136988169525925082216628415277075252202648371202",
                    "StartingSequenceNumber": "49564222136977019153325816905058856343758519904923287554"
                }
            },
            {
                "ShardId": "shardId-000000000001",
                "HashKeyRange": {
                    "EndingHashKey": "340282366920938463463374607431768211455",
                    "StartingHashKey": "170141183460469231731687303715884105728"
                },
                "SequenceNumberRange": {
                    "EndingSequenceNumber": "49564222137010470271123612839769950995347893348609294354",
                    "StartingSequenceNumber": "49564222136999319898524347528200392062031168266429267986"
                }
            },
            {
                "ShardId": "shardId-000000000002",
                "HashKeyRange": {
                    "EndingHashKey": "255211775190703847597530955573826158590",
                    "StartingHashKey": "170141183460469231731687303715884105728"
                },
                "ParentShardId": "shardId-000000000001",
                "SequenceNumberRange": {
                    "EndingSequenceNumber": "49564222218029077577385366712969215479879397915381202978",
                    "StartingSequenceNumber": "49564222218017927204786101401399656546562681216977338402"
                }
            },
            {
                "ShardId": "shardId-000000000003",
                "HashKeyRange": {
                    "EndingHashKey": "340282366920938463463374607431768211455",
                    "StartingHashKey": "255211775190703847597530955573826158591"
                },
                "ParentShardId": "shardId-000000000001",
                "SequenceNumberRange": {
                    "StartingSequenceNumber": "49564222218040227949984632024541192264835329578483318834"
                }
            },
            {
                "ShardId": "shardId-000000000004",
                "HashKeyRange": {
                    "EndingHashKey": "255211775190703847597530955573826158590",
                    "StartingHashKey": "0"
                },
                "ParentShardId": "shardId-000000000000",
                "AdjacentParentShardId": "shardId-000000000002",
                "SequenceNumberRange": {
                    "StartingSequenceNumber": "49564222255527780628714609525462734681157232485581455426"
                }
            }
        ],
        "StreamARN": "arn:aws:kinesis:ap-northeast-1:{AccountId}:stream/MyStream2",
        "EnhancedMonitoring": [
            {
                "ShardLevelMetrics": []
            }
        ],
        "StreamStatus": "ACTIVE"
    }
}
```
##あとしまつ
```
aws kinesis delete-stream --stream-name MyStream2
```