Kafka は、矢印が出入りする「Kafka」と書かれた 1 つの箱として簡単に描けます。しかしその箱は、人々が頼りにしているすべての性質を隠してしまいます。何が順序付けられ、何が順序付けられないのか、データのコピーがいくつあるのか、ブローカーが落ちたらどうなるのか、そして複数のサービスがお互いに干渉せずに同じストリームをどう読めるのか、です。
この記事では、重要な構成要素を備えた Kafka クラスターを図にします。ブローカー、トピックとパーティション、リーダーとフォロワーのレプリカ、キーを持つプロデューサー、コンシューマーグループとオフセット、そしてクラスターを管理する KRaft コントローラーです。
トピック、パーティション、ブローカー
トピック は、orders のような名前の付いたレコードのストリームです。各トピックは パーティション に分割され、各パーティションは追記専用のログで、すべてのレコードに増え続ける オフセット が付きます。
パーティションはあらゆるものの単位です。
- 順序: レコードはパーティション内では順序付けられますが、パーティションをまたいだ順序はありません。
- 並列性: 1 つのグループ内でトピックを消費できるコンシューマーの数は、最大でもパーティション数までです。
- 配置: パーティションは、クラスターのサーバーである ブローカー に分散されます。
パーティション数は、トピックごとに必要なスループットと、並列に動かしたいコンシューマーの数から、余裕を持たせて決めます。後からパーティションを追加することもできますが、キーがどのパーティションに割り当てられるかが変わります。
レプリケーション
各パーティションにはレプリケーション係数があり、通常は 3 です。1 つのレプリカが リーダー として読み書きを処理し、残りはリーダーのログをコピーする フォロワー です。追いついているフォロワーは ISR(in-sync replica の集合)を構成します。リーダーのブローカーが落ちると、追いついているフォロワーが新しいリーダーになります。
耐久性を決める設定は次のとおりです。
| 設定 | 場所 | 典型的な値 | 効果 |
|---|---|---|---|
replication.factor |
トピック | 3 | 各パーティションのコピー数 |
min.insync.replicas |
トピックまたはブローカー | 2 | 書き込みが有効になる前に、その書き込みを持っている必要があるレプリカの数 |
acks |
プロデューサー | all |
成功とする前にすべての同期レプリカを待つ |
係数 3、min.insync.replicas=2、acks=all の組み合わせでは、確認応答された書き込みは少なくとも 2 台のブローカーに存在し、ブローカーが 1 台停止していてもクラスターは書き込みを受け付け続けます。これらの設定とその相互作用については、Kafka のドキュメント で説明されています。
プロデューサーとキー
プロデューサーは、レコードごとにパーティションを選びます。キーがある場合、デフォルトのパーティショナーはキーをハッシュするので、同じキーを持つレコードはすべて同じパーティションに入り、順序が保たれます。キーがない場合、レコードはバランスのために分散され、レコード間の順序は失われます。
キーは、イベントの順序を保つ必要があるエンティティから選びます。注文 ID やアカウント ID です。図ではプロデューサーにキーを書き込みましょう。キーは、プロデューサーが持つ設定の中で最も影響の大きいものです。少数の巨大な値に偏るキーは避けます。パーティションがいくつあっても、1 つのホットキーが 1 つのパーティションに負荷を集中させるからです。
再試行によってレコードが重複することがあります。最近の Kafka はデフォルトで冪等プロデューサーを有効にしており、パーティション内でプロデューサーの再試行による重複を取り除きます。ただし、アプリケーション自身の再試行による重複は依然として起こりうるので、コンシューマーも冪等にしておくべきです。
コンシューマーグループとオフセット
コンシューマーグループ は、1 つの目的のために作業を分担するコンシューマーの集まりです。Kafka は各パーティションをグループ内のちょうど 1 つのコンシューマーに割り当てるので、パーティションが 3 つなら忙しく働けるコンシューマーは最大 3 つで、4 つ目は遊んでしまいます。コンシューマーが参加したり離脱したりすると、グループはリバランスし、パーティションが移動します。
各グループは自分の位置、つまりパーティションごとのコミット済み オフセット を管理し、Kafka はそれを内部トピックに保存します。これによって、複数のサービスが同じストリームを独立して読めます。fulfillment と analytics はそれぞれ自分のグループと自分のオフセットを持ち、お互いに影響しません。
オフセットを処理の前ではなく後にコミットすると、at-least-once の処理になります。クラッシュの後、コンシューマーは最後のコミット以降のレコードを再処理します。繰り返しが無害になるよう、処理を冪等にしておきましょう。
リテンションとコンパクション
Kafka は、レコードが読まれた後も保持します。時間またはサイズに基づくリテンションは、たとえば 7 日後に古いセグメントを削除します。一方、ログコンパクションはキーごとに最新のレコードを無期限に保持し、トピックを現在の状態の変更履歴(changelog)に変えます。トピックごとに選びましょう。イベントには通常リテンションを使い、「顧客ごとの最新の住所」のような状態にはコンパクションを使います。
サイジングの計算例
チェックアウトがピーク時に 1 秒あたり 3,000 件の注文イベントを生成し、それぞれ約 1 KB、つまり 3 MB/s だとします。fulfillment サービスの 1 つのコンシューマーは 1 秒あたり 400 件のイベントを処理できます。ピーク時には少なくとも 8 つのコンシューマーを並列に動かす必要があるので、パーティションも少なくとも 8 つ必要です。成長と、障害を起こしたコンシューマーのパーティションの分の余裕を残すために 12 を選びます。レプリケーション係数が 3 なら、クラスターはブローカー全体で 9 MB/s をディスクに書き込み、このレートで 7 日間保持すると、複製後のデータは最大で約 5.4 TB になります。平均トラフィックはピークより少ないので、これはディスク計画の上限と考えてください。こうした数字は図の隣に置くべきです。ブローカーの台数とディスクを決めるのは、Kafka と書かれた箱ではなく、これらの数字だからです。
KRaft:ZooKeeper はもう不要
以前のクラスターはメタデータを ZooKeeper に保存していました。現在の Kafka は、KRaft と呼ばれる Raft ベースのコントローラーのクォーラムで、メタデータを自ら管理します。2025 年 3 月にリリースされた Kafka 4.0 は、ZooKeeper なしで完全に動作する最初のメジャーリリースです。図では、小規模なクラスターが同じマシンで両方の役割を動かしている場合でも、コントローラーのクォーラムはブローカーとは別に描きましょう。
アーキテクチャ図
ダイアグラムの内容
- Checkout service
- Payments service
- Broker 1: P0 leader, P1 P2 followers
- Broker 2: P1 leader, P0 P2 followers
- Broker 3: P2 leader, P0 P1 followers
- KRaft controllers
- Consumer group: fulfillment
- Consumer 1
- Consumer 2
- Consumer 3
- Analytics consumer
- order 8812 to P0
- order 9001 to P2
- replicate
- same events, separate group
- metadata
図の読み方は次のとおりです。
- 左: 2 つのプロデューサーが注文 ID をキーにしてイベントを送ります。注文 8812 はパーティション 0 に、注文 9001 はパーティション 2 にハッシュされます。
- 中央: 3 台のブローカーがあり、それぞれ 1 つのパーティションのリーダーで、残り 2 つのフォロワーです。破線のエッジはレプリケーションを示し、下にある KRaft コントローラーがメタデータとリーダー選出を管理します。
- 右: fulfillment グループには、パーティションごとに 1 つずつ、3 つのコンシューマーがいます。analytics のコンシューマーは別のグループに属しているので、自分のオフセットですべてのイベントを読みます。
- Markdown ブロック には、この図が前提としているトピックの設定を並べています。
Kafka の図に描くべきもの
- トピックごとのパーティション数とキー: 順序と並列性を決めるからです。
- レプリケーション係数と
min.insync.replicas: 耐久性を決めるからです。 - 名前付きの各コンシューマーグループ: コンシューマーと一緒に描きます。
- トピックごとのリテンションまたはコンパクション。
- 誰が生成し、誰が消費するか: サービスをまたいで描き、責任の所在を明確にします。
Kafka の上に構築するパターンについては、イベント駆動アーキテクチャの図、データベースから確実にパブリッシュするための トランザクショナルアウトボックスパターン、Kafka から分析へデータを流す データパイプラインのアーキテクチャ図 を参照してください。
Archboard で作る
- Google または GitHub でサインインし、図を作成します。
- C4 モデルパックからプロデューサー用に コンテナ ノードを追加し、説明にキーを書きます。
- データパックからブローカー用に Kafka ノードを 3 つ追加し、それぞれがリーダーとフォロワーを務めるパーティションをラベルに書きます。KRaft コントローラー用に コンテナ を 1 つ追加します。
- 基本パックからコンシューマーグループ用に フレーム を追加し、その中にコンシューマーごとに コンテナ を置きます。2 つ目のグループ用に別のコンシューマーも追加します。
- レプリケーションを破線のエッジで描き、トピックの設定を書いた基本パックの Markdown ブロックを追加します。
この例で使うダイアグラムノードは 12 個で、Free プランの範囲に収まります。
よくある質問
Kafka はメッセージの順序を保証しますか? パーティション内では保証します。パーティションをまたぐ順序は保証しません。順序を保つ必要があるレコードが同じパーティションに入るよう、キーを使います。
トピックにはいくつのパーティションが必要ですか? 必要なスループットと、並列に動かしたいコンシューマーの数を満たし、成長の余地もある数です。後から数を変えると、キーとパーティションの対応が変わります。
ブローカーが落ちるとどうなりますか?
そのブローカーがリーダーだった各パーティションについて、別のブローカー上の追いついているフォロワーがリーダーになります。レプリケーション係数 3 と min.insync.replicas=2 なら、書き込みは続きます。
コンシューマーグループとは何ですか? トピックのパーティションを分担するコンシューマーの集まりです。異なるグループは、それぞれ自分のオフセットで同じトピックを独立して読みます。
Kafka にはまだ ZooKeeper が必要ですか? いいえ。Kafka 4.0 以降は KRaft モードでのみ動作し、コントローラーのクォーラムがクラスターのメタデータを管理します。