blog

PostgreSQLの問題点を解決する

は1996年までさかのぼる非常に古いシステムで、複数のオペレーティングシステム上で多くのユーザーによって実行されています。そのため、開発者が追加できるLinux固有のコードには限りがあります。Linu...

Aug 28, 2015 · 6 min. read
シェア

カーネルはさまざまなワークロードに対応する必要があります。カーネルがユーザーコミュニティの一部の人たちが望むようなパフォーマンスを常に発揮するわけではないことは、間違いなく驚くべきことではありません。2014 Linux Storage, Filesystems, and Memory Management Summitの主催者からの招待に応じて、PostgreSQLの開発者であるRobert Haas氏、Andres Freund氏、Josh Berkus氏が参加し、最も痛みを伴う問題と考えられる解決策について議論しました。解決策

PostgreSQLは1996年までさかのぼる非常に古いシステムです。そのため、PostgreSQLの開発者はLinux固有のコードを追加できる量に制限があります。Linuxは協調プロセスに基づいており、スレッドは使用しません。プロセス間通信にはSystem V共有メモリが使用されます。重要な点として、PostgreSQLは独自の内部バッファを保持しますが、ディスクとのデータの読み書きにはI/Oバッファも使用します。このバッファの組み合わせにより、PostgreSQLのユーザが経験するいくつかの問題が発生します。

低速同期

***PostgreSQLは "書き込み前ロギング "と呼ばれるロギング形式を使用しています。ログが安全にディスクに保存されると、主要なデータベースブロックを書き戻すことができます。この作業の多くは、"チェックポイント "プロセスによって行われます。チェックポイントプロセスは、ログエントリを書き込んだ後、データのバッチをディスク上の様々なファイルに書き戻します。これらのログ可能な書き込みは比較的小さく、継続的に行われます。[Robert Haas]

データの書き込みは別の問題です。チェックポイント・プロセスは、I/Oシステムが他のすべてを圧倒しないように、これらの書き込みを調整します。しかし、fsync()を呼び出して、データが安全に書き込まれたことを確認し、これらの調整された書き込みがすべてリクエストキューに即座にプッシュされることを考え始めたとき、I/Oの嵐につながりました。彼らによると、問題はfsync()が遅すぎることではなく、速すぎることでした。fsync()はI/Oシステムに大量のデータをエクスポートするため、アプリケーションからの読み取り要求など、それ以外のものがブロックされてしまったのです。これはユーザを苦しめ、PostgreSQLの開発者にとっても同様でした。

Ted Ts'o氏は、チェックポイントプロセスを利用可能なI/O帯域幅の特定のパーセンテージに制限することで解決できるのではないかと質問しました。しかしRobertは、I/Oの優先順位はもっと良いはずだと答えました。チェックポイントプロセスは、他のプロセスが帯域幅を必要としない場合、それを100%使用するには十分すぎるはずです。I/Oフレンドリーのメカニズムを使用することが提案されましたが、これにも問題があります。fsync()が実際のI/O操作を開始したときに、チェックポイント処理からのデータが書き込まれていたとしても、優先順位は強制されません。

Ric WheelerはPostgreSQLの開発者がデータを書き込む速度をよりよく制御する必要があると提案し、Chris MasonはI/O要求を生成する際にO_DATASYNCオプションを使用することでよりよく制御できると付け加えました。ここでの問題は、この実装ではPostgreSQLがストレージデバイスの速度を知る必要があるということです。

まず議論をI/Oに戻しましょう。要求キューの保守はI/Oスケジューラを通して実装されているため、PostgreSQLユーザが好んで使用するスケジューラのほとんどはCFQスケジューラの使用を避けるか、I/O優先度機構を全く実装しない傾向にあります。I/O優先度を提供するものでさえ、要求キューの長さを制限しています。ビッグデータのフラッシュ操作でキューはすぐに一杯になり、I/Oプライオリティはその効果をほとんど失います。これらのリクエスト・キューに余裕がない場合、高優先度のリクエストは非活性化され、望ましい高優先度を達成することはできません。I/O優先は問題を解決しないようです。

