Priorities/ja
ユーザ、問い合わせ、データベースについてのプライオリティ付け
PosgtgreSQLには特定のユーザ、問い合わせ、データベースが消費するリソースを制限する機能はありません。 同様にあるユーザ/問い合わせ/データベースが他より多くのリソースを得られるようなプライオリティを設定する機能もありません。 プライオリティの制限を実現するためにはオペレーティングシステムの機能を使用する必要があります。
PostgreSQLユーザ、問い合わせ、データベースが競い合うリソースには大きく以下の3つがあります。
- メモリ
- CPU
- ディスクI/O
3つの中で、ディスクI/Oがデータベースアプリケーションのボトルネックとなることがよくあります。 しかし常にそうとは限りません。 スキーマ・問い合わせ設計の中には特にCPUが大きな問題となることがあります。 その他大量のメモリを使用して作業することが、特にソート処理で、実際に利点となりえます。
プライオリティが本当に問題なのか?
問い合わせ/ユーザ/データベースへのプライオリティ付けを議論する前に、問い合わせを最適化しデータベースのチューニングを行うことが有効です。 プライオリティについて作業したり余計な手段を取ることなく、以下の技法を使用して、完全に受け入れられる性能を得ることができることが分かるかもしれません。
- 問い合わせの改良
- autovacuumの膨張化を防止するチューニング
- 一般的なクラスタの性能の向上
- VACUUM FULLの使用防止。これはインデックスの膨張をもたらす可能性があります。すると、大量のメモリを要し、そして、スキャンに長期間かかり、ディスクのI/Oバンド幅を無駄に使用してしまいます。詳しくはVACUUM FULL wikiページを参照ください。
CPUが本当にボトルネックなのか?
よく、CPUの性能不足(100%)であることを問題とし、これがデータベースの性能低下の原因であると仮定します。 これは必ずしも問題ではありません。 システムは100%近くCPUを使用していると示しているかもしれませんが、実際ほとんどはI/Oバンド幅の制限が原因です。 以下の試験を検討してください。 これは20個のddプロセスを起動し、それぞれのプロセスが異なる1Gbブロックをハードディスクからオフセット1Gbで読み取るものです。
for i in `seq 1 20`; do ( dd if=/dev/md0 bs=1M count=1000 skip=$(($i * 1000)) of=/dev/null &) done
'top'コマンドの出力結果は以下のようになります。
top - 14:51:55 up 3 days, 2:09, 5 users, load average: 10.92, 4.94, 2.93 Tasks: 259 total, 3 running, 256 sleeping, 0 stopped, 0 zombie Cpu(s): 1.6%us, 15.0%sy, 0.0%ni, 0.0%id, 78.6%wa, 0.8%hi, 4.0%si, 0.0%st Mem: 4055728k total, 3843408k used, 212320k free, 749448k buffers Swap: 2120544k total, 4144k used, 2116400k free, 2303356k cached PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND 33 root 15 -5 0 0 0 R 5 0.0 0:26.67 kswapd0 904 root 20 0 4152 1772 628 D 5 0.0 0:00.62 dd 874 root 20 0 4152 1768 628 D 3 0.0 0:00.74 dd 908 root 20 0 4152 1768 628 D 3 0.0 0:00.80 dd 888 root 20 0 4152 1772 628 D 3 0.0 0:00.44 dd 906 root 20 0 4152 1772 628 D 3 0.0 0:00.56 dd 894 root 20 0 4152 1768 628 D 2 0.0 0:00.49 dd 902 root 20 0 4152 1772 628 D 2 0.0 0:00.46 dd .... etc ....
これはCPUのビジー状態ではないかと混乱するかもしれませんが、実際は、ディスクI/Oが原因の負荷を示します。 ここで警告のキーとなる兆候は、CPU利用率の中でiowait("%wa")が高い割合を示していることです。 つまり、見かけの負荷の多くは実際にはI/Oサブシステムにおける遅延によるものであることを意味します。 `dd'プロセスのほとんどが'D'状態、つまりシステムコール内の割り込み不可のスリープ状態です。 もし"ps"コマンドの"wchan"を点検すると、I/O待ちのスリープであることがわかるでしょう。
CPUの競合が問題であると仮定するのではなく、利用可能なPerformance Analysis Toolsを使用して、システムの本当のボトルネックが何かについてより優れた情報を得ることを勧めます。
CPUについてのプライオリティ付け
CPUに関して、(Unixシステムでは)"nice"を使用することができますが、バックエンドに接続する クライアントプログラムではなく対象のバックエンドに"nice"を行う必要がありますので、多少扱 いづらいものです。"SELECT pg_backend_pid()" SQL問い合わせやpg_stat_activitiesビューの検索 を行うことでバックエンドプロセスIDを入手することができますが、通常のセッション内でバックエ ンドのnice値を変更する方法はありません。特定の大規模問い合わせがあり、その実行時間を減少 させたいような状況では、データベースクライアント外部でpg_stat_activityから対象の問い合わせ /クライアントを見つけ出し、この作業を行う監視プロセスを持つことができます。
バックエンド関数niceの開発
他の取りえる方法は、呼び出すバックエンドのnice値を"prio"に変更する"nice_backend(prio)" C関数を作成しインストールすることです。 "prio"を0以上に制限し、スーパーユーザのみが使用可能な、バックエンドのnice値を変更可能かつ任意のプライオリティに設定可能な第二の関数"nice_backend_super(pid,prio)"を提供してください。 だれもがこれを実装できるとはわかりませんが、関数のドキュメントや例を定義されたCユーザを元にたきつけ、この作業を行うようにnice(2)システムコールを使用することは難しくはないはずです。 もし似たようなものを作成しているのであれば、pgsql-performance mailing listに投稿し、ここにそのリンクを提供してください。
こうした関数を使用したとしても、ユーザアプリケーション自身でCPUに負荷をかける問い合わせを実行する前に適切なnice値を設定するように協調させなければなりません。 また、多くのバックエンドからの競合がある場合では大した効果は得られないでしょう。 重要ではないもののプライオリティを低くするよりも重要なバックエンドのプライオリティを増やす方がより効果的です。
I/Oについてのプライオリティ付け
I/Oはより難しいものです。 一部のオペレーティングシステムでは、Linuxのioniceのように、I/Oのプライオリティを提供するものがあります。 また、'nice'の使用方法と似たような方法でこれらを使用したいと考えるでしょう。 残念ながら、うまく動作しません。 PostgreSQLが行う作業、特にディスクへの書き込みが、すべてのバックエンドで共有されるメモリから動作する別個のバックグランドライタプロセスを介して行われるためです。 同様に先行書き込みログは共有メモリを介して独自のプロセスで管理されています。 これら2つのため、効率的に書き込みに関してユーザ別のプライオリティを与えることは非常に困難です。 しかし読み込みに関してはioniceは相当効果があるはずです。
"nice"同様、接続レベルにおける効率的な制御を行うためには、追加の適切な補助関数が必要です。 また、ユーザ毎のプライオリティを実現するためにはユーザの協力が必要です。
より良くI/O作業負荷を分離するためにはcluster separationが必要です。 これはデータベース毎レベルで独自のコストを持つものであり、データベースレベルでのみ有効です。
メモリについてのプライオリティ付け
PostgreSQLには、クライアント毎に使用するメモリに関するtunable parametersがいくつかあります。
具体的にはwork_mem
およびmaintenance_work_mem
です。
これらは、バックエンドがソート処理やインデックス作成などの作業のために通常のメモリ量より多くのメモリを使用することができるように、指定された接続内で設定されるかもしれません。
これらは保守的にpostgresql.conf
の低い値を設定し、そして、特定のバックエンドについてはより高い値を割り当てるように、たとえばSET work_mem = '100MB';
のようにSET
コマンドを使用することもできます。
PostgreSQL 8.5からユーザ毎のGUC変数を使用してwork_mem
およびmaintenance_work_mem
に別の値を設定することができます。
以下に例を示します。
ALTER USER myuser SET work_mem = '50MB';
この方法でshared_buffersなどの設定でなされた共有メモリ割り当てをを変更することはできません。 データベース起動時に決定される値であり、再起動しない限り変更できません。
ほとんどのオペレーティングシステムでは、例えばOSは他のバックエンドのメモリの代わりにバックエンドのメモリをswapさせるなどのメモリ割り当てをプライオリティ付けする簡単な方法はありません。
リンク
Credits
Page initially by Ringerc 02:34, 26 November 2009 (UTC)