Golang 分散マーケットプッシュのパフォーマンスボトルネックを最適化する

Golang 分散マーケットプッシュのパフォーマンスボトルネックを最適化する

[[409249]]

この記事はWeChatの公開アカウント「Coder's Peach Blossom Land」から転載したもので、著者はFengyunです。この記事を転載する場合は、Coder's Peach Blossom Garden の公開アカウントにご連絡ください。

最近、私は市場情報プッシュ システムを最適化しており、皆さんと共有できる最適化の経験がたくさんあります。最も明らかなパフォーマンスの改善はレイテンシです。単一ノードに 80,000 のクライアントがある場合、レイテンシは 1500 ミリ秒から 40 ミリ秒に最適化されます。以下は、イントラネット モック クライアントから取得したストレス テスト データです。

サブスクライブするクライアントの数については特にテストを行っていませんが、ネットワークが弱い場合、1 台のマシンに 80,000 のクライアントがあっても問題ありません。現在、柔軟に拡張・拡大できる kubenetes デプロイメント ソリューションが使用されています。

アーキテクチャ図

Push-gateway は、いくつかの機能を備えたプッシュ ゲートウェイです。最初の機能は認証用です。 2 つ目は複数のプロトコルにアクセスするためのものです。 websocket、grpc、grpc-web、sse のサポートを実装しました。 3 番目は、ポリシー スケジューリングとアフィニティ バインディングを実装することです。

プッシュ サーバーは、サブスクリプション関係を維持し、MQ からの新しいメッセージを監視して、ゲートウェイにプッシュするプッシュ サービスです。

問題1: 同時マップ操作によるロック競合と遅延

プッシュされたサービスは、通常、ネストされたマップ構造によって表されるサブスクリプション関係を維持する必要があります。これにより、マップの同時実行の競合時にロックの競合と高レイテンシの問題が発生します。

  1. //xiaorui.cc
  2. { "topic1" : { "uuid1" : クライアント1、 "uuid2" : クライアント2}、 "topic2" : { "uuid3" : クライアント3、 "uuid4" : クライアント4} ... }

4 つのマップはビジネスに応じて分割されていますが、サブスクリプション関係はネストされています。直接ロックすると他のコルーチンがブロックされ、レイテンシが高くなります。

ロック操作マップは非常に高速であるはずですが、なぜブロックされているのでしょうか?上記で、マップはトピックとクライアント リスト間のサブスクリプション関係を格納するために使用されると述べました。プッシュするときは、トピックのすべてのクライアントを取得して、通知を 1 つずつ送信する必要があります。 (ここでの送信は io.send ではなく chan send であり、各クライアントはバッファリングされた chan にバインドされます)

解決策: 256 個のマップと読み取り/書き込みロックを各ビジネスに分割し、ロックの粒度を 1/256 に減らします。この方法に加えて、当初はクライアント リストを新しいスライスで返すことも試みましたが、これにより GC 負荷が発生し、テストの結果、推奨されませんでした。

  1. //xiaorui.cc
  2.  
  3. 同期RWMutex
  4. map[文字列]map[文字列]クライアント
  5.  
  6. これを変更してください
  7.  
  8. m *シャードマップ.シャードマップ

セグメントマップライブラリはgithub[1]にプッシュされました。興味のある方はぜひご覧ください。

質問2: シリアルメッセージ通知を同時モードに変更する

簡単に言うと、プッシュ サービスでトピックと 10,000 個のクライアント Chan 間のマッピングを維持します。トピックからのメッセージが MQ から受信されると、これらの 10,000 個のクライアント チャネルに通知されます。

クライアントの chan 自体に大きなバッファがあり、送信関数もブロックを回避するために select default を使用します。しかし、実際には、chan を連続して送信するのは非常に時間がかかります。チャネルの最下層では、チャネルの goroutine を待機し、それを runq にプッシュするために goready が必要です。

以下は私が書いたベンチマーク[2]で、シリアル操作と同時操作の時間消費を比較するために使用できます。 Mac の CPU 周波数は高いため、Mac 上では効果はあまり顕著ではありませんが、サーバー上では明らかです。

シリアル通知、全クライアントの chan を取得して送信します。

  1. for _、notifier := range notifiers {
  2. s.directSendMesg(通知者, メッセージ)
  3. }

