カーネルリソースの管理

PostgreSQL 9.1.1文書
前のページ | 巻戻し | 第 17章サーバの準備と運用 | 早送り | 次のページ

# 17.4. カーネルリソースの管理

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

## 17.4.1. 共有メモリとセマフォ

共有メモリとセマフォはひとまとめに"System V IPC"と呼ばれます （メッセージキューも一緒ですが、これはPostgreSQLとは関係ありません）。 ほとんどすべての最近のオペレーティングシステムはこれらの機能を提供していますが、デフォルトではこれらの多くで有効になっていませんし、また、特に搭載されるRAMやデータベースアプリケーションの需要が大きくなっているにも関わらず、十分なサイズがありません。 （Windows版では、PostgreSQLは独自の代替的な実装でこれらの機能を提供しています。このため本節のほとんどは無視することができます）。

これらの機能の完全な欠落は、サーバ起動時のIllegal system callエラーによって判明します。 その場合はカーネルを設定し直すしかありません。 PostgreSQLはこれらの機能なしでは動きません。 しかし最近のオペレーティングシステムではこうした状況はまれなものです。

PostgreSQLが様々なIPCのハードリミットの1つを超えると、サーバは起動を拒否し、問題および何をすべきかを説明するエラーメッセージを残します。 （項17.3.1 も参照してください。） 関係するカーネルパラメータは別々のシステム上でも統一して名付けられています。 表17-1で概略がわかります。 しかしこれらを設定するための方法は異なります。 以下に、いくつかのプラットフォームへの提案を挙げます。

表 17-1. System V IPCパラメータ

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

共有メモリに関する一番重要なパラメータは、共有メモリセグメントの最大サイズのバイト数`SHMMAX`です。 もし`shmget`から"Invalid argument"のようなエラーメッセージを受けた場合、おそらくこの上限を超えています。 必要な共有メモリセグメントのサイズは、表17-2に示す各種のPostgreSQL設定パラメータによって変わります。 （エラー時に出力されるメッセージにはすべて、割り当て要求に失敗した正確なサイズが記載されています。） エラーをなくすための一時的な策として、これらの設定を低くすることもできます。 `SHMMAX`を2メガバイトとしてPostgreSQLを稼動させることができますが、受容できる性能を確保するためにはかなりより多くのサイズが必要です。 10メガバイト単位から100メガバイトから数ギガバイトの設定を推奨します。

また、システムの中には、システムにおける共有メモリの総量（`SHMALL`）に対する制限があるものがあります。 この値を確実に、PostgreSQLと共有メモリセグメントを使用する他のアプリケーションの合計よりも十分に大きくしてください。 多くのシステムで`SHMALL`はバイト単位ではなくページ単位であることに注意してください。

問題が少ないのは共有メモリセグメントの最小サイズ（`SHMMIN`）で、PostgreSQLでは最大でもおよそ500キロバイトのはずです（通常では1です）。 システム全体のセグメントの最大数（`SHMMNI`）もしくはプロセスごとのセグメントの最大数（`SHMSEG`）に関して、使用しているシステムで0に設定されていない限り、問題が起きることはほぼありません。

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

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

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

`SEMMNU`と`SEMUME`のような、その他の様々な"semaphore undo"に関する設定はPostgreSQLには影響を与えません。

AIX

  少なくともバージョン5.1では、すべてのメモリが共有メモリとして使用できるように設定されているようにみえますので、`SHMMAX`などのパラメータに対して特別な設定は必要ありません。 これはDB/2などの他のデータベースでも使用される、一般的な設定方法です。

  しかし、`/etc/security/limits`内の大域的な`ulimit`情報は変更しなければならないかもしれません。 デフォルトのファイルサイズ（`fsize`）とファイル数（`nofiles`）用のハードリミットは低過ぎるかもしれないためです。

BSD/OS

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

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

  `SHMALL`は4キロバイトページ単位ですので、1024という値は、共有メモリが4メガバイトであることを示します。 したがって、上記では、最大の共有メモリ領域を32メガバイトまで増加しています。 4.3以降では、おそらく`KERNEL_VIRTUAL_MB`をデフォルトの`248`より増やさなければなりません。 すべての変更を行った後、カーネルを再コンパイルし、リブートしてください。

  セマフォ. セマフォの数についても増やしたい場合があるかもしれません。 デフォルトのシステム合計である60という値では、およそ50個のPostgreSQL接続しかできません。 希望する値をカーネル設定ファイルに設定してください。例えば、

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

