GoのGCがスワップで40ms停止、原因はメタデータのページフォルト
A 40ms Go garbage collector pause caused by swap

Goのガベージコレクタはstop-the-world中にヒープ外のメタデータを読むが、そのページがスワップに追い出されていると、ページフォルトが発生し、40msもの停止を引き起こす。HetznerのNVMe上で計測したところ、中央値51usの停止が最大40msに達し、そのうち39msは228回のページフォルトに費やされていた。スワップ自体は悪ではないが、GCとの相性が悪いことを示す実測結果だ。
40msは中央値の800倍だ。テスト中のメモリスパイクで2、3回発生する。これは大きい。
HNでの議論
113- nasretdinov
残念ながら、それはある程度予想されることだ。実装がどうであれ、GCが参照されている部分をトレースするためにツリー全体を何らかの形で走査する必要があるという事実だけでも、swapは極めて非実用的になる。たとえ40msのstop-the-worldポーズがなかったとしても、swapが使うLRUキャッシュはGCのたびに捨てられてしまうだろう。
AppleがフレームワークでGCをやめて自動参照カウント方式に切り替えたのも、実は同じ理由だと思う。
- jacobgold
「これをやると痛いんだ」
「やめろよ」
レイテンシが気になるなら、swapを無効にしよう。システム全体で、あるいは特定のcgroupで。
- pizlonator
GoがオンザフライGC、つまりSTWが全くない方式を使わない理由でもあるのか?
- xavdid
Discordは2020年にこれを学んで、素晴らしいブログ記事を公開している:https://discord.com/blog/why-discord-is-switching-from-go-to...
- soltanov
GCレイテンシのSLOには、オペレーティングシステムのメモリプレッシャーを含めるべきだ。そうでなければ、ページフォルトの問題がコレクタの問題に見えてしまい、間違った修正につながる。
- Gabrys1
swapを意識したGCというのはあり得るのだろうか、たとえばまず必要なページをswapインして(そんな明白なAPIがあるわけではないが…)、それからworldを止めるとか?
- imclaren
これだよ。Goではメモリ肥大化のバグは比較的簡単に直せるが、swapの肥大化を解消するのは時に冒険になる。そしてswapの肥大化は全部解消する価値があると思う!
- faangguyindia
Node、Ruby、Pythonを使うようなところではGoを使う。
低レイテンシが必要なところではRustを使う。