1.Kafkaがパーティションの概念を採用する理由
Kafkaメッセージは、トピック(トピック)-パーティション(パーティション)-メッセージの3レベルの構造を採用しています。各メッセージは特定のパーティションにのみ保存され、複数のパーティションには保存されません。
パーティションの役割を使用することは、高いシステムスケーラビリティを実現するために、負荷分散機能を提供することです。
異なるノードマシンに異なるパーティションが配置され、データの読み取りおよび書き込み操作はパーティションの粒度を目的としています。各ノードマシンは、それぞれのパーティションの読み取りおよび書き込み処理要求を個別に実行できます。また、新しいパーティションを追加することで増やすこともできます。ノードマシンシステム全体のスループット。
さらに、パーティションを使用すると、ビジネスでのメッセージの順序の問題も発生する可能性があります。同じパーティションでメッセージの送信順序を保証でき、同じパーティションにメッセージを送信するためのキーを指定することで、ビジネスでのメッセージの順序の問題を解決できます。
2.一般的なパーティショニング戦略は何ですか?
パーティション戦略とは、プロデューサーがメッセージを送信するパーティションを指します。一般的なパーティション戦略は次のとおりです。
- ポーリング戦略:異なるパーティションに順番に割り当てられる、より優れた負荷分散機能を備えたデフォルトの戦略もより推奨されます。
- ランダム戦略:メッセージを任意のパーティションに送信します。
- 保存するメッセージキーを指定します。同じキーのメッセージは同じパーティションに送信され、各パーティションでのメッセージの処理は整然と行われます。
- カスタム戦略、
org.apache.kafka.clients.producer.Partitioner
インターフェースの実装
3.プロデューサー圧縮アルゴリズム
圧縮とは、CPU時間を使用してディスクスペースまたはネットワークI / O転送ボリュームを交換することで、ディスク占有率またはネットワークI / O転送を減らし、CPUオーバーヘッドを減らします。
(1)圧縮
Kafkaでの圧縮は、プロデューサーとブローカーの2か所で発生します。
プロデューサー側はprops.put("compression.type", "gzip");
、圧縮機能を有効にして使用するために使用されます。
ブローカー側は通常、メッセージを再圧縮せず、受信したメッセージはそのまま送信されるだけです。メッセージを圧縮するには、次の2つのシナリオがあります。
- ブローカー側は、プロデューサー側とは異なる圧縮アルゴリズムを指定します
- ブローカー側でメッセージ形式の変換が発生しました
ブローカー側はcompression.type
、圧縮アルゴリズムを設定するために使用します。値がプロデューサー側の値と異なる場合、受信したメッセージは解凍されてから圧縮されます。(CPUを急上昇させるのは簡単です)
メッセージ形式には複数のバージョンがあります。メッセージセットに新しいバージョンと古いバージョンの両方がある場合、ブローカーは新しいメッセージを古いバージョンのメッセージに変換します。
(2)解凍
一般的に、減圧は消費者側で発生します。プロデューサー側はメッセージを圧縮し、ブローカー側はメッセージを受信して保存し、コンシューマー側はメッセージを受信して解凍します。
プロデューサーはメッセージコレクションで使用する圧縮アルゴリズムをカプセル化し(注:メッセージではなく、メッセージコレクションです)、コンシューマーはメッセージコレクションを読み取るときに設定された圧縮アルゴリズムに従ってメッセージコレクション内のメッセージを解凍します。
ブローカー側は、受信した各メッセージセットを解凍する必要があります(注:これはメッセージではなく、メッセージは解凍されません。ただし、上記の2つのブローカー側の再圧縮シナリオが発生しない限り、メッセージは再圧縮および解凍されます。動作中)。
(3)圧縮アルゴリズムを開くタイミング
- プロデューサー側で実行されているプログラムマシンには十分なCPUリソースがあります。そうでない場合、メッセージ収集を有効にすると、CPUが急増し、CPUが占有されます。
- 帯域幅のリソースは限られているため、圧縮を有効にすることをお勧めします。これにより、ネットワークリソースの消費を大幅に節約できます。
- メッセージ形式の変換によって引き起こされる圧縮/解凍の問題を回避するようにしてください。
4.プロデューサーは、メッセージが失われないようにどのように確認しますか?
ビジネスプログラムを介してKafkaにメッセージを送信する場合、メッセージの送信に失敗する要因は何ですか。
- ネットワークジッター、プロデューサーによって送信されたメッセージはブローカーにまったく送信されません。
- メッセージが大きすぎてブローカー側に耐えられないため、拒否されます
- ブローカーがダウンしています(この状況の解決策はありません。できるだけ早く解決するための操作とメンテナンスを見つけることしかできません)
上記のすべてにより、プロデューサーによって送信された「失われた」メッセージが誤って表示されます。
では、上記の問題をどのように解決するのでしょうか?
プロデューサー側はproducer.send(msg, callback)
、コールバック付きの送信APIを使用する必要があり、コールバックなしのAPIは使用しないでくださいproducer.send(msg)
。コールバック付きのAPIは、ブローカー側がプロデューサー側から送信されたメッセージを受信したかどうかを通知します。メッセージが正常に送信されなかった場合は、状況を把握し、再試行などのターゲットを絞った方法で対処できます。
詳細な例については、以下を参照してください:Kafkaプロデューサーメッセージ送信コードの例
/**
* 异步发送kafka消息
*
* @param topic
* @param key
* @param message
*/
public void asyncSendMsg(String topic, String key, String message) {
ProducerRecord producerRecord = new ProducerRecord(topic, key, message);
producer.send(producerRecord, (recordMetadata, e) -> {
if (e != null) {
System.out.println("!!!+++error!!!!");
log.error("kafka msg send error, topic={}, key={}, message={}, e={}", topic, key, message, e);
return;
}
// send success
if (recordMetadata != null) {
System.out.println(">>>>>>>message:" + message);
log.info("kafka msg send success, topic={}, key={}, partition:{}, offset:{}, timestamp:{}", topic, key, message, recordMetadata.partition(),
recordMetadata.offset(), recordMetadata.timestamp());
} else {
log.info("kafka msg send success result is null, topic={}, key={}, timestamp:{}", topic, key, message, recordMetadata.timestamp());
}
});
}
本番環境では、メッセージを損失なく処理する方法は次のとおりです。
(1)プロデューサー構成:
-
送信のAPIコールバック通知を使用します:
producer.send(msg, callback)
; -
を設定
acks=all
すると、すべてのレプリカブローカーが「コミット済み」と見なされる前にメッセージを受信することを意味します。設定
retries > 0
。プロデューサーの自動再試行を表します。ネットワークで瞬間的なジッターが発生すると、メッセージの送信が失敗する場合があります。retries > 0
プロデューサーは、メッセージの損失を回避するために、メッセージの送信を自動的に再試行できます。
(2)ブローカー構成
unclean.leader.election.enable = false
:一部のブローカーが元のリーダーデータに落ち着いたときに、新しいリーダーになると、メッセージが失われる可能性があります。falseに設定すると、このタイプのブローカーは新しいリーダーになることができなくなります。replication.factor >= 3
:コピー数は少なくとも3であるため、メッセージは複数のブローカーに保存され、ダウンタイムによる単一のブローカーの損失を回避します。min.insync.replicas > 1
:メッセージが少なくとも数個のコピーに書き込まれた場合、そのメッセージは「コミット済み」と見なされ、コピーの下限は次のacks=-1
場合にのみ有効になることが保証されます。replication.factor > min.insync.replicas
:それらが等しい場合、1つのコピーがダウンしている限り、プロデューサーはそれに書き込むことができません。たとえば、両方が2で、1つのコピーがダウンしている場合、min.insync.replicas=2
それを満たすことはできません。通常、replication.factor = min.insync.replicas +1を設定することをお勧めします。
(3)コンシューマー構成
enable.auto.commit
falseに設定すると、コードは手動変位送信方法を採用します。
5.KafkaプロデューサーTCP管理
Kafkaのプロデューサー、コンシューマー、およびブローカー間の通信は、TCPプロトコルを使用して通信し、多重化など、TCPのいくつかの高度な機能を使用できます。
(1)プロデューサーとブローカーの間にTCP接続を作成するタイミング
-
プロデューサーがKafkaProducerのインスタンスを作成すると、Senderスレッドが作成されてバックグラウンドで開始され、スレッドの実行時にブローカーへの接続が作成されます。
bootstrap.servers
パラメーター値を指定している限り、Prodcuerはこれらの構成済みブローカーとのTCP接続を作成し、メタデータ要求をブローカーに送信してクラスターメタデータ情報の取得を試みます。注:プロデューサーは、デフォルトでクラスター内のすべてのブローカーへのTCP接続を作成し、時間内に3つのみと通信できます。
-
プロデューサーが不明なトピックトピックにメッセージを送信しようとすると(パーティション情報とトピックに対応する対応するノード情報を知らずに)、KafkaクラスターにrequestUpdateリクエストを送信して、最新のメタデータ情報を取得しようとします。
-
プロデューサー
metadata.max.age.ms
メタデータパラメータを定期的に更新することにより、デフォルト値は5分です。
(2)TCPが接続を閉じるとき
- ユーザーは積極的に閉鎖しました:
producer.close
- プロデューサー側は
connections.max.idle.ms
、プロデューサー側がブローカーとのTCP接続セッションを維持する時間を示すパラメーターを設定します。デフォルトは9分です。Kafkaは、要求なしで9分以上TCP接続を閉じます。接続を永続的に維持するには、-1に設定します。
6. Kafka Producerは、メッセージが繰り返し送信されないようにするにはどうすればよいですか。
プロデューサー側のメッセージ配信の信頼性には、次の3種類の保証があります。
- 最大で1回:プロデューサーは1回だけ送信するため、メッセージは繰り返し送信されませんが、メッセージが失われる可能性があります。たとえば、ブローカーは瞬間的なネットワークジッターのためにメッセージを受信せず、メッセージは失われます。
- 少なくとも1回:メッセージは失われませんが、繰り返し送信される可能性があります。これは、プロデューサーに再試行を禁止させることで実現されます。
- 正確に1回:メッセージが失われたり、繰り返し送信されたりすることはありません。
実際の運用では、メッセージが失われないようにする必要があるため、2番目または3番目の方法が一般的に採用されています。
したがって、プロデューサーはメッセージが繰り返し送信されないことを保証し、デフォルトの前提はメッセージが失われないことです。それでは、達成する方法を見てみましょう。
- べき等
- 事務
(1)べき等プロデューサー
Kafkaはバージョン0.11.0.0以降、べき等プロデューサーを導入しました。props.put(“enable.idempotence”, ture)
設定されている限り、コードを変更する必要はなく、Kafkaはメッセージの重複排除を自動的に実行します。プロデューサーが同じフィールド値でメッセージを送信すると、ブローカーはメッセージが重複していることを認識し、メッセージを破棄します。
ただし、べき等プロデューサーは、トピックが単一のパーティションでメッセージを繰り返さないことを保証することしかできません。次に、サービスが再起動すると、このべき等は失われます。
(2)トランザクションプロデューサー
Transactional Producerは、メッセージが複数のパーティションにアトミックに書き込まれることを保証できます。また、サービスが再起動された後でも、メッセージを1回だけ送信することを保証できます。