16.5. カーネルリソースの管理

大規模なPostgreSQLインストレーションでは、すぐに各種オペレーティングシステムのリソース制限を越えてしまうことがあります。 (システムによっては、実際に"大規模"なインストレーションでなくても、出荷時のデフォルトでは低過ぎるものもあります。) この種の問題が発生したら、これらを読んでください。

16.5.1. 共有メモリとセマフォ

共有メモリとセマフォは一まとめに"System V IPC"と呼ばれます。(メッセージキューも一緒ですが、これはPostgreSQLとは関係ありません。) ほとんどすべての最近のオペレーティングシステムはこれらの機能を提供していますが、 これらのすべて、特にBSD由来、で有効にされているとは限りませんし、デフォルトで十分なサイズがあるとも限りません。 (QNXBeOS の移植では、PostgreSQLは独自の代替的な実装でこれらの機能を提供しています。)

これらの機能の完全な欠落は、サーバ起動時のIllegal system callエラーによって判明します。 その場合はカーネルを設定し直すしかありません。 PostgreSQLはこれらの機能なしでは動きません。

PostgreSQL がさまざまな IPC のハードリミットの 1 つを越えると、サーバは起動を拒否し、発生した問題とおよび何をすべきかを説明するエラーメッセージを残します。 (項16.3.1 も参照してください。) 関係するカーネルパラメータは別々のシステム上でも統一して名付けられています。 (表16-2で概略がわかります。) しかしこれらを設定するための方法は異なります。 以下に、いくつかのプラットフォームへの提案を挙げます。 これらの設定を変えるには、しばしばマシンを再起動することが必要になり、カーネルをコンパイルし直す必要がある場合さえあるので注意してください。

表 16-2. System V IPC パラメータ

名前説明適切な値
SHMMAX共有メモリセグメントの最大サイズ(バイト)250 kB + 8.2 kB * shared_buffers + 14.2 kB * max_connections 以上から無限大
SHMMIN共有メモリセグメントの最小サイズ(バイト)1
SHMALL使用可能な共有メモリの総量(バイトまたはページ)バイト指定の場合 SHMMAX と同じです。 ページ指定の場合は ceil(SHMMAX/PAGE_SIZE)です。
SHMSEGプロセスごとの共有メモリセグメントの最大数必要なのは1セグメントだけですが、デフォルトではもっと多くなっています
SHMMNIシステム全体の共有メモリセグメントの最大数SHMSEGと同様 + 他のアプリケーション用の空間
SEMMNIセマフォ識別子の最大数(つまりセット)最低 ceil(max_connections / 16)
SEMMNSシステム全体のセマフォの最大数ceil(max_connections / 16) * 17 + 他のアプリケーション用の空間
SEMMSLセットごとのセマフォの最大数最低17
SEMMAPセマフォマップの中の項目の数本文を参照
SEMVMXセマフォの最大値最低1000(デフォルトはしばしば32767ですが、変更するようにいわれない限り変えないでください)

一番重要な共有メモリのパラメータは、共有メモリセグメントの最大サイズのバイト数 SHMMAX です。 もし shmget から Invalid argument のようなエラーメッセージを受けた場合、この上限を越えている可能性があります。 必要な共有メモリセグメントのサイズは要求されるバッファ数(オプション -B)と許されている接続数(オプション -N)によりますが、前者の方が重要です。(一時的な策として、エラーをなくすためにこれらの設定を低くすることもできます。) 大雑把な概算としては、必要とされるセグメントサイズは、バッファ数×ブロック数(デフォルトでは8Kバイト)+十分なオーバヘッド(少なくとも0.5Mバイト)と見積もることができます。 表示されるすべてのエラーメッセージには割り当てに失敗した要求サイズが表示されているはずです。

問題が少ないのは共有メモリセグメントの最小サイズ(SHMMIN)で、PostgreSQL では最大でもおよそ 256K バイトのはずです(通常では 1 です)。 システム全体のセグメントの最大数(SHMMNI)もしくはプロセスごとのセグメントの最大数(SHMSEG)は使用しているシステムで0に設定されていない限り問題はないはずです。 また、システムによっては、システム内の共有メモリの合計値にも制限を設定しています。 下記のプラットフォーム固有の指示を参照してください。

