3.1 Kafkaのプロデューサー処理解析
3.1.1 書き込み方法
プロデューサーは、メッセージをブローカーにプッシュ(push)モードで送信します。各メッセージはパーティションに追加され、ディスクへの順次書き込みが行われます。これはランダムなメモリ書き込みよりも効率的であり、Kafkaのスループットを確保します。
3.1.2 パーティション(Partition)
メッセージはトピックに送信され、その内部ではパーティションログとして組織されます。各パーティション内のメッセージは順序付けられており、一意のオフセット値が割り当てられます。
- パーティション分割の理由
- クラスター内の拡張性を向上させるため。
- 並列性を高めるため。
- パーティションの選択基準
- 指定されたパーティションを使用する。
- キーが指定されている場合、キーのハッシュ値に基づいてパーティションを選択する。
- どちらも指定されていない場合、ラウンドロビンでパーティションを選択する。
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 書き込みフロー
- プロデューサーはZookeeperからパーティションのリーダーを見つける。
- プロデューサーはメッセージをリーダーに送信する。
- リーダーはメッセージをローカルのログに書き込む。
- フォロワーはリーダーからメッセージを取得し、ローカルのログに書き込んでACKを返す。
- リーダーはすべての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つの戦略があります:
- 時間ベース:log.retention.hours=168
- サイズベース:log.retention.bytes=1073741824
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 コンシューマーグループの例
同一グループ内のコンシューマーは同一時間に一つのコンシューマーのみがメッセージを消費します。