Tedは、もしPostgreSQL開発者が実行中のデータベースからこのI/Oパターンを構築するアプレットを提供し、問題を単純に再現する方法を提供できれば、カーネル開発者は解決策を見つけるために多くの異なるアプローチを試すことができるだろうと言いました。このようなアプレットはPostgreSQLの初期設定スクリプトに似ているかもしれませんが、独立したアプレットはカーネル開発者コミュニティが望むものです。

ダブルバッファリング技術

様々な理由でI/Oバッファリングを使用するケースが多いので、PostgreSQLは独自のバッファリング技術を採用する必要があります。PostgreSQLはある程度までメモリ使用数を大幅に増やしており、これは完全なシステムにとって有害です。

多くのメモリ浪費動作が効果的に取り除かれるはずです。PostgreSQLのキャッシュ上に、カーネルがページキャッシュ上に持つデータよりも新しいダーティデータがある例を考えてください。PostgreSQLがこのダーティなデータをフラッシュする時、ページキャッシュが書き換えられるという重要な処理は行われません。この場合、PostgreSQLがページキャッシュ上の該当ページを削除するようにカーネルに伝えることができれば良いのですが、現実にはこれを行うための良いAPIは今のところありません。Andrewによれば、ffadvise()関数のFADV_DONTNEEDパラメータを呼び出すことは可能で、これは事実上指定したページを読み込むトリガとなります。また、ファイル処理にマッピングすることなくmadvise()関数を使用することもできません。

PostgreSQLは自身のバッファからきれいなページを削除したかったのかもしれませんが、ページキャッシュにはコピーを残していたのかもしれません。考えられるシナリオは、実際にはI/Oを起動しない特別な書き込み操作、もしくは物理ページをページキャッシュに変換するシステムコールです。これらは表面上ではかなり議論されていますが、決定的な結論を与えている部分はありません。

来る

PostgreSQLユーザが頻繁に遭遇するもう1つの問題は、最近のカーネル機能の一部が実行性能の問題を引き起こしている可能性があるということです。例えば、透過的なラージページング機能はPostgreSQLのワークロードには何の役にも立たず、著しく遅くなります。明らかに、実際に自由なラージページングを生成することなく実行しようとするタイトなコードに多くの時間が費やされています。 そのため、多くのシステムで、透過的なラージページング機能をオフにしたところ、ひどい性能問題は単純になくなりました。

メル・ゴーマンは次のように答えました:もし圧縮がパフォーマンスを低下させるのであれば、それは欠陥でしょう。とはいえ、彼はかなり長い間、透過的なラージページングに欠陥を見つけていません。さらに彼によると、ある時点で圧縮を実行できるプロセス数を制限するパッチがリリースされているそうです。しかし、このパッチのコードはマージされていません。なぜなら、圧縮を実行するプロセス数が多すぎることが原因で問題が発生したワークロードはないからです。彼は、この特定のパッチを再検討する時期に来ているのではないかと考えました。

この機能は、システム全体のメモリが不足していなくても、カーネル内のいくつかの領域からページを再生成します。領域の再利用はPostgreSQLのワークロードを遅くします。PostgreSQLサーバではこの機能を単に無効にするのが一般的であり、Andres氏はゾーン再生成に関連する性能問題について何度もコンサルタントとして働いてきたと述べています。それは彼にとってお金を稼ぐための素晴らしい方法です。しかし、これらの問題を修正することは良いことでしょう。

メル氏によると、ゾーン・リカバリ・モデルは、システム内の全プロセスが1つのNUMAノードの下に組み込まれているという前提で書かれていたとのことです。この仮定はもはや意味を成さず、非常に時代遅れであると彼は述べ、このオプションのデフォルト値を「オフ」に変更しました。このアイデアに反対している人はいないようなので、近い将来少し変わるかもしれません。

*** Linuxカーネルの性能特性はリリースごとに大きく異なる傾向があり、このためアップグレードは不確実なものとなります。PostgreSQLベンチマークを実行するための新しいカーネルを見つけるという議論もありましたが、明確な結論には至りませんでした。しかし、全体として、両プロジェクトの開発者はこの会話がどのように行われたかに満足しています。

Read next

Lua標準ライブラリ - 文字列操作

全ての関数は文字列テーブルに格納され、メタテーブルが作成されます。

Aug 23, 2015 · 2 min read