PostgreSQLは、許可した接続(-Nオプション)ごとに1つのセマフォを使用し、16個のセマフォを一集合として扱います。 この集合それぞれは17個目のセマフォを持ち、そのセマフォは他のアプリケーションに使われているセマフォセットとの衝突を検出するための"マジックナンバー"を持っています。 システム内のセマフォの最大数はSEMMNSによって設定され、その結果としてその値は少なくとも接続の設定分、ただし、16の接続毎に余分な1個を加えた値以上はなければいけません (表16-2の公式を参照してください)。 パラメータSEMMNIはシステム上に同時に存在できるセマフォ集合の数の上限を決定します。 ですからこのパラメータは少なくともceil(max_connections / 16)以上はなくてはいけません。 一時的な失敗の回避策としては許可される接続の数を下げることができますが、No space left on deviceという紛らわしい言葉が関数semget()から表示されます。

場合によっては SEMMAP を少なくとも SEMMNS と同程度に増やすことが必要になる場合があるかもしれません。 このパラメータはセマフォリソースマップのサイズを定義し、その中では有効なセマフォのそれぞれの隣接したブロックの項目が必要です。 セマフォ集合が解放されると、解放されたブロックに隣接するすでに存在する項目に追加されるか、もしくは新しいマップの項目の下に登録されます。 もしマップが一杯だった場合、解放されたセマフォは(再起動するまで)失われます。セマフォ空間の断片化により時間が経つごとに、有効なセマフォがあるべきよりも少なくなる可能性があります。

1つの集合の中にいくつのセマフォがあるかを決めるSEMMSLPostgreSQLでは少なくとも17はなくてはいけません。

SEMMNUSEMUMEのような、その他のさまざまな"semaphore undo"に関する設定はPostgreSQLでは問題にする必要がありません。

BSD/OS

共有メモリ. デフォルトでは、4Mバイトの共有メモリしかサポートされていません。 共有メモリはページングできないことを覚えておいてください。 RAMの中にロックされているのです。 システムでサポートされる共有バッファ数を増加するには、カーネル設定ファイルに以下を追加して下さい。 SHMALL の 1024 という値は、共有メモリが 4MB であることを示します。 以下では、最大の共有メモリ領域を 32MB まで増加しています。

options "SHMALL=8192"
options "SHMMAX=\(SHMALL*PAGE_SIZE\)"

4.3以降では、おそらくKERNEL_VIRTUAL_MBをデフォルトの248より増やさなければなりません。 すべての変更を行なった後、カーネルを再コンパイルし、リブートしてください。

4.0以前のリリースでは、bpatchを使用して現在のカーネルからsysptsizeを検索してください。 これは起動時に自動的に計算されます。

$ bpatch -r sysptsize
0x9 = 9

そして、SYSPTSIZEをカーネル設定ファイル内にハードコードした値として追加してください。 この値をbpatchを使用して見つけた値に増やしてください。 希望共有メモリを4MB増やす毎に1増加してください。

options "SYSPTSIZE=16"

sysptsizesysctlでは変更できません。

セマフォ. セマフォの数を増やす必要がある場合があるかもしれません。 デフォルトではPostgreSQLは34のセマフォを割り当てていますが、これはシステム合計のデフォルトである60の半分以上です。 希望する値をカーネル設定ファイルに設定してください。例えば、

options "SEMMNI=40"
options "SEMMNS=240"

FreeBSD
NetBSD
OpenBSD

オプション SYSVSHMSYSVSEM はカーネルのコンパイル時に有効にする必要があります(デフォルトでは有効になっています)。 共有メモリの最大サイズはオプションSHMMAXPGS(ページ数)で決定されます。 以下に、さまざまなパラメータの設定方法の例を示します。

options         SYSVSHM
options         SHMMAXPGS=4096
options         SHMSEG=256

options         SYSVSEM
options         SEMMNI=256
options         SEMMNS=512
options         SEMMNU=256
options         SEMMAP=256

(実際はNetBSDOpenBSDでは、このキーワードは単数形のoptionです。)

また、共有メモリを RAM の中にロックするようにカーネルを設定することで、スワップにページアウトしないようにもできます。 sysctl を使用してkern.ipc.shm_use_physを設定してください。

