GO言語のパフォーマンス問題の発見と解決

GO言語のパフォーマンス問題の発見と解決

事件の原因

この事件は、社内の同僚が社内メーリンググループに質問を投稿したことから始まりました。 go1.8.3 で書かれたビジネス プログラムをしばらく実行した後、一部の goroutine がロック ForkLock を待機して停止しました。同僚は、これは go1.8.3 のバグだと考えており、go1.10 にアップグレードした後も再発しませんでした。これを理解するために、同僚が github https://github.com/golang/go/issues/26836 に問題を投稿し、再現を何度も試みましたが、うまくいきませんでした。

問題が発生したビジネスコードを参照しました。大まかな使用方法は、親プロセスが os/exec の下のコマンドを呼び出して子プロセスを開き、シェル コマンドを実行することです。次に、コマンドは golang によってカプセル化された forkExec を呼び出して子プロセスを開き、コマンドを実行します。 forkExec は ForkLock を使用します。

問題分析

ForkLock は、次のような状況を回避するために存在します。複数の goroutine が同時に exec を fork する場合、子プロセスが必要なファイル記述子のみを継承するには、親プロセスがこれらのファイル記述子を作成するときに O_CLOEXEC フラグを追加して、これらの記述子が子プロセスで閉じられ、子プロセスが必要に応じて継承する必要がある記述子を開くことができるようにする必要があります。

Linux 2.6.27 以降では、ファイルやパイプを開いたり、O_CLOEXEC を設定したりすることはアトミック操作なので、大きな問題はありません。ただし、golang ではカーネル バージョンが 2.6.23 以上である必要があります。さらに、Unix システムでは、オープンと O_CLOEXEC の設定は 2 つの操作です。 2 つの操作間でフォークが発生した場合、子プロセスは必要のないファイル記述子を継承する可能性があるため、ロックが必要になります。 forkExec のソースコードに注目してください。

問題の現象から判断すると、goroutine が forkExecPipe または forkAndExecInChild ステップでスタックし、ロックが解除されない状態になっていると考えられます。そのため、一部のゴルーチンはロックを取得できず、飢餓状態になります。 forkExecPipe*** はカーネル pipe2 を呼び出し、forkAndExecInChild*** はカーネルの clone と exec を呼び出します。

推測

pipe2 は高速なシステム コールなので、ブロックされる可能性があるシステム コールは clone と exec です。なお、この問題はgo1.10では再発しません。 forkAndExecInChild 関数における go1.8 コードと go1.9 の違いを比較します。

1.8 に行く

1.9 へ

go1.9 では CLONE_VFORK と CLONE_VM が追加されました。 SIGCHILD のみを使用したクローン作成は、fork に似ていると考えられます (*** 両方とも do_fork を呼び出します)。 fork の問題は、親プロセスがより多くのメモリを占有するため、パフォーマンスが低下することです。詳細については、次のリンクを参照してください: https://bugzilla.redhat.com/show_bug.cgi?id=682922

このケースは 2011 年に提案され、今年 7 月時点でも更新中でした。この場合に反映される問題は、Linux カーネルがコピーオンライト メカニズムを導入したにもかかわらず、フォーク中にページ テーブルをコピーする必要があることです。プロセスの仮想メモリが大きいほど、コピーする必要があるページ テーブル エントリの数が多くなり、フォークが遅くなります。 Golang ディスカッション グループの誰かがテストしたところ、ヒープ サイズが 2G の場合、フォークにかかる時間はミリ秒単位まで短縮される可能性がある一方、通常は数十マイクロ秒であり、その差は数千倍にもなるとのことです。

Go1.9 では、子プロセスと親プロセスがメモリを共有できるようにするために、これら 2 つのパラメータが追加されました。これは、vfork を呼び出すのと同等です。ページテーブルをコピーする必要がないため、作成速度が速くなります。テスト結果から、数十マイクロ秒で安定しています。

したがって、go1.9 より前のバージョンで書かれたプログラムでは、プログラムのメモリ使用量が十分に大きく、プロセス作成の頻度が十分に高い場合、ForkLock は長時間待機することになるというのが妥当な推測です。

実験的デモンストレーション

go1.8.3 を使用してテスト プログラムを作成し、2 コア 4G 仮想マシン (カーネル 3.10.0-693.17.1.el7.x86_64) でテストしました。

10 秒ごとに、プログラムに SIGUSR1 信号が送信され、ランタイム スタックが印刷されます。しばらく実行すると、一部の goroutine では ForkLock を取得するのにかかる時間がどんどん長くなります。以下の2枚の写真をご覧ください。