FreeBSD

  デフォルトの設定は、小規模なインストレーションでのみ適しています（例えば、デフォルトの`SHMMAX`は32メガバイトです）。 `sysctl`または`loader`インタフェースを使用して変更を行うことができます。 以下では`sysctl`を使用してパラメータを変更しています。

      $ sysctl -w kern.ipc.shmall=32768
      $ sysctl -w kern.ipc.shmmax=134217728
      $ sysctl -w kern.ipc.semmap=256

  これらの設定をリブートしても永続化するには、`/etc/sysctl.conf`を変更します。

  残りのセマフォ設定は`sysctl`では読み取りのみとみなされていますが、起動前に`loader`プロンプトを使用して変更することができます。

      (loader) set kern.ipc.semmni=256
      (loader) set kern.ipc.semmns=512
      (loader) set kern.ipc.semmnu=256

  同様に、これらの設定をリブートしても永続化させるには`/boot/loader.conf`に保存します。

  また、共有メモリをRAM上に残し、スワップへのページアウトを行わせないようにさせたいかもしれません。 これは`sysctl`の`kern.ipc.shm_use_phys`設定を使用して実現できます。

  sysctlの`security.jail.sysvipc_allowed`を有効にしてFreeBSD jailを実行している場合、異なるjailで実行するpostmasterを異なるオペレーティングシステムユーザで実行しなければなりません。 これは、非特権ユーザが別のjailの共有メモリやセマフォに干渉することを防止できるため、セキュリティが向上します。 また、これによりPostgreSQLのIPCを整理するコードを適切に動作させることができます。 （FreeBSD 6.0以降では、IPC整理コードは他のjailにおけるプロセスを適切に検出せず、異なるjailで同一ポートでpostmasterを実行させることができません。）

  FreeBSDバージョン4.0以前では、（後述の）NetBSDとOpenBSDと同様に動作します。

NetBSD
OpenBSD

  `SYSVSHM`オプションと`SYSVSEM`オプションはカーネルのコンパイル時に有効にする必要があります（デフォルトでは有効になっています）。 共有メモリの最大サイズは`SHMMAXPGS`オプション（ページ数）で決定されます。 以下にNetBSDにおける様々なパラメータの設定方法の例を示します（OpenBSDでは代わりに`option`が使用されています）。

      options        SYSVSHM
      options        SHMMAXPGS=4096
      options        SHMSEG=256

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

  また、共有メモリを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

  デフォルトの最大セグメントサイズは32メガバイトで、非常に小規模なPostgreSQLインストレーションのみに適しています。 デフォルトの最大総サイズは2097152ページです。 "大規模ページ"を持つ通常ではないカーネル設定を除き、1ページはほとんど常に4096バイトです。 (検証には`getconf PAGE_SIZE`を使用してください。) これによりデフォルトの上限は8ギガバイトになります。 たいていは十分ですが、常に十分というわけではありません。

  共有メモリサイズの設定は`sysctl`インタフェースを使用して変更可能です。 例えば16ギガバイトまで許すには以下のようにします。

      $ sysctl -w kernel.shmmax=17179869184
      $ sysctl -w kernel.shmall=4194304

  更にこれらの設定をリブート時に保持できるように`/etc/sysctl.conf`に保存することができます。 こうすることを大いに勧めます。

  古めのディストリビューションでは`sysctl`プログラムが存在しない可能性があります。 この場合、`/proc`ファイルシステムに対する操作で同等の変更を行うことができます。

      $ echo 17179869184 >/proc/sys/kernel/shmmax
      $ echo 4194304 >/proc/sys/kernel/shmall

  他のデフォルトはかなり豊富なサイズですので、通常は変更する必要はありません。

Mac OS X

  OS Xにおける共有メモリの推奨設定方法は、以下のような変数代入文からなる`/etc/sysctl.conf`という名称のファイルを作成することです。

      kern.sysv.shmmax=4194304
      kern.sysv.shmmin=1
      kern.sysv.shmmni=32
      kern.sysv.shmseg=8
      kern.sysv.shmall=1024

  一部のバージョンのOS Xでは`/etc/sysctl.conf`内に共有メモリパラメータ5つすべてを設定しなければならないという点に注意してください。 さもなくば値が無視されます。

  最近のリリースのOS Xは、`SHMMAX`を4096の倍数以外に設定しようとすると無視しますので、注意してください。

  このプラットフォームでは`SHMALL`は4キロバイトページ単位です。

  古めのバージョンのOS Xでは、共有メモリパラメータの変更を有効にするためにリブートが必要になります。 10.5から`SHMMNI`以外の変更は、sysctlを用いることにより、その場で行うことができます。 しかしいずれにせよ`/etc/sysctl.conf`経由で望む値に設定することが最善です。 リブートを行っても値が保持されるからです。

  `/etc/sysctl.conf`はOS X 10.3.9以降でのみ使用されます。 もしこれより前の10.3.xリリースを使用しているのであれば、`/etc/rc`ファイルを編集し、以下のコマンドで値を変更しなければなりません。

      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

  通常`/etc/rc`はOS Xのアップデートで上書きされることに注意してください。 ですので、アップデートの度に編集し直す必要があるものと考えなければなりません。

  OS X 10.2以前では、代わりに`/System/Library/StartupItems/SystemTuning/SystemTuning`ファイル内にあるこれらのコマンドを編集してください。

SCO OpenServer

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

      ./configure -y SHMMAX

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

      ./configure SHMMAX=value

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

      ./link_unix

Solaris 2.6から2.9 (Solaris 6からSolaris 9)

  共有メモリセグメントのデフォルトの最大サイズは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://sunsite.uakom.sk/sunworldonline/swol-09-1997/swol-09-insidesolaris.htmlを参照してください。

