メッセージ キュー CKafka 大洋横断データ同期パフォーマンスの最適化

序章

この記事では、CKafka が大洋横断シナリオで遭遇した地域間の大きなデータ同期遅延の問題を主に紹介しますが、地域間の遅延の問題は典型的なものなので、要約するために詳細に記録されています。

1. 背景

リージョンを越えた災害復旧とコールド バックアップに対する顧客の要求を満たすために、メッセージ キュー CKafka は、コネクタ機能を介してリージョンを越えたデータ同期機能を提供し、リージョンを越えた第 2 レベルの準リアルタイム データ同期をサポートします。

全体的なアーキテクチャ図は次のとおりです。

上の図に示すように、CKafka のリージョン間データ同期機能は、最下層の Kafka Connect クラスターに基づいて実装され、クラウド環境は Vpcgw Privatelink を通じて開かれます。

データ同期の主なプロセスは次のとおりです。

1. Connect クラスターは Connect タスクを初期化し、各タスクはソース CKafka インスタンスからデータをプルするために複数の Worker ConsumerClients (特定の数はソース インスタンスのパーティション数によって異なります) を作成します。

2. Connect クラスターがソース インスタンスからデータを取得した後、プロデューサーを起動してデータをターゲット CKafka インスタンスに送信します。

顧客のビジネス シナリオでは、顧客はリージョン間同期機能を使用して、香港の CKafka インスタンスのデータを米国東部の CKafka インスタンスに同期したいと考えています。これにより、使用中にリージョン間で遅延が発生するという奇妙な問題が発生します。

2. 問題となる現象

お客様がリージョン間同期機能を使用すると、香港 -> 米国東部のデータ同期遅延が非常に大きいことがわかり、Connect がコンシューマーとして機能してソース インスタンス (香港) からデータを消費およびプルしていることが明らかにわかります。メッセージの蓄積は非常に膨大です。

ニュースの蓄積

過去の経験によれば、国内リージョンの同期ではそれほど大きな遅延は発生しないはずですが、今回はリージョン全体でこれほど大きな遅延が発生するのはなぜでしょうか?

3. 問題分析

メッセージが蓄積される一般的な原因

Kafka の生成および消費プロセスにおいて、メッセージが蓄積される一般的な理由は次のとおりです。

● ブローカー クラスタの負荷が高すぎます。CPU、メモリ、ディスク IO が高すぎるため、スループットの消費が遅くなります。

● コンシューマの処理能力が不十分: コンシューマの処理能力が不足しているため、タイムリーにメッセージを消費できない場合、メッセージが蓄積されます。この問題は、コンシューマの数を増やすか、コンシューマの処理ロジックを最適化することで解決できます。

● コンシューマの異常終了: コンシューマが異常終了すると、メッセージが時間内に消費されず、大量の未消費メッセージがブローカに蓄積されます。消費者の状態や健康状態を監視することで、異常を早期に発見し、対処することができます。

● コンシューマがオフセットの送信に失敗する: コンシューマがオフセットの送信に失敗すると、メッセージが繰り返し消費または失われ、大量の未消費メッセージがブローカに蓄積されます。オフセットの原子性と一貫性は、コンシューマのオフセット送信ロジックを最適化するか、Kafka のトランザクション メカニズムを使用することによって保証できます。

● ネットワーク障害またはブローカー障害: ネットワーク障害またはブローカー障害が発生すると、メッセージの送信または保存が間に合わず、大量の未消費メッセージがブローカーに蓄積されます。この問題は、ネットワークの安定性と信頼性を最適化するか、ブローカーの数とフォールト トレランスを増やすことで解決できます。

● プロデューサがメッセージを送信する速度が速すぎる: プロデューサがメッセージを送信する速度が速すぎて、コンシューマの処理能力を超えると、メッセージが蓄積されます。この問題は、プロデューサの送信速度を調整するか、コンシューマの数を増やすことで解決できます。

上記の理由に基づいて、まず Connect クラスター内のすべてのノードとソースおよびターゲット CKafka インスタンスのすべてのノードの負荷をチェックしたところ、すべての監視インジケーターが正常で、クラスターの負荷が非常に低く、ConnectConsumer の消費容量に異常やパフォーマンスのボトルネックがないことがわかりました。

ただし、一度にメッセージを取得する速度は非常に低く、平均消費速度は 325KB/秒であり、予想と一致しません。

(注: 上の図の消費バイト数インジケーターは、1 秒あたりに消費されるバイト数を表します)

クラスターの負荷に問題がないため、さらに詳細な調査と分析を実施しました。

分析の第 1 段階: ネットワーク速度を確認する