ただし、go1.9以上では上記のような状況は発生しませんでした。この結果は問題を説明するのに十分だと思います。バージョンを go1.9 以上にアップグレードすると、この問題を解決できます。

***で書かれた

vfork は、ページ テーブル エントリをコピーするフォークによって発生するパフォーマンスの問題を解決するように設計されています。ほとんどのシナリオでは、exec は fork の後に呼び出されます。 Exec はすべてのページ テーブルを削除し、新しいページ テーブルをリセットします。ページ テーブル エントリを再度コピーする必要はまったくありません。ただし、vfork の親プロセスと子プロセスはメモリを共有するため、使用時には十分に注意する必要があります。子プロセスが変数を変更すると、親プロセスに影響し、カーネルは親プロセスを一時停止して、子プロセスを先に実行させます。これらの制限により、vfork は基本的に exec を使用するシナリオに制限され、fork ほど汎用的ではありません。

vfork は注意して使用する必要があり、go1.9 が vfork とともにリリースされる前に、rawVforkSyscall が戻った後も命令は親プロセス セグメントで実行されるため、子プロセスが両者の共有スタックを破壊する可能性があるため、コードが十分に堅牢ではないという意見がありました。そのため、図に示すように、この相互影響を解決するために、rawVforkSyscall が親プロセス セグメントで何もせず、戻った後に直接戻ることを許可するコミットが提案されました。

さらに詳しく知りたい場合は、Rob Pike 氏や他のユーザーがコメントしているこのコミットのレビューを参照してください。

https://go-review.googlesource.com/c/go/+/46173

<<:  クラウドコンピューティングの相互接続の未来とは?

>>:  アリババクラウドとHuyaが共同でライブストリーミング業界向けのエッジノードとクラウドエンタープライズネットワークサービスを初めて開始

推薦する

成功するウェブサイトには、高品質な内部リンクの構築が欠かせません

無駄なおしゃべりにこれ以上時間を無駄にせず、すぐに本題に入りましょう。ウェブサイトに内部リンクを構築...

GOは、高度な並列性と可用性を備えた分散システムを実装します。Logマイクロサービスの実装

この記事はWeChatの公開アカウント「Coding Disney」から転載したもので、著者はChe...

ウェブサイトのSEO最適化プロセスにおけるコンテンツ構築の思考方向の分析と解釈

ご存知のとおり、ウェブサイトの SEO 最適化のプロセスでは、コンテンツが第一の要素です。コンテンツ...

競争やツールを利用して自分を宣伝する方法を学ぶ

今日は、A5のウェブサイトに記事を投稿するのは初めてです。一生懸命努力すれば、良い結果が得られるとず...

企業にクラウドコンピューティングを提供する方法

世界中で猛威を振るっている新型コロナウイルスは人々の仕事や生活に深刻な影響を及ぼしており、組織は従業...

情報化時代において、クラウドを活用して新たな問題を解決する

青銅器時代から産業時代へと移行し、私たちは今、急速な技術の発展により、情報化時代という新たな画期的な...

ドメイン名とスペースの品質を検出する方法

スペースとドメイン名はウェブサイトにとって最も基本的なものなので、スペースとドメイン名が正常に使用で...

【ハードウェア仮想化】カーネルの理想郷からは程遠い

導入このストーリーでは、ハードウェア仮想化 (HVM) を使用して、独自のフック コードの一部をカー...

福建省の「リベートネットワーク」が崩壊:23省​​市を巻き込んだ高レベルの詐欺

5月31日、福州市西湖のほとりにある中福西湖花園北館6階は大混乱に陥っていた。広大なオフィスフロアに...

Baidu 入札はどこにでもありますが、草の根ウェブマスターはどこに行くべきでしょうか?

中国最大の検索エンジンである百度は、草の根のウェブマスターから愛され、嫌われている。私の小さなウェブ...

申し訳ありませんが、インターネット上で見つかったすべての Redis 分散ロックには脆弱性があります。

Redis ベースの分散ロックは誰もが知っているものですが、分散ロックが失敗したことはありますか?障...

国内外のブランドマーケティングの簡単な歴史

個人やブランドのIPを構築したい場合は、最終的にはブランドレベルに戻って基本的なブランド知識を学習し...

新たな小売業の起業の第二の春:伝統産業と伝統小売業の「化学反応」

2018年最もホットなプロジェクト:テレマーケティングロボットがあなたの参加を待っています「高速鉄道...

ローカルウェブサイトが収益性の高い業界を選択する方法について合理的に考える

大まかに言えば、ローカルポータルの主な収益源となる産業は、不動産、家具、結婚式、自動車です。将来の発...