クラスタ構成の基本構造
Kafkaでは、Topicという論理的な単位が複数のPartitionに分割され、各Brokerに分散配置されます。各Partitionにはリーダーとフォロワーが存在し、リーダーがデータの読み書きを担当します。フォロワーはデータの複製を保持することで可用性を確保します。
メッセージの書き込みはリーダーに集中し、その後フォロワーに複製されます。この構造により、障害発生時でもデータの損失を最小限に抑えつつ継続運用が可能です。
メッセージの処理とOffset管理
ProducerはメッセージをPartitionに送信し、ConsumerはOffsetという位置情報をもとにメッセージの消費位置を管理します。OffsetはConsumerグループごとに管理され、Consumerが処理完了後にKafkaに送信して記録します。
Offsetのコミット方法には2種類があります:
- 同期コミット: メッセージ処理後明示的にコミットするためデータ損失のリスクが少ないが、パフォーマンスが低下する。
- 非同期コミット: 処理と同時にバックグラウンドでコミットするため高速だが、処理失敗時にメッセージが失われる可能性がある。
インターセプターの利用
ProducerやConsumerにはインターセプターを設定でき、メッセージ処理の前後で共通処理を挟むことが可能です。以下はインターセプターの例です:
public class CustomInterceptor implements ConsumerInterceptor<String, String> {
@Override
public ConsumerRecords<String, String> onConsume(ConsumerRecords<String, String> records) {
// メッセージ受信時の処理
return records;
}
@Override
public void onCommit(Map<TopicPartition, OffsetAndMetadata> offsets) {
// Offsetコミット時の処理
}
}
シリアライズと通信
ネットワーク経由でのデータ送受信のため、Kafkaではシリアライズとデシリアライズが必要です。KafkaはStringやJSONなど基本的な型をサポートしますが、カスタムのシリアライザーも実装可能です。
以下はYAMLでの設定例です:
spring:
kafka:
producer:
key-serializer: org.apache.kafka.common.serialization.StringSerializer
value-serializer: org.apache.kafka.common.serialization.StringSerializer
consumer:
key-deserializer: org.apache.kafka.common.serialization.StringDeserializer
value-deserializer: org.apache.kafka.common.serialization.StringDeserializer
パーティション割り当て戦略
Consumerグループ内の各インスタンスがどのPartitionを処理するかは、以下の戦略によって決まります:
- Range: Partitionを連続区間で割り当てます。
- Round-robin: パーティションをインスタンス間で順番に割り当てます。
- Sticky: 前回の割り当てをできるだけ維持します。
Producerのバッチ送信とバッファ管理
KafkaのProducerはRecordAccumulatorを通じてメッセージをバッチ化し、一定量をまとめて送信します。この仕組みによりネットワーク負荷を軽減しつつ、高スループットを実現します。
メッセージはPartitionごとにバッファリングされ、以下の条件で送信されます:
- バッチサイズに到達
- 一定時間(linger.ms)が経過
メッセージの確認応答(acks)
acksパラメータによって、ProducerがBrokerからの応答をどの程度待つかが決まります:
- acks=0: 応答を待たず送信のみ。
- acks=1: リーダーに書き込まれたことを確認。
- acks=all: リーダーとフォロワーの全ノードで書き込み完了を確認。
べき等性の実現
KafkaはProducerごとにPID(Producer ID)を割り当て、Partitionごとにシーケンス番号を管理します。Brokerは受信時にこの番号をチェックし、重複メッセージの処理を回避します。
ZooKeeperとの連携
Kafkaのクラスタ管理にはZooKeeperが利用され、Controller Brokerがクラスタ全体の管理を行います。Controller Brokerは以下の役割を担います:
- Brokerの追加・削除を検知
- TopicやPartitionの変更を管理
- メタデータの更新と配布
リーダー選出とISR管理
Partitionのリーダー選出は、ISR(In-Sync Replica)の中から行われます。ISRにはリーダーと同期が取れているフォロワーのみが含まれます。
リーダーがダウンした場合、ISR内のフォロワーが新たなリーダーに選出されますが、HW(High Watermark)に基づいてデータの一貫性を保ちます。
自動バランス機能
Kafkaは定期的にリーダーの負荷バランスをチェックし、不均衡が発生した場合にリバランスを自動で実行します。この機能は以下のパラメータで制御されます:
auto.leader.rebalance.enable: 自動リバランスの有効化leader.imbalance.check.interval.seconds: チェック間隔leader.imbalance.per.broker.percentage: 不均衡の閾値