Apache Kafkaについてまとめる

# この記事は？
ここではOSSの分散メッセージングシステムであるApache Kafkaについて調べまとめます。具体的には以下のようなことについてまとめます。

* Apache Kafkaの概要
* Kafkaのアーキテクチャ

# Apache Kafka の概要

Apache Kafka(以降、Kafka)はLinkedInによって開発された分散メッセージングシステムです。もともとは高スループットでリアルタイムにデータを扱うことを目的とし開発されました。

![kafka.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/202545/32455f69-3191-cb11-2e4e-52471f53fea9.png)

Kafkaではこれまでのメッセージキュー、ログコレクター、ETLツールなどでは対応しきれない要件に対応するために生まれました。Kafkaには以下のような特徴があります。

* 分散システム
* リアルタイムなデータ処理  
* 任意なタイミングでのデータ取り出しも可能
* At Least Oneの到達保証

## 分散システム
Kafkaは分散システムです。求められるビジネス要件に対してシステムを事前にスケールアウトさせておくことが可能です。
またデータのレプリケーションを行うことで耐障害性も担保しています。

## リアルタイムなデータ処理
Kafkaではデータの収集から数百ミリ秒から数秒の間でデータが処理されることが想定されます。分散システムであることにより高スループットを実現しています。また、**KafkaはExactly Onceの到達保証を行わない**選択をしスループットを優先した開発が行われています。

## 任意なタイミングでのデータ取り出し
Kafkaはバッチ処理などに対応できるようにデータをディスクにします。それにより比較的大量のデータを保持することが可能です。
ちなみにKafkaではデータの古いものから削除されますデータ保存マニフェストはデータの保存期間(デフォルト一週間)とデータ容量(デフォルト無制限)の2つが設定できます。
そのほかにも、同一のキーで最新のデータのみを保持したいなどの要件に対して、といったようなコンパクションもサポートしています。

## At Least Onceの到達保証
KafkaではAt Least One(最低、一回、複数回到達する可能性あり)の到達保証をサポートします。詳細は後程記述しますがシステムがメッセージの到達管理を行います。

## Kafkaの要件と他ツールとの比較
Kafkaは以下のようなことを解決することを目指して作成されています。

* リアルタイムでのメッセージのやり取り
* スケールアウト可能な構成
* 永続化可能
* 最低一回の送信保証

こういった要件をすべて満たすツールがそれまで利用されていたツールにはなくそのためにKafkaは開発されました。

|Kafkaの対応する要件|メッセージキュー|ログコレクター|ETLツール|  
|------|:------:|:------:|:------:|
|リアルタイム|〇|〇|×|
|スケールアウト可能|×|〇|〇|
|永続化|△(長期保存ができない)|×|×|
|送信保証|〇(ツールによっては強力すぎる)|△(トランザクション機能がない)|〇|

# Kafkaのアーキテクチャ
## Producer、Broker、Consumer
Kafkaでは大きく以下のようなシステム構成をとります。

![pbc.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/202545/f0c68b24-8005-d413-1092-30a45fae6f56.png)

ProducerとBroker、Consumerはそれぞれが分散してシステムを組むことが可能となっています。
また、BrokerのノードディスカバリにはApache ZooKeeperがつかわれるようです。
Producer、Broker、Consumerのそれぞれの説明を以降にまとめます。

### Producer
データの送信元Messageをブローカーへ送信するアプリケーションです。
Producerはライブラリとして提供されたProducer APIをKafkaを利用する開発者側で利用して作成します。
そのほかにもProducerの機能をプラグインとして提供するOSSも存在します。
ProducerはPush型です。

### Blocker 
データを受信配信する役割を持つサービスです。1つのデーモンプロセスとして動作し受信と配信のリクエストを受け付けます。取得したデータはすべてディスクへの永続化を行います。

### Consumer
BrokerからMessageを取得するアプリケーションです。Producerと同じくライブラリとして提供されるConsumer APIを利用し、
ConsumerはPull型として動作し、Consumer側のタイミングでMessageを取得することができます。