メッセージの遅延が長く、ネットワークの問題が最初に考えられたため、すぐにネットワークのストレス テストを開始しました。Iperf3 と Wget を通じてネットワーク速度を検出します。

Iperf3 圧力テスト、速度は 225Mbps です。

Wget は Connect クラスター内の香港に直接接続し、ダウンロード速度は 20MB/s です。

これら 2 つのテストは、同じ環境下ではネットワーク伝送速度が低くなく、20MB/秒に達する可能性があることを示しています。では、ネットワーク帯域幅には問題がないのですが、どこに問題があるのでしょうか?

フェーズ 2 分析: カーネル調整パラメータ

ネットワークには問題ないのですが、Kafkaのネットワーク関連のアプリケーションパラメータやカーネルネットワーク関連のパラメータが無理に設定されているのではないでしょうか?

1. 最初にカーネル パラメータを調整しましたネットワークに関連するカーネル パラメータには主に次のものがあります。

系统默认值:
net.core.rmem_max=212992
net.core.wmem_max=212992
net.core.rmem_default=212992
net.core.wmem_default=212992
net.ipv4.tcp_rmem="4096    87380   67108864"
net.ipv4.tcp_wmem="4096    65536   67108864"

---------------------------------------------------------
调整内核参数:
sysctl -w net.core.rmem_max=51200000
sysctl -w net.core.wmem_max=51200000
sysctl -w net.core.rmem_default=2097152
sysctl -w net.core.wmem_default=2097152
sysctl -w net.ipv4.tcp_rmem="40960 873800 671088640"
sysctl -w net.ipv4.tcp_wmem="40960 655360 671088640"

调整TCP的拥塞算法为bbr:
sysctl -w net.ipv4.tcp_congestion_control=bbr

全体的なカーネル パラメータの値を増やし (ただし、システム カーネルのデフォルト値は小さくないと考えています)、TCP の輻輳アルゴリズムも調整しました。

ここでは、TCP 輻輳アルゴリズムを調整する必要がある理由について説明します。

(参考文献: [[翻訳] [論文] BBR: 輻輳に基づく輻輳制御 (パケットロスではない) (ACM, 2017)]( [翻訳] [論文] BBR: 輻輳に基づく輻輳制御 (パケットロスではない) (ACM, 2017) ) )

この遅延は地域や海洋を越えて発生するため、BBR を使用するとネットワーク スループットが大幅に向上し、遅延が削減されます。スループットの向上は、太平洋横断ファイルや大規模なデータ転送などの長距離パスで、特にパケット損失がわずかなネットワーク条件下で顕著です。レイテンシの改善は主にパスの最後の 1 マイルで見られ、バッファの肥大化の影響を受けることがよくあります。いわゆる「バッファインフレ」とは、不必要に大きなバッファを設計するネットワーク デバイスまたはシステムを指します。バッファの肥大化は、ネットワーク リンクが混雑しているときに発生し、パケットがこれらの非常に大きなバッファ内で長時間キューに留まります。FIFO キュー システムでは、バッファが大きすぎるとキューが長くなり、遅延が長くなり、ネットワーク スループットは向上しません。BBR はバッファーをいっぱいにしようとしないため、バッファーの肥大化を回避する効果が高くなります。

カーネルパラメータを調整した後、検証では遅延が大幅に改善されていないことがわかりました。

2. クラウド製品テクニカルサービス専門家の注意喚起のもと、接続の受信バッファ設定が小さすぎてカーネルパラメータの調整が反映されないことが確認され、アプリケーション層で設定されている可能性が考えられます。

そこで、Kafka アプリケーションのネットワーク パラメーター Socket.Send.Buffer と Socket.Recevie.Buffer のパラメーター値を調整しました。

(1) システムのソケット送信バッファを使用するように、ソース ターゲット CKafka インスタンス ブローカーの Socket.Send.Buffer.Bytes パラメータをデフォルトの 64KB から調整します。

ソケット送信バッファに関する Kafka カーネル コード:

ヒント】:

Kafka では、TCP 送信バッファのサイズはアプリケーションとオペレーティング システムによって共同で決定されます。アプリケーション プログラムは、Socket.Send.Buffer.Bytes パラメーターを設定することによって TCP 送信バッファーのサイズを制御できます。また、オペレーティング システムも、TCP/IP プロトコル スタックのパラメーターを設定することによって、TCP 送信バッファーのサイズを制御できます。

