★PostgreSQLカンファレンス2024 12月6日開催/チケット販売中★
他のバージョンの文書 16 | 15 | 14 | 13 | 12 | 11 | 10 | 9.6 | 9.5 | 9.4 | 9.3 | 9.2 | 9.1 | 9.0 | 8.4 | 8.3 | 8.2 | 8.1 | 8.0 | 7.4 | 7.3 | 7.2

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

PostgreSQLは、特に同一システム上で複数のサーバコピーを実行している場合や非常に大規模なインストレーションでは、オペレーティングシステムの様々なリソース制限を超えてしまうことがあります。 本節では、PostgreSQLで使用されるカーネルリソース、およびカーネルリソース消費に関連した問題を解消する時に取ることができる手順について説明します。

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

PostgreSQLはオペレーティングシステムが、プロセス間通信(IPC)特に共有メモリとセマフォ機能を提供することを要求します。 Unix(派生)システムでは、System V IPCや、POSIX IPC、またはその両方を提供します。 Windowsは、これらの機能を独自で実装しているため、ここでは説明しません。

デフォルトではPostgreSQLは通常、非常に少量のSystem V共有メモリと、もっと大量の無名mmap共有メモリを割り当てます。 代替方法として、単一の大きなSystem Vメモリリージョンも利用できます (shared_memory_type参照)。 さらに、System V又はPOSIXスタイルのどちらかのセマフォがサーバの起動時に作成されます。 現在、LinuxとFreeBSDシステムではPOSIXセマフォが使用され、それ以外のプラットフォームではSystem Vセマフォが使用されます。

System V IPC機能は、通常システム全体の割り当て制限に制約されます。 PostgreSQLがこれらの制限のいずれかを超えると、サーバは起動を拒否し、問題および何をすべきかを説明するエラーメッセージを残します。 (19.3.1 も参照してください。) 関係するカーネルパラメータは別々のシステム上でも統一して名付けられています。 表 19.1で概略がわかります。 しかしこれらを設定するための方法は異なります。 以下に、いくつかのプラットフォームへの提案を挙げます。

表19.1 System V IPCパラメータ

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

PostgreSQLは、サーバのコピー毎にSystem V共有メモリの数バイト(64ビットプラットフォームでは通常48バイト)を必要とします。 最近のほとんどのオペレーティングシステムでは、このくらいの量は簡単に割り当てられます。 しかし複数のサーバのコピーを実行している場合やSystem V共有メモリを使用する他のアプリケーションを実行している場合(shared_memory_typeおよびdynamic_shared_memory_typeを参照)は、システム全体のSystem V共有メモリであるSHMALLを増加させる必要があるかもしれません。 多くのシステムではSHMALLをバイト単位ではなくページ単位で測ることに注意してください。

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

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

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

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

POSIXセマフォを使用している場合、System Vと同じ数のセマフォを必要とします。 つまり、許可した接続(max_connections)、許可したオートバキュームワーカープロセス(autovacuum_max_workers)、許可したWAL送信プロセス(max_wal_senders)、許可したバックエンドプロセス(max_worker_processes)ごとに1つのセマフォを使用します。 このオプションが優先されるプラットフォームでは、POSIXセマフォの数に特定のカーネル制限はありません。

AIX

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

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

FreeBSD

shared_memory_typesysvに設定していない限り、通常はデフォルトの共有メモリ設定で十分です。 System V セマフォはこのプラットフォームでは使用しません。

デフォルトのIPC設定はsysctlまたはloaderインタフェースを使用して変更を行うことができます。 以下ではsysctlを使用してパラメータを変更しています。

# sysctl kern.ipc.shmall=32768
# sysctl kern.ipc.shmmax=134217728

これらの設定を再起動しても永続化するには、/etc/sysctl.confを変更します。