同時送信。ここでは、コルーチン プールを使用して morestack の消費を回避し、sync.waitgroup を使用して非同期待機を実装します。

  1. //xiaorui.cc
  2.  
  3. 通知:= []*mapping.StreamNotifier{}
  4. // 変換スライス
  5. for _、notifier := range notifierMap {
  6. 通知者 = append(通知者, 通知者)
  7. }
  8.  
  9.  
  10. // 最適化: 直接マップ構造体
  11. タスクチャンク:= b.splitChunks(通知、バッチチャンクサイズ)
  12.  
  13.  
  14. // 同時送信チャネル
  15. wg := sync.WaitGroup{}
  16. _の場合、チャンク:=範囲taskChunks{
  17. chunkCopy := chunk // スライスレプリカ
  18. WG。追加(1)
  19. b.送信ブロック(
  20. 関数() {
  21. _の場合、notifier := range chunkCopy {
  22. b.directSendMesg(通知、メッセージ)
  23. }
  24. wg.完了()
  25. },
  26. }
  27. wg.Wait()

オンライン監視パフォーマンスによると、レイテンシは 200 ミリ秒から 30 ミリ秒に短縮されました。ここでより詳細な最適化を行うことができます。クライアント数が 5,000 未満の場合は、直接シリアルで呼び出すことができます。それ以外の場合は、同時に呼び出すことができます。

問題3: タイマーが多すぎるとCPUオーバーヘッドが増加する

マーケットプッシュにはハートビート検出やタスク時間制御が多数ありますが、それらはすべてタイマーに依存しています。 Go 1.9 以降、単一の timerproc が複数の timerproc に変更され、ロックの競合が減少しました。ただし、クアッドヒープ データ構造の時間計算量は依然として複雑であり、高精度によって発生するツリーおよびロック操作は依然として頻繁に発生します。

したがって、ここでは上記の問題を解決するためにタイムホイールが使用されます。データ構造は単純なループ配列とマップに変更され、時間精度は第2レベルに弱められています。時間差はビジネス上許容範囲内です。

Golangタイムホイールのコードはgithub[3]にプッシュされています。タイムホイールの多くのメソッドは、golang のタイムネイティブライブラリと互換性があります。興味のある方はぜひご覧ください。

問題4: 複数のコルーチンがチャネルを読み書きするときに送信クローズパニックが発生する

解決策は非常に簡単です。チャネルを直接使用しないでください。代わりに、トリガーをカプセル化します。クライアントが閉じられているときは、積極的にチャンを閉じないでください。代わりに、トリガー内の ctx を閉じて、トピックとトリガー間のマッピングを直接削除します。

  1. //xiaorui.cc
  2.  
  3. // トリガー構造
  4. StreamNotifier構造体型{
  5. GUID文字列
  6. キュー チャン インターフェース{}
  7.  
  8.  
  9. 閉じた int32
  10. ctx コンテキスト.コンテキスト
  11. キャンセルコンテキスト.CancelFunc
  12. }
  13.  
  14.  
  15. func (sc *StreamNotifier) ​​IsClosed() bool {
  16. sc.ctx.Err() == nilの場合{
  17. 戻る 間違い 
  18. }
  19. 戻る 真実 
  20. }
  21.  
  22. ...

質問5: grpcスループットパフォーマンスの向上

grpc は http2 プロトコルに基づいて実装されており、http2 自体はストリームの多重化を実装しています。一般的に、イントラネット内の 2 つのノードは、パフォーマンスの問題が発生することなく、単一の接続でネットワーク帯域幅全体を使用できます。ただし、golang で実装された grpc には、さまざまなロック競合の問題があります。

最適化するにはどうすればいいですか?ロック競合の競合の可能性を回避するために、複数の grpc クライアントを開きます。テストの結果、qps は 80,000 から約 200,000 に大幅に改善されました。

以前に書かれたgrpcパフォーマンステスト[4]を参照してください。

問題6: コルーチンの数を減らす

イベントを待機するコルーチンが多すぎると、メモリを消費するだけでコルーチンをスケジュールできず、実行時のパフォーマンスも低下しないので問題ないと考える人もいます。この記述は間違いです。スケジュール設定できず、メモリを占有するだけのように見えますが、GC に大きなオーバーヘッドが発生します。したがって、アイドル コルーチンをあまり多く開かないでください。たとえば、大きなコルーチン プールを開かないでください。

プッシュ アーキテクチャでは、プッシュ ゲートウェイからプッシュ サーバーへの接続は、少数の接続だけでなく、数十のストリームを必要とします。私たちは、12 を超えるストリームで実行される大量のメッセージを独自に実装し、通知をスケジュールします。 golang grpc ストリーミングの実装では、各ストリーミング要求でイベントを待機するためのコルーチンが必要です。したがって、ストリーム チャネルを共有すると、コルーチンの数も削減できます。

質問7: GCの問題

頻繁に作成される構造の場合、キャッシュには sync.Pool が使用されます。一部のビジネス キャッシュは、以前はリンク リストを使用して保存されていました。新しいデータが継続的に更新されると、新しいオブジェクトが絶えず作成され、GC に影響します。したがって、ホット キャッシュを実装するには、再利用可能な循環配列が使用されます。

追記

穴を恐れるのではなく、ただ埋めればいいのです。

参考文献

[1]github: https://github.com/rfyiamcool/ccmap/blob/master/syncmap.go

[2]ベンチマーク: https://github.com/rfyiamcool/go-benchmark/tree/master/batch_notify_channel

[3]github: https://github.com/rfyiamcool/go-timewheel

[4] テスト: https://github.com/rfyiamcool/grpc_batch_test

<<:  AppleがGoogle Cloudの最大のユーザーとなり、2021年の支払いは3億ドルを超えると予想

>>:  Flink分散プログラムにおける例外処理

推薦する

s"unspeakable" mvz が iniz に改名 128M メモリ デュアル コア VPS 年間支払い 12 ポンド

Hostcat は以前、自社の Web サイトで「unspeakable」mvz というプロモーショ...

個人的な経験:タオバオの商人はユーザーを騙し、オンラインショッピングをする際には注意するよう皆に警告している

インターネット セキュリティは絶えず求められ、推進されており、2014 年のクリーン インターネット...

インターネットマーケティングの学習を始める場所 - 観察から始める

私のチームのメンバーの多くは、よく私に次のような質問をします。「インターネット マーケティングを学び...

どの韓国のクラウドホスト/韓国のクラウドサーバーが優れていますか?韓国のクラウドベンダーが推奨!

どの韓国のクラウドホストが優れていますか?どの韓国のクラウドサーバーが優れていますか?どの韓国のクラ...

Woothosting-24ドル[2年]/2Gメモリ/30Gハードディスク/2Tトラフィック/フェニックス

WootHosting の公式ウェブサイトによると、同社は 2007 年に設立され (ドメイン名は ...

SEO について何も知らない初心者はどこから学習を始めるべきでしょうか?

5か月前、初めてSEOという言葉を聞き、それが私の仕事の始まりでもありました。この「神秘的で奥深い」...

他人の名前を間違って発音することから生じる SEO に関する考察

最近、劉玉凡は執筆に忙しく、自分が考えたことをいくつか書いています。録音は良い習慣なので、一生懸命取...

鐘を鳴らす:競争戦略の観点から見たブランド構築の幻想と真実

テキスト | 曽祥玲出典: 科学技術貿易摩擦が続く中、国家の自立を求める声が相次いでいる。 5月10...

Amazon vs. Microsoft vs. Alibaba: クラウドコンピューティングの三王国

世界のクラウドコンピューティング/パブリッククラウド市場は、Amazon(AWS)、Microsof...

衣料品ウェブサイト向け検索エンジン最適化ソリューション

これは、当社の衣料品ウェブサイトの状況に基づいて、いくつかの一般的な SEO 手法をまとめたものです...

Wanlian は 2015 年データセンター DCIM 管理 SaaS プラットフォーム イノベーション製品賞を受賞しました

最近、2015年中国ソフトウェア会議が北京で開催されました。会議の重要な部分として、主催者の中国情報...

クラウド化、値下げ、苦難を乗り越えたクラウドコンピューティングはどこへ向かうのか?

クラウド コンピューティング業界を一文で要約すると、「あらゆる「災難」にもかかわらず、業界は前進を続...

企業がツールを活用してクラウドコストを管理する方法

パブリック クラウドのオンデマンド価格モデルは、クラウド コンピューティングの主な利点であるアプリケ...

クラウドコンピューティングとスマート機器技術の変革

産業部門は、比類のない精度、正確さ、品質を得るために、急速に自動化へと移行しています。高度な計測ソリ...

2013年ウェブマスターネットワーク第26回公益講演会「地域人材採用サイト運営経験」

中国国内の3大人材募集サイトであるChinaHR、51job、Zhaopin.comは、中国の人材募...