Kafkaの動作フロー解析

3.1 Kafkaのプロデューサー処理解析

3.1.1 書き込み方法

プロデューサーは、メッセージをブローカーにプッシュ(push)モードで送信します。各メッセージはパーティションに追加され、ディスクへの順次書き込みが行われます。これはランダムなメモリ書き込みよりも効率的であり、Kafkaのスループットを確保します。

3.1.2 パーティション(Partition)

メッセージはトピックに送信され、その内部ではパーティションログとして組織されます。各パーティション内のメッセージは順序付けられており、一意のオフセット値が割り当てられます。

  1. パーティション分割の理由
    • クラスター内の拡張性を向上させるため。
    • 並列性を高めるため。
  2. パーティションの選択基準
    • 指定されたパーティションを使用する。
    • キーが指定されている場合、キーのハッシュ値に基づいてパーティションを選択する。
    • どちらも指定されていない場合、ラウンドロビンでパーティションを選択する。

  class CustomPartitioner {
    public int partition(String topic, Object key, byte[] keyBytes, Object value, byte[] valueBytes, Cluster cluster) {
      List<PartitionInfo> partitions = cluster.partitionsForTopic(topic);
      int numPartitions = partitions.size();
      if (keyBytes == null) {
        int nextValue = getNextValue(topic);
        List<PartitionInfo> availablePartitions = cluster.availablePartitionsForTopic(topic);
        if (!availablePartitions.isEmpty()) {
          int part = Math.abs(nextValue) % availablePartitions.size();
          return availablePartitions.get(part).partition();
        } else {
          return Math.abs(nextValue) % numPartitions;
        }
      } else {
        return Math.abs(Utils.murmur2(keyBytes)) % numPartitions;
      }
    }
  }
  

3.1.3 レプリケーション(Replication)

同じパーティションには複数のレプリカを持つことができます。これにより、ブローカーがダウンした場合でもデータの可用性が保証されます。各パーティションのレプリカ間でリーダーが選出され、プロデューサーとコンシューマーはこのリーダーと通信します。

3.1.4 書き込みフロー

  1. プロデューサーはZookeeperからパーティションのリーダーを見つける。
  2. プロデューサーはメッセージをリーダーに送信する。
  3. リーダーはメッセージをローカルのログに書き込む。
  4. フォロワーはリーダーからメッセージを取得し、ローカルのログに書き込んでACKを返す。
  5. リーダーはすべてのISRからのACKを受け取ったらHWを更新してプロデューサーにACKを返す。

3.2 ブローカーによるメッセージ保存

3.2.1 保存方法

トピックは物理的に複数のパーティションに分割されます。各パーティションは個別のディレクトリを持ち、その中にメッセージとインデックスファイルが格納されます。


  [user@host logs]$ ll
  drwxrwxr-x. 2 user user  4096 8月   6 14:37 first-0
  drwxrwxr-x. 2 user user  4096 8月   6 14:35 first-1
  drwxrwxr-x. 2 user user  4096 8月   6 14:37 first-2
  [user@host logs]$ cd first-0
  [user@host first-0]$ ll
  -rw-rw-r--. 1 user user 10485760 8月   6 14:33 00000000000000000000.index
  -rw-rw-r--. 1 user user      219 8月   6 15:07 00000000000000000000.log
  -rw-rw-r--. 1 user user 10485756 8月   6 14:33 00000000000000000000.timeindex
  -rw-rw-r--. 1 user user        8 8月   6 14:37 leader-epoch-checkpoint
  

3.2.2 保存戦略

メッセージは消費されたかどうかに関わらず保持されます。古いデータの削除には以下の2つの戦略があります:

  1. 時間ベース:log.retention.hours=168
  2. サイズベース:log.retention.bytes=1073741824
Kafkaは特定のメッセージの読み取り時間がO(1)であるため、これらの戦略はパフォーマンス向上とは関係ありません。

3.2.3 Zookeeperの保存構造

注意:プロデューサーはZookeeperに登録しませんが、コンシューマーは登録します。

3.3 Kafkaのコンシューマー処理解析

Kafkaは2種類のコンシューマーAPIを提供しています:高レベルAPIと低レベルAPI。

3.3.1 高レベルAPI

高レベルAPIは簡単で、オフセット管理やパーティション管理などの詳細を気にする必要はありません。

3.3.2 低レベルAPI

低レベルAPIはより細かい制御が可能です。ただし、それらの管理は開発者自身が行う必要があります。

3.3.3 コンシューマーグループ

コンシューマーはグループとして動作し、一つのトピックを共有します。各パーティションは同一時間に一つのコンシューマーのみが読むことができますが、複数のグループが同時に同じパーティションを読むことは可能です。

3.3.4 消費方法

コンシューマーはプル(pull)モードでブローカーからデータを取得します。プッシュモードでは、異なる消費速度に対応するのが難しいため、Kafkaではプルモードが適しています。

3.3.5 コンシューマーグループの例

同一グループ内のコンシューマーは同一時間に一つのコンシューマーのみがメッセージを消費します。

タグ: Kafka ZooKeeper Producer consumer partition

9月3日 02:35 投稿