## データの単位、メッセージの送受信
Kafkaではデータの最小単位をMessageと呼びます。メッセージはKeyとValueを持っています。
Messageの種別ごとにTopicと呼ばれるストレージがBlocker内で用意されており、ProducerやConsumerはTopicを指定してメッセージの送受信を行います。

![topic.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/202545/0377d70c-5ede-1292-e372-f39b575695bc.png)

### パーティショニング
1つのTopicに対する大量の入出力に対応するためにBlockerはデータをパーティションと呼ばれる単位で分割してデータを扱います。パーティションはBlockerクラスタ内で分散して配置されます。ProducerからMessageを受け取る際にはKeyのハッシュを用いたパーティショニングとラウンドロビンによるパーティショニングが存在します。

![partition.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/202545/98483895-4ef3-4633-11c4-2fb2fa0b5cd5.png)

Keyのハッシュを用いる場合は同一Keyを同一のConsumerから取得することが可能といった制御ができるがパーティションで保持するデータの偏りに注意する必要があります。

### レプリケーション
Kafkaはサーバの故障などに備えデータをレプリケーションしています。

![replica.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/202545/6b3c7367-8f6b-e0e8-35b2-3f455bb46871.png)

レプリケーションはパーティションごとに行われ、それぞれ別のBlockerで管理されます。レプリカのうち1つはLeaderと呼び、他のレプリカをFollowerと呼びます。データの読み書きはLeaderから行われます。

### Producerのメッセージの送信について
Producerが送信対象のTopicにMessageを送る際にデフォルトでは1メッセージにつき一回の送信ですが、細かい単位でメッセージを送りすぎるとネットワークリソースの枯渇につながるのため、調整が必要です。
以下の二つをトリガーとすることも可能です。

* 指定したサイズまでメッセージが蓄積したらメッセージを送信する。
* 一定時間ごとにメッセージを送信する。

また、上記の通りメッセージ送信する際にはどパーティションに送信するかのパーティショニング機能が備わっています。

At Least Onceの実現のためにBlockerは正しく受信できたことを示すためAck(肯定応答)を行います。Ackを受け取れなかった場合ProducerはMessageの再送処理を行います。

![producer.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/202545/404e2e88-9e48-7a30-704f-c648320992f3.png)


### Consumerのメッセージ受信について
Consumerのメッセージ受信ではConsumerがまずトランザクション開始リクエストを送ります。
その後Consumerは取得対象のTopicに対してCurrent Offsetと呼ばれるどこまで送信したか表す位置からMessage のBrokerの持つ最新のMessageまでまとめて配信リクエストを送ります。

ConsumerはからOffset Commit メッセージを送ります。

![comsumer.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/202545/562de3c9-1755-44af-cbf6-69c6e2105ca7.png)

Blockerからメッセージ配信後、Consumer側で障害が発生した際にはCurrent Offsetは前回の位置まで戻ります。

![consummer2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/202545/55a98b38-995f-5de4-701c-c5d99ec9f1f6.png)


Topicがレプリケーションされている場合は、最新のメッセージまではなくHighWatermarkと呼ばれるレプリケーションが完了Offsetを示す位置までConsumerはメッセージを取得可能です。
このようにすることよってAt Least Oneの到達保証を可能としています。

## まとめ
Kafkaの概要とアーキテクチャについてまとめました。Kafkaは分散システムがあるゆえに少し複雑なアーキテクチャになっています。また多くのシステムにおいてはオーバースペック気味になることもあります。しかし、リアルタイムなデータハブを構築したいなどの要件に対して強いソフトウェアとなっています。

# 参考文献
* [Apache Kafka 分散メッセージングシステムの構築と活用](https://www.amazon.co.jp/Apache-Kafka-分散メッセージングシステムの構築と活用-NEXT-ONE/dp/4798152374/ref=asc_df_4798152374/?tag=jpgo-22&linkCode=df0&hvadid=296037098760&hvpos=1o1&hvnetw=g&hvrand=12197987601584218192&hvpone=&hvptwo=&hvqmt=&hvdev=c&hvdvcmdl=&hvlocint=&hvlocphy=1028852&hvtargid=pla-525885277091&psc=1&th=1&psc=1)