shared_memory_typesysvに設定している場合は、System V共有メモリをRAM上に固定して、スワップによってページアウトされるのを避けるために、カーネルを設定することもできます。 これはsysctlを使用してkern.ipc.shm_use_physを設定することで実現できます。

FreeBSD jailを実行している場合、sysvshmパラメータをnewに設定して、独自のSystem V共有メモリ名前空間を有するようにする必要があります。 (FreeBSD 11.0以前は、jailからIPC名前空間への共有アクセスを可能にし、衝突を避けるための対策を講じる必要がありました。)

NetBSD

shared_memory_typesysvに設定していない限り、通常はデフォルトの共有メモリ設定で十分です。 通常は、kern.ipc.semmnikern.ipc.semmnsを増やす必要があります。これは、NetBSDのデフォルト設定は不適切に小さいためです。

以下の例のようにIPCパラメータをsysctlを用いて調整することができます。

# sysctl -w kern.ipc.semmni=100

これらの設定を再起動しても永続化するには、/etc/sysctl.confを変更します。

shared_memory_typesysvに設定している場合は、System V共有メモリをRAM上に固定して、スワップによってページアウトされるのを避けるために、カーネルを設定することもできます。 これはsysctlを使用してkern.ipc.shm_use_physを設定することで実現できます。

OpenBSD

shared_memory_typesysvに設定していない限り、通常はデフォルトの共有メモリ設定で十分です。 通常は、kern.seminfo.semmnikern.seminfo.semmnsを増やす必要があります。これは、OpenBSDのデフォルト設定は不適切に小さいためです。

以下の例のようにIPCパラメータをsysctlを用いて調整することができます。

# sysctl kern.seminfo.semmni=100

これらの設定を再起動しても永続化するには、/etc/sysctl.confを変更します。

Linux

shared_memory_typesysvに設定していて、低いデフォルトで出荷されたより古いカーネルバージョンでない限り、通常はデフォルトの共有メモリ設定で十分です。 System V セマフォはこのプラットフォームでは使用しません。

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

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

これらの設定を再起動しても永続化するには、/etc/sysctl.confを参照してください。

macOS

shared_memory_typesysvに設定していない限り、通常はデフォルトの共有メモリとセマフォ設定で十分です。

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

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

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

SHMMAXは4096の倍数のみ設定できます。

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

SHMMNI以外の変更は、sysctlを用いることにより、その場でおこなうことができます。 しかしいずれにせよ/etc/sysctl.conf経由で望む値に設定することが最善です。 再起動を行っても値が保持されるからです。

Solaris
illumos

大抵の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を再起動した時(再読み込み時ではありません)に有効になります。 上ではPostgreSQLpostgresグループに属するpostgresユーザにより実行されていることを前提としています。 サーバの再起動は不要です。

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

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

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

19.4.2. systemd RemoveIPC #

systemdが使用されている場合、(共有メモリを含む)IPCリソースがオペレーティングシステムによって時期尚早に削除されないように注意する必要があります。 これはPostgreSQLをソースからインストールした場合に特に重要です。 PostgreSQLのディストリビューションパッケージのユーザーは、通常postgresユーザーがシステムユーザーで作成されるため、影響を受けにくいでしょう。

logind.confRemoveIPCの設定はユーザが完全にログアウトしたときにIPCオブジェクトを削除するかどうかを制御します。 システムユーザは免除されます。 この設定のデフォルトはsystemdですが、いくつかのオペレーティングシステムではデフォルトでオフになっています。

この設定が有効になっている時の典型的な影響は、並列問い合わせの実行で使われる共有メモリオブジェクトが見かけ上ランダムな時間に削除され、共有メモリオブジェクトをオープンしようとしたり、削除しようとしたりした時に以下のようなエラーや警告が出ることです。

WARNING:  could not remove shared memory segment "/PostgreSQL.1450751626": No such file or directory

