Dev Study
AWSサービスの内部原理 コース

53. 拡張ファンアウト — 共有2MB/sの奪い合いをHTTP/2プッシュで解消する

DynamoDB編・Lambda編で見てきた「追記ログを何者が読むか」の総仕上げとして、Kinesisのシャードから複数のコンシューマがデータを受け取る2つの経路——pullで帯域を分け合う共有スループットと、pushで専用帯域をもらう拡張ファンアウト——を図で追っていきます。

① シャードは追記ログ — 読み手がpullで引く

プロデューサPutRecord / PutRecords
GetRecords(pull): 自分で引きにいく
シャード=追記ログ順序を保った不変のレコード列
コンシューマ1台読み取り最大2MB/s/シャード
  • 読み取りはpullモデル。コンシューマがGetRecordsを呼んでポーリングする(基礎編「ポーリング vs プッシュ」のpull側)。
  • シャード1本の読み取り上限は合計2MB/s(公式表記:「Fixed at a total of 2 MB/sec per shard」)。
  • 伝搬遅延(message propagation delay)とは、PutRecord/PutRecordsで送ったペイロードがGetRecordsやSubscribeToShardを通じてコンシューマに届くまでの時間。1コンシューマのとき平均約200ms。

シャードは追記ログで、標準コンシューマはそこから自分でGetRecordsを呼んで引いてくるpull型。1台なら2MB/sをまるごと使え、遅延は約200ms。

② 読者が増えると2MB/sを分け合う

シャード=追記ログ読み取り上限: 合計2MB/s(固定)
コンシューマA約0.67MB/s
コンシューマB約0.67MB/s
コンシューマC約0.67MB/s
3台で均等に読んだ場合の目安
  • 帯域は足し算で増えない。公式:「they all share this throughput. The sum of the throughputs they receive from the shard doesn't exceed 2 MB/sec」。OSで複数プロセスが同じ物理帯域を奪い合うのと同じ構図。
  • 公式が保証するのは「合計が2MB/sを超えない」ことだけで、均等に分配されるとは限らない(図の約0.67MB/sはあくまで均等時の目安)。
  • 取り分が減る → 未読が溜まる → 伝搬遅延が伸びる。5コンシューマで平均約1000ms(1台の約200msから悪化)。
  • 遅延の悪化は「帯域を分け合う」ことの直接の帰結であって、Kinesisが遅くなったわけではない。

共有スループットでは2MB/sは固定枠を全員で奪い合う。読者が増えるほど1者あたりの帯域が痩せ、伝搬遅延は1台の約200msから5台で約1000msへと伸びる。

③ 「引かせる」をやめ登録ごとに専用線を張る

シャード=追記ログ
登録コンシューマX専用 最大2MB/s
登録コンシューマY専用 最大2MB/s
登録コンシューマZ専用 最大2MB/s
他の台数に依存しない
  • 公式:「Each consumer registered to use enhanced fan-out receives its own read throughput per shard, up to 2 MB/sec, independently of other consumers.」
  • 共有(②)は1本の枠を分ける「割り算」、専有(③)は登録ごとに枠が増える。OSでのリソース共有と専有割当の対比と同じ。
  • 各パイプは「up to 2 MB/sec of data per shard, independently of any other pipes or of the total number of consumers」。
  • KCL 2.0以降を使うと、全シャードへの登録・購読を自動でセットアップしてくれる。API直叩きなら個々のシャードを購読できる。

拡張ファンアウトは「分け合う1枠」を「登録ごとの専用枠」に変える。台数が増えても1者あたり最大2MB/sは目減りしない——これが読者スケールの鍵。

④ GetRecords(pull)からSubscribeToShard(HTTP/2 push)へ

標準(共有)GetRecordsを何度も呼ぶ(polling)
拡張ファンアウトSubscribeToShardで購読=HTTP/2接続を確立
pull: 取りにいく呼ばれたら返す
push: 押し込むHTTP/2接続上のイベントストリームで連続配信
  • pull(GetRecords)=基礎編SQS側の考え方。push(SubscribeToShard)=基礎編SNS側の考え方。Kinesisは同じログに対して両方の読み取り経路を選べるのが特徴。
  • 基礎編のHTTP/2(1本の持続接続の上でストリーミングできる)がここで効く。公式:「Kinesis Data Streams pushes the records to you over HTTP/2 using SubscribeToShard」。
  • 購読は張りっぱなしではなく最大5分で失効する。受信を続けるにはSubscribeToShardを再度呼んで購読を更新する(呼び出しは登録コンシューマ×シャードの組ごとに毎秒1回まで)。KCL 2.0以降はこの更新を自動でやってくれる。
  • push化により、伝搬遅延はコンシューマが1台でも5台でも平均約70ms(共有の200ms→1000msと違い、読者が増えても悪化しない)。

拡張ファンアウトはpull(GetRecords)をやめ、SubscribeToShardで張ったHTTP/2接続の上をKinesisが押し込むpush配送に切り替える。ゆえに遅延は1台でも5台でも約70msで安定する。

⑤ 登録上限とコスト — 「何者が読むか」の設計判断

何者が読む?このシャードのログの読者と遅延要件
共有スループットpull・2MB/sを分け合う
読者少・遅延ゆるくてOK。登録不要・追加コスト無し
拡張ファンアウトpush・専用最大2MB/s
読者多・低遅延を各自に保証。要登録(上限あり)・従量コスト
  • 登録上限: On-demand StandardおよびProvisionedストリームで1ストリームあたり最大20コンシューマ。執筆時点の公式では、On-demand Advantageモードかつ対応リージョン(東京含む)に限り最大50まで登録可能。
  • コスト: 拡張ファンアウトには「data retrieval cost」と「consumer-shard hour cost」が発生する(共有側にはこの追加コストは無い)。
  • 選択は二者択一ではなくコンシューマ単位。低遅延が要るものだけ登録する運用ができる。

拡張ファンアウトは専用帯域とpush配送と引き換えに、登録上限(標準20)と従量コストを背負う。「同じログを何者が読むか」の答えとして、読者ごとにpull共有かpush専用かを選ぶのが設計の勘所。

公式ドキュメントで詳しく ↗