テクノロジー 注目度 74

Linux 7.0の変更がPostgreSQLに深刻な影響:プリエンプションの回帰が原因

※本記事の要約および解説はAIが自動生成しており、誤りが含まれる可能性があります。事実確認は元ニュースをご参照ください。

AWSのエンジニアであるサルヴァトーレ・ディピエトロ氏が、Linuxカーネルのバージョンアップに伴うPostgreSQLのパフォーマンス低下という重大な問題を発見しました。彼は、Linux 7.0環境下で、96 vCPUのGraviton4マシン上でPostgreSQLの標準ベンチマークツールpgbenchを実行しました。その結果、スループットがLinux 6.xと比較して約半分にまで落ち込むという驚くべき結果を得ました(Linux 6.x: 98,565トランザクション/秒に対し、Linux 7.0: 50,751トランザクション/秒)。

パフォーマンスボトルネックを分析したところ、CPU時間の約55%が単一の関数`s_lock`(ロック取得処理)に費やされていることが判明しました。この問題の根本原因は、Linux 7.0で導入されたプロセススケジューリングの変更、特に「プリエンプション(Preemption)」の挙動の変化にあります。

PostgreSQLは、データを8KBの「データページ」単位で管理し、共有バッファプールにキャッシュします。複数のバックエンドプロセスがこの共有バッファプールにアクセスする際、排他制御のために「スピンロック」を使用します。スピンロックは、ロックが解放されるまで待機プロセスがCPUを消費し続ける仕組みです。

このシステムにおいて、ページフォールト(Page Fault)が発生した場合、ロックを保持しているプロセスはカーネルのフォールトハンドラ内で処理が停止します。Linux 7.0以降のスケジューラ(PREEMPT_LAZYなど)は、プロセスが動作中に割り込み(プリエンプション)をかける可能性が高まりました。その結果、ロックを保持したプロセスがページフォールトで停止している間に、他の多数のバックエンドプロセスがロックを待ってCPUを消費し続ける「スピン」状態に陥り、システム全体のスループットが劇的に低下するという事態を引き起こしました。これは、ロック保持中にフォールトが発生した場合のプリエンプションの挙動が、従来のカーネル(PREEMPT_NONE)と大きく異なるためです。


背景

PostgreSQLのような高並行性データベースは、共有リソースへのアクセスを制御するためにスピンロックなどの低レベルな同期機構に依存しています。Linuxカーネルのバージョンアップに伴い、プロセススケジューリングの挙動(特にプリエンプションの頻度)が変更されたことが、この種のロック機構とページフォールト処理の組み合わせにおいて、予期せぬ深刻なパフォーマンス問題を誘発しました。

重要用語解説

  • プリエンプション: OSが実行中のプロセスを強制的に中断し、他のプロセスにCPUを割り当てる仕組み。頻度が高いほど応答性は向上するが、コンテキストスイッチのオーバーヘッドが増大する。
  • スピンロック: ロックが解放されるのを待つ間、プロセスが休止する代わりにCPUを使い続け、ロックの解放を待機する同期機構。短いクリティカルセクションで有効。
  • ページフォールト: プロセスがアクセスしようとした仮想メモリのアドレスに対応する物理メモリのページが、現在存在しない(またはマップされていない)場合に発生する例外処理。カーネルが物理メモリを割り当てる必要がある。

今後の影響

本件は、高並行性環境でスピンロックとメモリ管理(特にページフォールト)が絡むデータベースシステムにとって、カーネルのスケジューリングモデルの選択が極めて重要であることを示しています。今後のデータベース開発やチューニングにおいては、使用するOSカーネルのプリエンプションレベルと、内部の同期機構の相互作用を深く考慮する必要が生じます。特定のワークロードでは、最新のカーネルが必ずしも最適とは限りません。