The Go Blog
Go GC: 低遅延とシンプルさを優先
セットアップ
Go は、2015年だけでなく2025年以降のためにもガーベージコレクター(GC)を構築しています。つまり、今日のソフトウェア開発をサポートし、今後10年間、新しいソフトウェアとハードウェアとともにスケールする GC です。そのような未来には、Go のような安全でセキュアな言語の幅広い用途を妨げてきた、ストップ・ザ・ワールド GC ポーズの居場所はありません。
Go 1.5 は、この未来を垣間見せるものであり、1年前に設定した10ミリ秒の目標をはるかに下回る GC レイテンシーを実現しています。Gophercon での発表では、いくつかの印象的な数値を提示しました。レイテンシーの改善は大きな注目を集めています。Robin Verlangen のブログ投稿「1日あたりの何十億ものリクエストが Go 1.5 と出会う」は、エンドツーエンドの結果で私たちの方向性を検証しています。また、Alan Shreve のプロダクションサーバーのグラフと彼の「まさかの85%削減」というコメントも特に気に入っています。
今日、16ギガバイトの RAM は100ドルで、CPU には多くのコアがあり、それぞれが複数のハードウェアスレッドを備えています。10年後には、このハードウェアは古めかしく見えるでしょうが、今日 Go で構築されているソフトウェアは、拡大するニーズと次の大きなものに対応するためにスケールする必要があります。ハードウェアがスループットを向上させるパワーを提供することを考えると、Go のガーベージコレクターは、低遅延と単一のノブによるチューニングを優先するように設計されています。Go 1.5 は、この道のりの最初の大きな一歩であり、これらの最初の一歩は、Go とそれが最適にサポートするアプリケーションに永遠に影響を与えるでしょう。このブログ投稿では、Go 1.5 コレクターのために私たちが何をしてきたかについて、高レベルの概要を説明します。
装飾
次の10年間のガーベージコレクターを作成するために、私たちは何十年も前のアルゴリズムに目を向けました。Go の新しいガーベージコレクターは、並行、三色、マーク・アンド・スイープコレクターであり、Dijkstra が1978年に最初に提案したアイデアです。これは、今日のほとんどの「エンタープライズ」レベルのガーベージコレクターとは意図的に異なるアプローチであり、最新のハードウェアの特性と最新のソフトウェアのレイテンシー要件によく適していると私たちは考えています。
三色コレクターでは、すべてのオブジェクトは白、灰色、黒のいずれかであり、ヒープを接続されたオブジェクトのグラフとして見なします。GC サイクルが開始されると、すべてのオブジェクトは白色です。GC は、グローバル変数やスタック上のものなど、アプリケーションが直接アクセスできるオブジェクトであるすべての「ルート」を訪れ、これらを灰色に着色します。次に GC は灰色のオブジェクトを選択し、それを黒色にして、他のオブジェクトへのポインタをスキャンします。このスキャンで白色のオブジェクトへのポインタが見つかると、そのオブジェクトを灰色にします。このプロセスは、灰色のオブジェクトがなくなるまで繰り返されます。この時点で、白色のオブジェクトは到達不能であることがわかり、再利用できます。
これはすべて、コレクターが実行中にポインターを変更する、ミューテーターとして知られるアプリケーションと並行して行われます。したがって、ミューテーターは、黒色のオブジェクトが白色のオブジェクトを指さないという不変条件を維持しなければなりません。そうしないと、ガーベージコレクターが、すでに訪問したヒープの一部にインストールされたオブジェクトを見失ってしまう可能性があります。この不変条件を維持するのが、ライトバリアの仕事です。これは、ヒープ内のポインターが変更されるたびにミューテーターによって実行される小さな関数です。Go のライトバリアは、現在白色のオブジェクトが到達可能になった場合に灰色に着色し、ガーベージコレクターが最終的にそのポインターをスキャンするようにします。
すべての灰色のオブジェクトを見つける作業がいつ完了するかを決定することは微妙であり、ミューテーターをブロックすることを避けたい場合には、高価で複雑になる可能性があります。物事をシンプルにするために、Go 1.5 は可能な限り並行して作業を行い、その後、すべての潜在的な灰色のオブジェクトのソースを検査するために一時的にストップ・ザ・ワールドを行います。この最終的なストップ・ザ・ワールドに必要な時間と、この GC が行う作業の総量との間のスイートスポットを見つけることは、Go 1.6 の主要な成果物です。
もちろん、詳細に悪魔が潜んでいます。GC サイクルはいつ開始するのか?その決定を下すためにどのようなメトリクスを使用するのか?GC は Go スケジューラーとどのように相互作用するべきか?ミューテーターのスレッドをスタックをスキャンするのに十分な時間一時停止するにはどうすればよいか?灰色、白、黒をどのように表現すれば、効率的に灰色のオブジェクトを見つけてスキャンできるか?ルートがどこにあるかを知るにはどうすればよいか?オブジェクト内のポインターがどこにあるかを知るにはどうすればよいか?メモリの断片化を最小限に抑えるにはどうすればよいか?キャッシュのパフォーマンスの問題にどのように対処するか?ヒープはどのくらい大きくするべきか?などなど、一部は割り当てに関連し、一部は到達可能なオブジェクトの検索に関連し、一部はスケジューリングに関連しますが、多くはパフォーマンスに関連しています。これらの各領域の低レベルな議論は、このブログ投稿の範囲を超えています。
より高いレベルでは、パフォーマンスの問題を解決する一つのアプローチは、パフォーマンスの問題ごとに GC ノブを追加することです。プログラマーは、アプリケーションに適した設定を探してノブを回すことができます。欠点は、10年間毎年1つか2つの新しいノブが追加された後、最終的に GC ノブターナー雇用法に行き着くことです。Go はその道を行きません。代わりに、GOGC と呼ばれる単一のノブを提供します。この値は、到達可能なオブジェクトのサイズに対するヒープの合計サイズを制御します。デフォルト値の100は、前回のコレクション後、到達可能なオブジェクトのサイズの100%大きく(つまり2倍)ヒープの合計サイズであることを意味します。200は、到達可能なオブジェクトのサイズの200%大きく(つまり3倍)ヒープの合計サイズであることを意味します。GC に費やす合計時間を短縮したい場合は、GOGC を増やしてください。メモリを減らすために GC 時間を増やす場合は、GOGC を減らしてください。
さらに重要なことは、次世代のハードウェアでRAMが倍増しても、単にGOGCを倍増させるだけでGCサイクルの数を半分にできることです。一方、GOGCは到達可能なオブジェクトのサイズに基づいているため、到達可能なオブジェクトを倍増させて負荷を倍増させても再調整は不要です。アプリケーションは単にスケールします。さらに、数十のノブの継続的なサポートに邪魔されることなく、ランタイムチームは実際の顧客アプリケーションからのフィードバックに基づいてランタイムの改善に集中できます。
オチ
Go 1.5 の GC は、ストップ・ザ・ワールドの一時停止が安全でセキュアな言語への移行の障壁ではなくなる未来をもたらします。それは、アプリケーションがハードウェアとともに楽にスケールし、ハードウェアが強力になるにつれて GC がより良く、よりスケーラブルなソフトウェアの妨げにならない未来です。これは、今後10年とその先にとって良い場所です。1.5 GC とレイテンシーの問題をどのように解消したかについての詳細は、「Go GC: レイテンシー問題解決」プレゼンテーションまたはスライドをご覧ください。
次の記事:Golang UK 2015
前の記事:Go 1.5 がリリースされました
ブログインデックス