HP-UX

デフォルトの設定は通常のインストールではほぼ十分です。 HP-UX 10ではSEMMNSの出荷時のデフォルトは128ですが、これは大きなデータベースサイトには低すぎるかもしれません。

IPC パラメータはシステム管理マネージャSAM)からKernel Configuration->Configurable Parametersの下で、設定することができます。 終わったらCreate A New Kernelを押してください。

Linux

共有メモリ制限のデフォルト(SHMMAXSHMALLの両方とも)は2.2カーネルで32Mバイトですが、procファイルシステムで変えることができます(再起動なし)。 たとえば128Mバイトを許可するためには下記のようになります。

$ echo 134217728 >/proc/sys/kernel/shmall
$ echo 134217728 >/proc/sys/kernel/shmmax

これらのコマンドを起動時に実行されるスクリプトに記述することもできます。

他の方法として、sysctlが利用できるならば、それを使用してこれらのパラメータを制御することができます。 /etc/sysctl.confという名前のファイルを探し、そこに以下の行を追加してください。

kernel.shmall = 134217728
kernel.shmmax = 134217728

このファイルは通常は起動時に処理されますが、sysctlは後で明示的に呼び出すこともできます。

他のパラメータはどんなアプリケーションにも合うようなサイズに設定されています。 自分で確認したい場合は、/usr/src/linux/include/asm-xxx/shmparam.h/usr/src/linux/include/linux/sem.hを参照してください。

MacOS X

OS X 10.2以前では、/System/Library/StartupItems/SystemTuning/SystemTuning ファイルを編集して以下のコマンド内の値を変更します。

sysctl -w kern.sysv.shmmax
sysctl -w kern.sysv.shmmin
sysctl -w kern.sysv.shmmni
sysctl -w kern.sysv.shmseg
sysctl -w kern.sysv.shmall

OS X 10.3では、これらのコマンドは/etc/rcに移動されましたので、そこで編集しなければなりません。

SCO OpenServer

デフォルトの設定では、セグメント当たり512kBの共有メモリが許されています。 これは、-B 24 -N 12にはほぼ十分です。 この設定を増加させるには、まず、/etc/conf/cf.dディレクトリに移動します。 SHMMAXの現在値を表示させるには、以下を実行します。

./configure -y SHMMAX

SHMMAXに新しい値を設定するには、以下を実行します。

./configure SHMMAX=value

ここで、valueが希望する新しい値(バイト単位)です。 そして、以下のようにカーネルを再構築し、リブートします。

./link_unix

Solaris

少なくともバージョン 2.6 では、共有メモリセグメントのデフォルトの最大サイズは PostgreSQL には低すぎる設定になっています。 必要な設定は/etc/systemで変えることができ、たとえば以下のようになります。

set shmsys:shminfo_shmmax=0x2000000
set shmsys:shminfo_shmmin=1
set shmsys:shminfo_shmmni=256
set shmsys:shminfo_shmseg=256

set semsys:seminfo_semmap=256
set semsys:seminfo_semmni=512
set semsys:seminfo_semmns=512
set semsys:seminfo_semmsl=32

変更を反映させるには再起動する必要があります。

Solaris環境での共有メモリに関する情報については、http://www.sunworld.com/swol-09-1997/swol-09-insidesolaris.htmlも参照してください。

UnixWare

UnixWare 7では、共有メモリセグメントの最大サイズはデフォルト設定で512Kバイトです。 これは-B 24 -N 12にはおよそ十分です。 現在のSHMMAX値を表示するためには下記を実行してください。

/etc/conf/bin/idtune -g SHMMAX

これは現在値、デフォルト値、最小値、および最大値を、バイト単位で表示します。 SHMMAX の新しい値を設定するためには、以下を実行します。

/etc/conf/bin/idtune SHMMAX value

ここでvalue は、希望する新しい値 (バイト) です。 SHMMAXの設定が終わったらカーネルを再構築し、リブートします。

/etc/conf/bin/idbuild -B

16.5.2. リソースの制限