IPCオブジェクトの違い(共有メモリ vs. セマフォ、System V vs. POSIX)はsystemdによって若干扱いが異なるため一部のIPCは他のものと違って削除されないことがあります。 しかし、これらの微妙な違いに依存することはお勧めできません。

ユーザーログアウトは、メンテナンスジョブの一環として、又は手動で、管理者がpostgresユーザーや類似のユーザでログインする可能性があるため、一般的に防止することは困難です。

システムユーザーは、/etc/login.defsSYS_UID_MAXの設定によりsystemdのコンパイル時に決定されます。

パッケージとデプロイスクリプトは、useradd -r, adduser --system又は同等のコマンドを使用してpostgresユーザを作成するように注意する必要があります。

また、ユーザアカウントが誤って作成されて変更出来ないような場合は、以下を設定することを推奨します。

RemoveIPC=no

/etc/systemd/logind.conf又はその他の設定ファイルで上記を入れます。

注意

これらの2つのうち少なくとも1つが保証されてないとなりません。そうでないとPostgreSQLサーバは非常に信頼性が低くなります。

19.4.3. リソースの制限 #

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

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

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

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

  • Linuxカーネルパラメータfs.file-maxは、カーネルがサポートするオープンファイルの最大数を決定します。 これはsysctl-w fs.file-max=Nで変更できます。 再起動後もこの設定を保持するには、/etc/sysctl.confに割り当てを追加します。 プロセスあたりのファイル数の上限は、カーネルのコンパイル時に固定されます。 詳細は/usr/src/linux/Documentation/proc.txtを参照してください。

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

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

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

多数のクライアント接続をサポートする場合に懸念されるもう1つのカーネル制限は、ソケット接続キューの最大長です。 非常に短い時間内にそれ以上の数の接続要求が到着すると、PostgreSQLサーバが要求を処理する前に一部が拒否される可能性があります。 これらのクライアントはResource temporarily unavailableConnection refusedなどの役に立たない接続失敗エラーを受け取ります。 多くのプラットフォームでデフォルトのキュー長制限は128です。 これを上げるにはsysctlで適切なカーネルパラメータを調整し、PostgreSQLサーバを再起動します。 このパラメータはLinuxではnet.core.somaxconn、新しいFreeBSDではkern.ipc.soacceptqueue、macOSや他のBSD系ではkern.ipc.somaxconnと様々な名前が付けられています。

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

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

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

Out of Memory: Killed process 12345 (postgres).

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

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

PostgreSQL自体が実行中のシステムのメモリ不足を引き起こした場合、設定を変更することで問題を防止することができます。 場合によっては、メモリ関連の設定パラメータ、shared_bufferswork_memおよびhash_mem_multiplierを低くすることで回避できる場合もあります。 この他にもデータベースサーバ自体への接続を多く許可しすぎることで問題が引き起こされる場合もあります。 多くの場合、max_connectionsを減らし、外部のコネクションプールソフトウェアを使用することで改善されます。

メモリをオーバーコミットさせないようにカーネルの動作を変更することができます。 この設定は完全にOOM killerの発生を防ぐことはできませんが、その発生頻度をかなり軽減しますので、システム動作の堅牢性をより高めます。 これは、以下のようにsysctlを使用して厳密なオーバーコミットモードを選択することで実施されます。

sysctl -w vm.overcommit_memory=2

または/etc/sysctl.confに同等のエントリを配置します。 また、関連するvm.overcommit_ratio設定を変更した方が良いでしょう。 詳細はカーネル文書ファイルhttps://www.kernel.org/doc/Documentation/vm/overcommit-accountingを参照してください。

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

echo -1000 > /proc/self/oom_score_adj

この作業をrootで実行しなければならないことに注意して下さい。 さもないと効果がありません。 このためrootが所有する起動スクリプトが、これを行うための最も簡単な場所です。 その場合には、起動スクリプトのpostgresの起動前に以下の環境変数を設定することも推奨します。

