Apache Kafkaの基本まとめ
はじめに
最近kafkaを使用する機会があったため知識定着のためにまとめていこうかと思います。
ここではkafka connectやkafka streams、strimzi、実装などのお話は省かせていただきます。
kafkaの用途、目的
マイクロサービスアーキテクチャにおけるデータ連携
マイクロサービスアーキテクチャは複雑なシステムをサービス単位に分割することで、疎結合にすることで迅速な機能改修が可能になります。
しかし、多数のサービス間で直接データを受け渡そうとすると接続経路が複雑になり、データ流用の急激な増加により、サービスの負荷が急増します。
そのようなサービス間で大量のデータを受け渡すためのハブとして活用されます。
大量のデータをリアルタイムに処理する
例えば、株価や為替レートなどの金融データを分析し取引シグナルを生成するなど、大量データをリアルタイムに生成したい場合に活用されます。
後述で説明しますが、Kafkaはトピックと呼ばれるデータストリームを保持し、パーティションと呼ばれるトピックの分割を保持します。これにより、データを複数分散して保存することで、処理負荷を分散し、スループットを向上させることができます。
kafkaのアーキテクチャ
イベント
イベントとはKafkaのデータの単位のことです。メッセージやレコードと呼ばれることもあります。
実際にProducerの役割をするサービスがメッセージに特定の値を詰めて、Kafkaに送信します。
イベント内には以下のように4つのデータが存在します。
- key
- イベント格納先の振り分けや集約に使用されるデータ
- キーを設定しないことも可能
- value
- イベントで処理したいデータ本体
- 文字列、数値、JSON といった様々な形式のデータを値に指定可能
- header
- イベントのメタデータや補足情報を格納
- timestamp
- イベントが作成された時刻
- イベントが作成された時刻
書き込んだイベントはBrokerのディスクに保存され、読み出されてもすぐには削除されません。
一定期間が経過したイベントや、Partitionの最大容量を超えた分のイベントは自動的に削除されます。
Topic
メッセージを配信するための名前をつけたカテゴリのことです。
トピックは、複数のパーティション (Partition) に分割することができます。
Partition
Producerから送信されたイベントを保持する箱のことです。
Partitionは分割することができ、Partition数を増やすことでシステム全体のスループットを高めることができます。
Partitionに保存されたイベントはPartition内で連続した番号が割り振られます。この番号をOffsetといいます。
Offsetは、トピック内のパーティションにおけるメッセージの位置を表します。
Offsetが存在することで、どのメッセージまで処理したかを記録することができます。
オフセットは、0から始まり、メッセージが追加されるたびに1ずつ増加します。
Consumer
Kafkaトピックからメッセージを購読し、処理するクライアントアプリケーションのことです。
イベント呼び出し後、Partitionごとの処理済みOffsetを記録するコミットを行います。
Offsetをコミットしておくことで、何らかの理由でConsumerが停止した場合も次の起動時に以前のコミット済みOffsetからPartition内のイベントを読み直せます。
ただしOffsetのコミット前にConsumerが停止すると、最新のコミットから停止直前まで読み取ったOffsetのイベントを 2回読み取ることになるため、2回以上イベントを読みとっても問題にならないようConsumerの処理を冪等にしておくべきです。
1つ以上のConsumerをグルーピングしたConsumerGroupを構成することで、Topicから受信するイベントを負荷分散可能です。
以下はConsumerを複数にすることで同じトピックを購読することができ、並列実行を可能としています
ConsumerGroup内では1つのPartitionにつき1つのConsumerしかイベントを呼び出せないため、ConsumerGroup内で負荷分散可能なConsumerは最大Partition数までです。
ConsumerGroupのConsumerの数が増減した場合、ConsumerへのPartitionの際割り当て(リバランス)が自動的に行われます。
Broker
ProducerとConsumerがイベントを送受信する物理的な宛先のことです。
Brokerでクラスタを組むことで冗長化することができます。
実際にはPartition内のイベントはBroker間で複製されるため、一部のBrokerノードに障害が発生してもイベントが失われにくい仕組みになっています。
レプリケーションによる冗長化
-
各PartitionのイベントはKafkaが動作する複数のBrokerにコピーされます
-
レプリカ内で書き込み可能なPartitionをリーダーと呼び、それ以外のコピーはフォロワーと呼びます。
-
リーダーレプリカのBrokerに障害が発生した場合、別のBrokerにいるフォロワーの artitionがリーダーに昇格することで処理を続行させることができます。
-
BrokerはTopicに書き込まれたイベントをファイルに保存することで永続化します。
-
BrokerはReplicaごとにデータディレクトリを作成して、イベントは各ディレクトリ内のSegmentというファイルに書き込みます。
- このSegmentファイルの集合を、KafkaではLogと呼びます。
ZookeeperとController
Zookeeper
ZooKeeperは、Kafkaクラスタのメタデータを保存するための分散データベースです。具体的には、以下の情報等を保存します。
- Topicの一覧
- Topicの設定値
- Partitionの状態
- Brokerの一覧
- Brokerのアクセス制御リスト(ACL)
Controller
Controllerは、Kafkaクラスタ全体の管理を行う特別なBrokerのことです。
以下の役割等を果たします。
- トピックとパーティションの管理
- トピックの作成、削除、パーティション数の変更、リーダーの選定、レプリカの選定などの操作を行います。
- ZooKeeperとの同期
- ZooKeeperに保存されているメタデータを定期的に同期し、クラスタの状態を最新に保ちます。
- ISR(In-Sync Replica)の管理
- 各パーティションのISRを管理し、レプリケーションの整合性を保ちます。
- 各パーティションのISRを管理し、レプリケーションの整合性を保ちます。
KRaft
従来のZooKeeperベースのコントローラーではなく、Raftコンセンサスアルゴリズムと呼ばれる分散合意アルゴリズムを用いたコントローラーが導入されています。
Kafkaクラスターが自律的にリーダー選出やメタデータ管理をZooKeeperに依存することなく行います。
- KRaftモードは簡単に言うとZookeeperに保存されていたメタデータを全て各Brokerのローカルストレージで管理するようにしています。
- RaftベースのControllerを使用すると、以下の利点があります
- ZooKeeperが不要になるため、運用が簡素化
- ZooKeeperとの通信のオーバーヘッドがなくなり、metadataに直接アクセスできるなどパフォーマンス的に有利
Discussion