アプリケーションによって設定された Socket.Send.Buffer.Bytes パラメーターは TCP 送信バッファーのサイズに影響しますが、オペレーティング システムも TCP 送信バッファーのサイズを制限します。アプリケーションによって設定された Socket.Send.Buffer.Bytes パラメータがオペレーティング システムの制限を超える場合、TCP 送信バッファのサイズはオペレーティング システムの制限内に制限されます。アプリケーションが Socket.Send.Buffer.Bytes=-1 に設定すると、TCP 送信バッファのサイズはデフォルトでオペレーティング システムの TCP 送信バッファのサイズになります。TCP 送信バッファのサイズはネットワークのスループットと遅延に影響することに注意してください。TCP 送信バッファのサイズが小さすぎると、ネットワークのスループットとパフォーマンスが低下し、TCP 送信バッファのサイズが大きすぎると、ネットワークの遅延時間が増加します。したがって、最適なパフォーマンスと信頼性を実現するには、実際の状況に応じて調整する必要があります。

(2) システムのソケット受信バッファを使用するように、クライアント Connect Consumer の Receive.Buffer.Bytes パラメータをデフォルトの 64KB から調整します。クライアントの Max.Partition.Fetch.Bytes パーティションの最大フェッチ サイズを 5MB に調整しました。

調整後、お客様と速やかに調整し、クラスターを再起動して調整を確認しました。調整後の効果は明ら​​かです。単一接続の平均速度が 300KB/s から 2MB/s 以上に増加しました。

Kafka の Socket の受信および送信パラメーターを増やした後の効果は非常に明白で、同期率が向上していることがわかります。遅延問題が解決したと思ったら、また問題が発生!

分析の第 3 段階: 根本原因を深く掘り下げる

上記の第 2 段階の Kafka パラメータ調整が顧客のクラスタに適用され、1 日観察した後、顧客はクラスタの全体的な遅延は改善されたものの、一部のパーティションの遅延は依然として非常に大きいと報告しました。また、パーティションの約半分の同期率が依然として非常に低いことも観察されました。

(注: 上の図の Bytes-Consumed-Rate インジケーターは、1 秒あたりに消費されるバイト数を表します)

(1) 一部の接続速度が依然として非常に遅いのはなぜですか?

まず、操作バックグラウンドを通じて消費率の低いパーティションに対応する ConsumerGroupID を特定し、この ConsumerGroupID を使用してパケットをキャプチャし、対応する低速 TCP 接続を見つけます。

接続を見つけたら、パケット キャプチャ分析を実行します。

上記のことから、サーバーがデータを送信した後、一定期間停止し、その後約 1 RTT 送信し続けることがわかります。各送信間隔間のデータ パケットの合計サイズを数えます (約 64 KB)。これは基本的に、TCP の送信ウィンドウが 64KB に制限されていることを意味します。ただし、通常の速度で他の接続をキャプチャする場合には、そのような制限はありません。一般に、TCP 送信ウィンドウの実際のサイズはウィンドウ スケールに関連しており、接続が確立されたときにのみ確認できます。

ヒント】:TCP Window Scale、TCP ウィンドウのスケーリング係数。(参考: TCP の初期ウィンドウ サイズとスケーリング オプションを決定する方法?決定に影響する要因は? - Red Hat Customer Portal )

従来の TCP プロトコルでは、TCP ウィンドウの最大サイズは 64KB までしか到達できず、これにより TCP プロトコルの送信速度と効率が制限されます。この問題を解決するために、TCP ウィンドウ スケール メカニズムが TCP プロトコルに導入されました。

TCP ウィンドウ サイズ = (受信側ウィンドウ サイズ) * (2 ^ TCP ウィンドウ スケール オプションの値)

TCP スリーウェイ ハンドシェイク接続が確立されるときに、TCP ウィンドウ サイズの拡張方法とパラメータを決定するために、TCP ウィンドウ スケール メカニズムをネゴシエートする必要があることに注意してください。

接続確立の状況を把握するために、単一パーティションの消費タスクを再起動してみましたが、再起動さえすれば消費速度は回復し、ウィンドウ サイズのボトルネックも発生しないことがわかりました。

(2) 送信ウィンドウが制限されているのはなぜですか?

問題を再現するために、お客様の利用シナリオをシミュレーション・構築し、全体のシナリオ再現を実施しました。この問題は、タスクが完全に再起動された場合にのみ発生することが最終的に確認されました。タスクの再起動プロセス中に、サーバー側で全体的なパケット キャプチャを実行しました。正常な接続と異常な接続を特定し、接続を確立するプロセスを比較した結果、接続が遅い場合にはウィンドウ スケールが効果を発揮しないことが最終的に確認されました。

通常の接続確立プロセス:

接続確立プロセスが遅い:

上の図からわかるように、低速接続では、サーバーが Syn/Ack パケットを返すときに「WS=2」がなく、ウィンドウ スケール オプションが有効になっていないことを示します。これにより、接続全体の送信ウィンドウが 64 KB に制限され、スループットを向上させることができません。クライアントが最後の Ack を返したときも、「ウィンドウ スケーリングは使用されていません」と明確に表示されました。

(3) なぜ Window Scale が確率的に有効にならないのでしょうか?

この時点で、Syn/Ack を送信するときにサーバーが確率的に Window Scale を開かない理由を説明する必要があります。ここで、コンピューティンググループの偉い人が私たちが学ぶために同様のケースを提供してくれました:kubernetes - 深いレビュー - etcdの再起動によって引き起こされる例外 - 個人的な記事 - SegmentFaultメッセージを取得するかどうかを考える: SYN Cookieが有効な場合、相手はTimestampオプションを渡さないように見えます(実際には、SYN Cookieの原理に従って、相手に送信される返信パケットは、Tsvalフィールドの下位6ビットにエンコードされたオプション情報を保存します) )、Tcp_Clear_Options を呼び出して、ウィンドウの拡大率などのオプションをクリアします。システム ログから、タスク全体が再起動されたときに SYN フラッドが実際にトリガーされたことも観察できます。

(4) サーバーが Tsval (TCP タイムスタンプ値) を受信しなかったのはなぜですか?

前述したように、データ同期は社内の VPCGW を経由しており、クライアントとサーバーでそれぞれパケットをキャプチャし、最終的にクライアントが送信した Tsval を VPCGW が飲み込んでいることを確認しました。同時に、NAT 環境ではタイムスタンプを転送しないことが予期される動作であることも確認しました。主に特殊な場合のパケット損失問題と、NAT 環境における tcp_timestamps 問題_centos nat tcp_timestamps_Qingfeng Xulai 918 Blog-CSDN Blog を解決するためですただし、この問題は新しいカーネルには存在しないため、タイムスタンプを開く機能を提供するようにスケジュールすることができます。

根本原因の場所

徹底的に分析して掘り下げた結果、問題の根本原因は明らかです。

Connect Consumer はバッチで開始され、多数の新しい TCP 接続をトリガーし、短期間に多数の新しい接続がトリガーされたため、SYN​​ Cookie 保護チェック ロジックがトリガーされました。ただし、クライアントがタイムスタンプ オプションを送信しなかったため、サーバーはウィンドウ拡大率をクリアし、最終的に接続送信ウィンドウの最大値が 64KB になり、大きな遅延が発生した場合の送信パフォーマンスに影響を与えました。

4. 当社のソリューション

問題の根本原因が見つかると、解決策が明らかになります。

● 回避ソリューション: Connect Worker 初期化の同時実行性を調整し、TCP 初期化接続確立の速度を低下させ、後続のデータ同期のパフォーマンスを確保するために SYN Cookie がトリガーされないようにしました。

● 最終的な解決策: VPCGW の TCP タイムスタンプを開く機能を促進します。

V. まとめ

表面的には、この問題はリージョン間のデータ同期リクエストが遅いという問題ですが、徹底的に調べてみると、実際には非常に低レベルのネットワークの問題です。

この問題が発生する条件は比較的複雑であるため、この問題が発生することは比較的まれです。主に、リージョン間のネットワーク遅延の存在、同時に多数の TCP 接続が存在すること、および VPCGW のルーティング送信プロセス中の TCP タイムスタンプ パラメータの消費が重なり、この問題を引き起こします。

私たちは問題に直面しても畏敬の念を持ち続け、根底まで掘り下げる必要があります。

2023 年に最も需要の高い 8 つのプログラミング言語: PHP は好調、C/C++ の需要は鈍化 Programmer's Notes CherryTree 1.0.0.0 リリース CentOS プロジェクトは「誰にでもオープン」と宣言 MySQL 8.1 と MySQL 8.0.34 正式リリース GPT-4 はますますバカになっている?精度率は 97.6% から 2.4% に低下しました Microsoft: Windows 11 で Rust Meta を使用するための取り組みを強化 拡大: オープンソースの大規模言語モデル Llama 2 をリリースし、商用利用は無料です C# と TypeScript の父が最新の オープンソース プロジェクトを発表しました: TypeChat は レンガを移動したくないが、要件も満たしたいと考えていますか? おそらく、この 5,000 スター GitHub オープン ソース プロジェクトが役立つかもしれません - MetaGPT Wireshark の 25 周年記念、最も強力なオープン ソース ネットワーク パケット アナライザー
{{名前}}
{{名前}}

おすすめ

転載: my.oschina.net/u/4587289/blog/10089900