Solaris 2.10 (Solaris 10)
OpenSolaris

  Solaris 10とOpenSolarisでは、デフォルトの共有メモリとセマフォ設定は大抵のPostgreSQLアプリケーションで十分あります。 Solarisのデフォルトの`SHMMAX`はシステムのRAMの1/4になりました。 共有メモリの設定をより大きく設定するためにこの値を増やしたいのであれば、`postgres`ユーザに関するプロジェクト設定を使用しなければなりません。 例えば以下を`root`権限で実行してください。

      projadd -c "PostgreSQL DB User" -K "project.max-shm-memory=(privileged,8GB,deny)" -U postgres -G postgres user.postgres

  このコマンドは`user.postgres`プロジェクトを追加し、`postgres`ユーザの共有メモリの最大サイズを8GBまで上げます。 この影響は次にこのユーザがログインした時、またはPostgreSQLを再起動した時（再読み込み時ではありません）に有効になります。 上ではPostgreSQLは`postgres`グループに属する`postgres`ユーザにより実行されていることを前提としています。 サーバの再起動は不要です。

  多くの接続を受け付けるデータベースサーバにおいて推奨するカーネル設定にはこの他に以下があります。

      project.max-shm-ids=(priv,32768,deny)
      project.max-sem-ids=(priv,4096,deny)
      project.max-msg-ids=(priv,4096,deny)

  さらに、ゾーン内でPostgreSQLを実行している場合、ゾーンのリソース使用上限も上げる必要があるかもしれません。 `projects`と`prctl`についてはSolaris 10 System Administrator's Guideの第2章 プロジェクトとタスクを参照してください。

UnixWare

  UnixWare 7では、共有メモリセグメントの最大サイズはデフォルト設定で512キロバイトしかありません。 現在の`SHMMAX`値を表示するためには下記を実行してください。

      /etc/conf/bin/idtune -g SHMMAX

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

      /etc/conf/bin/idtune SHMMAX value

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

      /etc/conf/bin/idbuild -B

表 17-2. PostgreSQLの共有メモリ使用量

使用法 | 必要な共有メモリのおおよそのバイト数（8.3時点）
--- | ---
接続 | (1800 + 270 * max_locks_per_transaction) * max_connections
自動バキュームワーカ | (1800 + 270 * max_locks_per_transaction) * autovacuum_max_workers
プリペアドトランザクション | (770 + 270 * max_locks_per_transaction) * max_prepared_transactions
共有ディスクバッファ | (block_size + 208) * shared_buffers
WALバッファ | (wal_block_size + 8) * wal_buffers
固定の必要な空き容量 | 770 kB

## 17.4.2. リソースの制限

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

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

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

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

- Linuxでは、`/proc/sys/fs/file-max`が、カーネルがサポートするオープンファイル数の最大を決定します。 この数を変えるためには、そのファイルに別の数を書き込むか、あるいは`/etc/sysctl.conf`に代入式を追加します。 プロセスごとのファイルの最大制限はカーネルがコンパイルされた時に固定されます。 詳しい情報については`/usr/src/linux/Documentation/proc.txt`を参照してください。

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

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

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

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

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

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

    Out of Memory: Killed process 12345 (postgres).

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

この問題を防止する1つの方法として、PostgreSQLを他のプロセスがそのマシンのメモリを枯渇させないことが確実なマシンで起動するというものがあります。 物理メモリとスワップ領域が消費尽くされた時のみにメモリ不足（OOM）キラーが発生するため、メモリが不足する場合、オペレーティングシステムのスワップ領域を増やすことが問題解決の役にたちます。

Linux 2.6以降では、メモリを"オーバーコミット"させないようにカーネルの動作を変更することができます。 この設定は完全にOOMキラーの発生を防ぐことはできませんが、その発生頻度をかなり軽減しますので、システム動作の堅牢性をより高めます。 これは、以下のように`sysctl`を使用して厳密なオーバーコミットモードを選択すること、もしくは、`/etc/sysctl.conf`に同等の項目を記述することで実施されます。

    sysctl -w vm.overcommit_memory=2

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

`vm.overcommit_memory`の変更と関係なく使用できる、その他の方法はpostmasterプロセス向けのプロセス固有の`oom_adj`値を`-17`に設定することです。 これによりOOMキラーの対象とならないことが保証されます。 このための最も簡単な方法は以下をpostmasterの起動スクリプト内でpostmasterを実行する直前に実行することです。

    echo -17 > /proc/self/oom_adj

この作業をrootで実行しなければならないことに注意して下さい。 さもないと効果がありません。 このためrootが所有する起動スクリプトがこれを行うためには最も簡単な場所です。 こうした場合、PostgreSQLの構築時に `-DLINUX_OOM_ADJ=0`を`CFLAGS`に追加したいと考えるでしょう。 これによりpostmasterの子プロセスは通常のゼロという`oom_adj`を持って実行されるようになり、必要に応じてOOMキラーの対象となりえます。

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

前のページ | ホーム | 次のページ
データベースサーバの起動 | 上に戻る | サーバのシャットダウン