export PG_OOM_ADJUST_FILE=/proc/self/oom_score_adj
export PG_OOM_ADJUST_VALUE=0

これらの設定は、いざという時にpostmasterの子プロセスをOOM killerのターゲットに出来るようにOOMスコア調整を通常のゼロで実行します。 子プロセスを他のOOMスコア調整で実行したい場合には、PG_OOM_ADJUST_VALUEにより別の値にすることが出来ます。 (PG_OOM_ADJUST_VALUEは省略することが出来て、その場合はデフォルトのゼロになります。) PG_OOM_ADJUST_FILEを設定しない場合、子プロセスはpostmasterと同じOOMスコア調整で実行されますが、postmasterが優先される設定にすることが肝心なので、それは賢明とは言えません。

19.4.5. LinuxのHugePages #

PostgreSQLのように、メモリの大きな連続チャンクを使用するとき、特にshared_buffersの値が大きい場合に、huge pagesを使用するとオーバーヘッドが減少します。 PostgreSQLでこの機能を有効にするには、CONFIG_HUGETLBFS=yおよびCONFIG_HUGETLB_PAGE=yとしたカーネルが必要です。 また、要求される十分な量だけhuge pagesを提供するようにオペレーティングシステムを調整する必要があるでしょう。 必要なhuge pages数を決定するには、postgresコマンドを起動してshared_memory_size_in_huge_pagesの値を調べます。 実行時に計算されたこのパラメータを見るためには、サーバを停止しなければならないことに注意してください。 これは以下のような感じになるでしょう。

$ postgres -D $PGDATA -C shared_memory_size_in_huge_pages
3170
$ grep ^Hugepagesize /proc/meminfo
Hugepagesize:       2048 kB
$ ls /sys/kernel/mm/hugepages
hugepages-1048576kB  hugepages-2048kB

この例ではデフォルトは2MBですが、明示的に2MBまたは1GBをhuge_page_sizeで要求して、shared_memory_size_in_huge_pagesで計算されたページ数を調整することもできます。 この例では少なくとも3170のhuge pageが必要ですが、マシン上の他のプログラムもhuge pageを必要とする場合には、より大きな設定が適切です。 これは以下のように設定できます。

# sysctl -w vm.nr_hugepages=3170

再起動後にこの設定が行われるように、/etc/sysctl.confにこの設定を追加するのを忘れないようにしましょう。 非標準のhuge pageサイズなら、代わりに以下のようにできます。

# echo 3170 > /sys/kernel/mm/hugepages/hugepages-2048kB/nr_hugepages

hugepagesz=2M hugepages=3170のようにして、起動時にカーネルパラメータとしてこれらの設定を与えることもできます。

時には、断片化のためにカーネルは求められた数のhuge pagesを直ちには割り当てることができないことがあるので、そのコマンドを繰り返すか、再起動する必要があるかもしれません。 (再起動の直後は、マシンのメモリの大部分はhuge pagesへの変更が可能なはずです。) 指定サイズに対するhuge pagesの割り当ての状況を確認するには、次のようにします。

$ cat /sys/kernel/mm/hugepages/hugepages-2048kB/nr_hugepages

sysctlを使ってvm.hugetlb_shm_groupを設定する、あるいはulimit -lでメモリをロックする権限を与えることで、データベースサーバのOSユーザにhuge pagesを使用する権限を与える必要もあるかもしれません。

PostgreSQLのhuge pagesのデフォルトの動作は、可能な場合はシステムのデフォルトサイズのhuge pagesを使用し、失敗した場合は通常のページを使用します。 postgresql.confhuge_pagesonに設定することで、huge pagesの使用を強制することができます。 この設定の場合、十分なhuge pagesが確保できなければ、PostgreSQLの起動に失敗することに注意してください。

Linuxのhuge pages機能の詳細はhttps://www.kernel.org/doc/Documentation/vm/hugetlbpage.txtを参照してください。