Apache Kafkaは、1) 始めて見た時の興奮、2) 技術的な深遠さ、3) 十分な理解に達したときに得られる大きな報酬、という面から、まさに小説家にちなんだその名に相応しいものです。しかしながら、比較文学の入門講座は早々に終わることにして、最新のKafkaベストプラクティスに忠実に従うならば、このパワフルなデータストリーミングプラットフォームをもっともっと簡単な – そしてはるかに効率的なものにすることができるのです。
Kafkaのデプロイメントを最適化し、管理をより簡単にするための10のヒントをここで紹介しましょう。
- ログの管理がしやすいようにログ設定パラメータをセットする
- Kafkaのハードウェア要件(の低さ)を知る
- Apache ZooKeeperを最大限活用する
- レプリケーションと冗長性を適切にセットアップする
- トピックの設定に注意する
- 並列処理を使用する
- セキュリティに留意してKafkaの設定と分離を行なう
- システム停止を回避するためにUlimitを高く設定する
- ネットワークレイテンシを抑制する
- モニタリングとアラートを効果的に活用する
これらのベストプラクティスを詳しく見てみましょう。
ログの管理がしやすいようにログ設定パラメータを設定する
Kafkaはユーザのために、ログ設定のオプションをたくさん提供しています。デフォルト設定は妥当なものですが、自身の特定の条件に合わせてログ動作をカスタマイズすれば、管理面での課題の発生を長期にわたって防止することができます。ログの保存ポリシ、クリーンアップ、コンパクト化、圧縮アクティビティなどがこれに含まれます。
ログの動作は、log.segment.bytes、log.segment.ms、log.cleanup.policy(あるいはトピックレベルの同等の)パラメータを使ってコントロールすることができます。過去ログを必要としないユースケースの場合は、cleanup.policyを“delete”に設定することで、一定のファイルサイズあるいは設定した時間経過後にログファイルを削除することが可能です。また、必要ならば、ログの保持方法を“compact”とすることもできます。ログのクリーンアップはCPUとRAMを消費する、ということを理解しておく必要があります。Kafkaをコミットログとして長期間使用する場合、圧縮の頻度とパフォーマンス維持の必要性のバランスに注意してください。
圧縮のプロセスでは、(単一トピックパーティション内のデータのログに対して)少なくともメッセージキーの最後の既知の値を保持することが保証されています。圧縮処理ではトピックの各キーに作用して最終値を保持し、それ以外の重複をすべてクリーンアップしています。削除する場合、キーは’null’値として残されます(削除の比喩的な表現として、’tombstone(墓碑)’と呼ばれています)。
図1 – Kafkaのコミットログ圧縮プロセス(引用元)
Kafkaコミットログのドキュメントは次のものです。
Kafkaのハードウェア要件(の低さ)を知る
Kafkaに不慣れなチームには、そのハードウェア要件を大きく見過ぎる傾向がありますが、実際のKafkaはオーバーヘッドが低く、水平スケーリング性に優れた設計がなされています。このため、価格の安いコモディティハードウェアを使用しても、Kafkaを運用することは十分可能です。
- CPU: SSLとログ圧縮を必要としない限り、強力なCPUは必要ありません。また、コア数が多いほど、並列性が向上します。圧縮が重要でなければ、ほとんどのシナリオにおいて、最高のパフォーマンスを得るためにLZ4コーデックを使用するべきです。
- RAM: ほとんどの場合、ヒープ領域に6GBのRAMがあれば最適な実行が可能です。特に運用負荷が大きい場合は、32GB以上のマシンを使用してください。余剰RAMはOSページキャッシュに使用され、クライアントのスループットが向上します。Kafkaは少ないRAMで動作可能ですが、使用可能なメモリが少ない場合は処理能力に影響があります。
- ディスク: Kafkaは、複数のドライブによるRAIDセットアップを使用すると良好に動作します。KafkaのシーケンシャルなディスクI/Oパラダイムのため、SSDには大きなメリットはありません。また、NASは使用しないでください。
- ネットワークとファイルシステム: 状況が許せば、クラスタを単一のデータセンタに保つため、XFSを推奨します。また、ネットワーク帯域幅は可能な限り確保してください。
Apache KafkaのWebサイトには専用のハードウェアやOS設定のセクションがあって、貴重な助言が提供されています。
その他、Kafkaロード/パフォーマンステストに関する有益なリンクとしては、以下のものがあります。
- Benchmarking Apache Kafka: 2 Million Writes Per Second (On Three Cheap Machines)
- Load Testing Apache Kafka on AWS
- Performance testing
Apache ZooKeeperを最大限活用する
Apache ZooKeeperクラスタの実行は、Kafkaを実行するための重要な依存関係です。ただし、ZooKeeperをKafkaで使用する場合には、注意すべき重要なベストプラクティスがいくつかあります。
ZooKeeperのノード数は最大で5つとする必要があります。開発環境ではひとつのノードが適切です。また、Kafkaクラスタの運用では、ほとんどの場合、3つで十分です。大規模なデプロイメントでは、レイテンシ低減のために5つのZooKeeperノードが必要になる場合もありますが、ノードの負荷を考慮する必要があります。7つ以上のノードでは同期や要求処理の負荷が大きくなるため、パフォーマンスが著しく低下する可能性があります。Kafkaの最近のバージョンでは、コンシューマオフセットの格納にZooKeeperを使用していた以前のバージョンに比較して、ZooKeeperの負荷がはるかに低くなっている点にも注意してください。
最後に、Kafkaのハードウェア要件にもあるように、ZooKeeperに可能な限り強力なネットワーク帯域を提供してください。最高のディスクを使用する、ログを分割して格納する、ZooKeeperプロセスを分離する、スワップを無効にする、といったことによっても、レイテンシが低減されます。
下の表は、ZooKeeperに依存するコンソール操作について、Kaflaのバージョン毎に示したものです。0.8.0以前のバージョンでは、コンソールで使用可能な機能は多くありませんでしたが、0.10.0.0以降では、いくつかの主要な機能がZooKeeperから移動しているのが分かります。その結果、ZooKeeperの利用度は低減しています。
Kafkaデプロイメントのレジリエンスは、すべてが適切な管理に依存しています。重要なプラクティスのひとつは、Kafkaのデフォルトのレプリケーション係数を2から3に増やすことです。これはほとんどの運用環境で適切な値です。これによって、ひとつのブローカの損失は問題にならず、2つが失われても可用性の損なわれることが少なくなります。もうひとつ考慮すべき点は、データセンタのラックゾーンです。例えば、AWSを使用する場合、複数のKafkaサーバが同じリージョンにあるかも知れませんが、複数のアベイラビリティゾーンを使うことで冗長性とレジリエンスが実現できます。レプリケーションと冗長性を適切にセットアップしてください。
ラックのデプロイメントで考慮すべきKafkaの構成パラメータは次のものです。
broker.rack=rack-id
Apache Kafkaのドキュメントの記載によれば、
トピックが作成、変更、または複製される場合、ラックの制約が適用され、可能な限り多くのラックにレプリカが分散されます(ひとつのパーティションは、少なくともmin(#racks, replication-factor)の異なるラックに分割されます)。
例:
3つのラックにまたがる、9つのKafkaブローカ(B1-B9)を考えてみましょう。
図2 - ラックを考慮したKafkaクラスタ
この場合、3つのパーティション(P1、P2、P3)と3のレプリケーション係数(R1、R2、R3)を持つひとつのトピックが、ラックごとにひとつのノードを割り当てたひとつのパーティションを保持します。このシナリオでは、ひとつのラックに障害が発生しても(図に示すように)、各パーティションの2つのレプリカによって高可用性が実現されます。
トピックの設定に注意する
トピックの設定は、Kafkaクラスタのパフォーマンスに極めて大きな影響を与えます。レプリケーション係数やパーティション数などの運用中の変更は困難な場合があるため、これらは最初に適切な設定をして、変更が必要な場合はトピックを新たに生成するのみにすることをお勧めします(新しいトピックはステージング環境で必ずテストしてください)。
レプリケーション係数3を使用して、 大きなメッセージの処理には注意してください。可能であれば、順序付けた部分に分割するか、データへのポインタ(S3へのリンクなど)を使いましょう。これらの方法が使用できない場合は、プロデューサ側で圧縮を有効にします。ログのセグメントサイズの既定値は1GBです。メッセージがこれより大きい場合は、ユースケースを詳しく調べる必要があります。パーティション数の設定も重要です。これについては、次のセクションで詳しく説明します。
トピックの設定には“サーバデフォルト”プロパティがありますが、トピックの生成時またはその後でオーバーライドして、トピック固有の設定を行うことができます。
これまで述べたように、レプリケーション係数は最も重要な設定値のひとつです。次の例では、3のレプリケーション係数と3つのパーティション、その他の“トピックレベル”の設定を指定して、コンソールからトピックを生成しています。
bin/kafka-topics.sh --zookeeper ip_addr_of_zookeeper:2181 --create --topic my-topic --partitions 3 --replication-factor 3 --config max.message.bytes=64000 --config flush.messages=1
トピックレベルの設定値の全リストはこちらをご覧ください。
並列処理を使用する
Kafkaは並列処理用に設計されています。並列化そのものの動作がそうであるように、完全に活用するにはバランスの取れた動作が必要です。パーティション数はトピックレベルの設定値であり、パーティションが多いほど並列化とスループットは向上しますが、それに伴ってレプリケーションのレイテンシ、再バランス、オープンするサーバファイルの数も増えます。
最適なパーティション設定を見つけるには、現在のハードウェアで実現したいスループットを計算した上で、必要なパーティション数を求める算数を実行すればよいのです。控えめな見積によると、ひとつのトピックのひとつのパーティションは10MB/秒のデリバリが可能です。この見積値から外挿することで、必要なスループットの合計に到達することができます。すぐにテスト可能な別の方法として、ブローカ毎、トピック毎にひとつのパーティションを使用して結果を確認し、もっとスループットが必要ならば結果を確認し、パーティション数を2倍にするという方法もあります。
全体として、ここでの有用なルールは、トピックの合計パーティション数を10未満に、クラスタ全体のパーティション総数を10,000以下にすることです。それ以上の場合は、極めて能力の高い監視機能が必要であると同時に、非常に困難な再調整やシステム停止を覚悟しなければなりません!
パーティション数は次のように、Kafkaトピックの生成時に指定します。
bin/kafka-topics.sh --zookeeper ip_addr_of_zookeeper:2181 --create --topic my-topic --partitions 3 --replication-factor 3 --config max.message.bytes=64000 --config flush.messages=1
パーティション数は作成後に増やすこともできますが、コンシューマに影響を与える可能性があるので、すべての結果に対処した上でこのオペレーションを行うようにお勧めします。
bin/kafka-topics.sh --zookeeper zk_host:port/chroot --alter --topic topic_name --partitions new_number_of_partitions
セキュリティに留意してKafkaの設定と分離を行なう
Kafkaデプロイメントをセキュアにする上で、大きな懸念となるのは 1) Kafkaの内部構成、2) Kafkaの動作するインフラストラクチャ の2つです。
Kafka 9リリースには、Kafka/クライアントおよびKafka/ZooKeeprの認証サポートに加えて、公衆インターネットクライアントにおいてシステムを保護するためのTLSサポートなど、価値のあるセキュリティ機能が含まれていました。TLSにはスループットとパフォーマンス上のコストが伴いますが、Kafkaブローカとのトラフィックを効果的に分離し、保護します。
セキュリティ上不可欠なのは、KafkaとZooKeeperを分離することです。レアケースを別にすれば、ZooKeeperは公衆インターネットには絶対に接続せず、Kafka(あるいは使用する他のソリューション)との通信に特化する必要があります。ファイアウォールあるいはセキュリティグループでは、kafkaとZooKeeperをブローカとともに隔離して、外部接続を拒否する単一のプライベートネット内に置くべきです。ミドルウェアあるいはロードバランシングレイヤによって、パブリックインターネットクライアントからKafkaを隔離することが必要です。
カフカのセキュリティオプションとプロトコルは次のとおりです。
- SSL/SASL: クライアントからブローカ、ブローカ間、ブローカからツールへの認証。
- SSL: クライアントとブローカ間、ブローカ間、ツールからブローカへのデータの暗号化。
- SASLタイプ: SASL/GSSAPI (Kerberos)、SASL/PLAIN、SASL/SCRAM-SHA-512/SCRAM-SHA-256、SASL_AUTHBEARER
- Zookeeperのセキュリティ: クライアント認証(ブローカ、ツール、プロデューサ、コンシューマ)、ACLによる認証。
*Kafkaブローカのクライアント: プロデューサ、コンシューマ、その他のツール
*Zookeeperのクライアント: Kafkaブローカ、プロデューサ、コンシューマ、その他のツール
*認証はプラグ可能。
SASL_SSLによるセキュリティ設定の設定例を示します。
#Broker configuration
listeners=SSL://host.name:port,SASL_SSL://host.name:port
advertised.listeners=SSL://host.name:port,SASL_SSL://host.name:port
security.protocol=SASL_SSL
security.inter.broker.protocol=SSL
listener.security.protocol.map=INTERBROKER\:SSL,PUBLIC_CLIENT\:
SASL_PLAINTEXT,PRIVATE_CLIENT\:SASL_PLAINTEXT
ssl.keystore.location=/var/private/ssl/server.keystore.jks
ssl.keystore.password=test1234
ssl.key.password=test1234
ssl.truststore.location=/var/private/ssl/server.truststore.jks
ssl.truststore.password=test1234
sasl.mechanism.inter.broker.protocol=PLAIN
sasl.enabled.mechanisms=PLAIN
#Client Configuration (jaas file)
sasl.mechanism=PLAIN
sasl.jaas.config=org.apache.kafka.common.security.plain.PlainLoginModule
required \
username="[USER NAME]" \
password="[USER PASSWORD]";
システム停止を回避するためにUlimitを高く設定する
非常に頻繁に発生するシナリオとして、ブローカが負荷が過大と思われる状況から復帰したにも関わらず、実際には(これもストレスではありますが)“オープンファイルが多過ぎる”という穏便なエラーが通知される場合があります。/etc/sysctl.confを編集して、128,000以上のファイルのオープンが可能なようにUlimitを設定すれば、このエラーの発生を抑止することができます。
CentOSでulimitを増やす例を示します。
- ファイル
/etc/security/limits.d/nofile.conf
を新たに作成する
- 以下の内容を入力する。
* soft nofile 128000
* hard nofile 128000
- システムを再起動するか、再ログインする
- 以下のコマンドを実行して確認する
ulimit -a
* ulimitを増やす方法は他にもあります。自身のLinuxディストリビューションに適した方法に従ってください。
ネットワークレイテンシを抑制する
Kafkaデプロイメントのレイテンシを低減するには、ブローカをクライアントから地理的に最も近いリージョンに配置するとともに、クラウドプロバイダが提供するインスタンスを選択する際に、ネットワークパフォーマンスを考慮する必要があります。帯域幅が制限となっている場合は、大規模でパワフルなサーバへの投資が有効かも知れません。
モニタリングとアラートを効果的に活用する
Kafkaクラスタの生成時に上記のプラクティスに従うことは、将来的にさまざまな問題からあなたを救うことになります。ですが、問題になる前に、障害を認識して適切に対処したいと思うかも知れません。
システムメトリック – ネットワークスループット、オープン中のファイルハンドラ、メモリ、負荷、ディスク使用量、その他の要素 – や、GC停止およびヒープ使用量などJVM状態を監視することは、非常に重要です。ダッシュボードや履歴ツールはデバッグプロセスの短縮を可能にし、さまざまな価値を提供します。それと同時に、レイテンシの急増やディスク領域の低下といった現象の発生を警告するようにNagiosやPagerDutyといった警告システムを設定しておくことで、雪玉のように膨らむ前の小さな問題に対処できるようになります。
Instaclustrコンソールを使用したKafkaの監視グラフの例を示します。
著者について
Ben Bromhead氏はInstaclustrのCTO(最高技術責任者)です。同社はApache CassandraやApache Kafka、Apache Spark、Elasticsearchといったオープンソース技術の管理サービスプラットフォームを提供しています。