UnixライクなオペレーティングシステムではPostgreSQLサーバの操作と関係する可能性のあるさまざまな種類のリソース制限があります。 特に重要なのは、ユーザごとのプロセス数の制限、プロセスごとのオープンファイルの数、プロセスごとの利用可能なメモリの量です。 これらのそれぞれが"ハード""ソフト"の2つの制限を持っています。 ソフト制限が実際に有効な制限ですが、ユーザによってハード制限まで変えることが可能です。 ハード制限はルートユーザーによってのみ変えることができます。 システムコールsetrlimitがこれらのパラメータの設定を行います。 シェルの組み込みコマンドulimit(Bourne シェル)もしくはlimitcsh)は、コマンドラインからリソース制限を制御するために使われます。 BSD 派生システム上ではファイル /etc/login.conf が、ログイン時に設定されるさまざまなリソース制限を制御します。 詳細はオペレーティングシステムの文書を参照してください。 関連するパラメータはmaxprocopenfilesdatasizeです。例えば、

default:\
...
        :datasize-cur=256M:\
        :maxproc-cur=256:\
        :openfiles-cur=256:\
...

(-cur はソフト制限です。 ハード制限を設定するためには -max を付けてください。)

カーネルはいくつかのリソースに対して、システム全体の制限も持つことが可能です。

PostgreSQLサーバは接続ごとに1つのプロセスを使うので、少なくとも許可された接続の数だけのプロセスに残りのシステムで必要な分を追加したものが必要になります。 通常はこれは問題ではありませんが、1つのマシン上でいくつかのサーバを起動している場合は厳しい状況になるかもしれません。

オープンファイルの制限の出荷時のデフォルトは、しばしば大多数のユーザはマシン上でシステムリソースの不正使用をしないという前堤に立った"社会的に友好的な"値を設定してしまいます。 もし1つのマシン上で複数のサーバを起動する場合はそれが必要でしょうが、専用サーバではこの制限を上げたいかもしれません。

反対に、個々のプロセスが多数のファイルをオープンすることを許可するシステムもあります。 そのようなプロセスが数個以上あれば、システム全体の制限は簡単に越えてしまいます。 この発生を検知し、システム全体の制限の変更を望まない場合は、PostgreSQLmax_files_per_process 設定パラメータを設定し、オープンファイルの消費を制限することができます。

16.5.3. Linuxのメモリオーバーコミット

Linux 2.4 以降では、デフォルトの仮想メモリの動作はPostgreSQLには最適ではありません。 カーネルがメモリオーバーコミットを実装する方法のため、カーネルは、他のプロセスに依存するメモリがシステムの仮想メモリを枯渇させた場合、PostgreSQL(postmasterプロセス)を終了させる可能性があります。

これが発生した場合、以下のようなカーネルメッセージが現れます。 (こうしたメッセージを検索する場所についてはシステム文書と設定を参照してください。)

Out of Memory: Killed process 12345 (postmaster). 

これは、postmasterプロセスがメモリ不足のために終了してしまったことを示します。 起動中のデータベース接続は正常に動作しますが、新しい接続は受け付けられません。 復旧するには、PostgreSQL を再起動しなければなりません。

この問題を防止する1つの方法として、PostgreSQLを他のプロセスがそのマシンのメモリを枯渇させないことが確実なマシンで起動することがあります。

Linux 2.6以降では、メモリを"オーバーコミット"させないようにカーネルの動作を変更するという、より優れた解法があります。 これは、以下のようにsysctlを使用して厳密なオーバーコミットモードを選択すること、もしくは、/etc/sysctl.confに同等の項目を記述することで実施されます。

sysctl -w vm.overcommit_memory=2

また、関連するvm.overcommit_ratio設定を変更した方がいいでしょう。 詳細はDocumentation/vm/overcommit-accountingカーネル文書を参照してください。

Linux 2.4カーネルのベンダの中には、2.6のオーバーコミットsysctl版を持つものがあることが報告されています。 しかし、関係するコードを持たないカーネルでvm.overcommit_memoryを2に設定することはより状況を悪化させます。 2.4のインストレーションではこれを試す前に、実際のカーネルソースコードを調査し、その中でサポートしているかどうかを検証することを勧めます。(mm/mmap.cファイル内のvm_enough_memory関数を参照してください。) overcommit-accounting文書ファイルの存在は、この機能が存在するかどうかを証明するものではありません。 疑わしい場合は、使用中のカーネルベンダのカーネル専門家に相談してください。