Postgresに新しい調整を適用したいバグを追跡しています。
正確なエラーは次のとおりです。
2018-11-07 22:14:49 EST [7099]: [1-1] FATAL: could not map anonymous shared memory: Cannot allocate memory
2018-11-07 22:14:49 EST [7099]: [2-1] HINT: This error usually means that PostgreSQL's request for a shared memory segment exceeded available memory, swap space, or huge pages. To reduce the request size (currently 35301089280 bytes), reduce PostgreSQL's shared memory usage, perhaps by reducing shared_buffers or max_connections.
私はこのエラーに精通しています。 Postgresのさまざまなインスタンスを調整することは、私と一緒に働くエンジニアの毎月の仕事です。解決策はPostgres調整やshmall
などの管理設定をロールバックすることですulimit
。
この場合、私たちは他の人が作成したpostgresインストールを適用しており、何年も実行してアップグレードしながらいくつかの欠陥があります。このインストールはCentOS 5のインストールから始まり、現在CentOS 7にインストールされています。 CentOS 5の以前のSysVインストールには、次のようなさまざまなメモリ制限制御が適用されました。
/etc/sysconfig/postgresql.d/ulimit.sh
/etc/sysconfig/postgresql.d/memory-cap
shmmax
と設定は非常に保守的です。shmall
- 構成ファイルを変更して意図的に特定の値を強制する他のベンダーまたはシステム管理者のスクリプト
/etc/sysctl.conf
CentOS 5からCentOS 7にアップグレードした後、SysVからSystemDに変更したときに適用されるメモリ制限に関する追加の制御機能があるようです。
たとえば、次のようにsystemctl cat postgresql.service
表示されます。
# /usr/lib/systemd/system/postgresql.service
[Unit]
Description=PostgreSQL database server
After=network.target
[Service]
Type=forking
User=postgres
Group=postgres
Environment=PGPORT=5432
Environment=PGDATA=/opt/pgsql/data
OOMScoreAdjust=-1000
LimitSTACK=16384
ExecStart=/opt/pgsql/bin/pg_ctl start -D ${PGDATA} -s -o "-p ${PGPORT}" -w -l ${PGDATA}/serverlog
ExecStop=/opt/pgsql/bin/pg_ctl stop -D ${PGDATA} -s -m fast
ExecReload=/opt/pgsql/bin/pg_ctl reload -D ${PGDATA} -s
TimeoutSec=300
[Install]
WantedBy=multi-user.target
# /etc/systemd/system/postgresql.service.d/memory-cap.conf
#
# THIS FILE IS AUTO-GENERATED by /opt/pgsql/bin/tune.sh
# DO NOT MODIFY, it will be overwritten on next postgres startup.
# If you need to make a change, then disable the tuner:
#
# ln -s /dev/null /etc/systemd/system/postgresql.service.d/tune.conf
#
[Service]
LimitAS=12884901888
# /etc/systemd/system/postgresql.service.d/tune.conf
# /usr/lib/systemd/system/postgresql.service.d/use-system-timezone.conf
# Disable automatically setting the timezone by masking this drop-in file:
# ln -s /dev/null /etc/systemd/system/postgresql.service.d/use-system-timezone.conf
# Then you need to:
# systemctl daemon-reload
[Service]
ExecStartPre=/opt/pgsql/bin/use-system-timezone.sh
さて、実際の質問に戻ります。カーネル設定、ユーザー固有の制限、およびサービス構成には明らかに複数の層があり、各層は、、、およびshmmax
関連shmall
設定にulimit
制限を加えることができます。SystemD サービスの開始時に実際に適用される制限を構成またはランタイムでどのように確認できますか?
実行時に制限が何であるかを確認できる場合は、grep
ファイルとスクリプトの構成を開始して、その制限が設定されている場所を見つけることができます。この値を見つけたら、必要に応じて値を設定できます。 SystemDまたは私のpostgresプロセスがサービスとして起動したときに明白な設定を登録解除するようにするフラグがあったらと思います。
これらの値を設定する方法に満足しています。これらの値を強制またはオーバーライドできるレイヤが多すぎます。どの設定位置に触れるべきかを知りたいです。
私が見るには、LimitFOO
値が、sysctl -w kernel.shmfoo
と他のSystemD設定と同じ状況に直面する可能性があります/etc/someconfig/serviceuser/limit.foo
。実行中のサービスを調整するために正しく変更および設定できるように、実際に使用または適用される制限を確認する必要があります。
答え1
あなたの質問で指摘したように、ゲームにはいくつかの制限があります。
- System V IPC
shmall
などshmmax
- これRLIMIT個(しばしば
ulimit
シェルのコマンドで設定して確認するので、その名前で知ることもできます。) - cgroup制限(あなたの場合は特にメモリcgroup)は、最新のカーネルのプロセスグループに制限を適用する新しい方法です。
systemdは、特に制限と請求のための基本的なメカニズムとしてcgroupを使用して、後者の2つを管理します。 System V IPC には少し制限されたサポートがありますが、実際には制限ではありません。
これら3つの個々の概念を分析し、systemdに関して各概念の制限を調べて調整する方法を見てみましょう。
システムV産業用コンピュータ
systemdはSystem V IPCを少しサポートしています(例:サービス中断時のIPCクリーンアップ、独自のIPC名前空間でサービスを実行するまたは/tmp
個々のサービスのプライベートtmpfsのインストール(shmでサポート))、しかし、ほとんどの場合、System V IPC制限をさらに管理したり、会計処理を実行したりしません。
したがって、System V IPC の制限は完全に管理されるため、sysctl
次のコマンドを使用してこれらの制限を確認できます。
$ sysctl kernel.shmmax kernel.shmall kernel.shmmni
kernel.shmmax = 18446744073692774399
kernel.shmall = 18446744073692774399
kernel.shmmni = 4096
に調整してくださいsysctl -w
。
systemdには次のものが含まれているため、これらの制限設定にのみ関与しています。systemd-sysctl.service/etc/sysctl.conf
とから来る項目を設定する役割を担います/etc/sysctl.d/*.conf
。しかし、それ以上に、sysctl
これらの制限に関する直接的なカーネル情報を提供します。
RLIMIT(限界)
これらの制限はプロセスごとに設定され、子プロセスに継承されます。したがって、通常はプロセスツリー全体で同じですが、必ずしもそうではありません。
systemdを使用すると、サービス固有の設定では、サービスの開始時に設定されたとおりに制限を設定できます。
LimitSTACK=
これはあなたLimitAS=
の質問ですでに述べたようなディレクティブで構成されています。 RLIMITの完全なリストを見ることができます。systemd のマニュアルページからこれはまた、それを使い慣れたコマンドにulimit
関連付けます。
systemctl show
systemdからデバイスの内部状態をダンプするこのコマンドを使用して、実行中のデバイスの現在の制限を確認できます。
たとえば、
$ systemctl show postgresql.service | grep ^Limit
LimitSTACK=16384
LimitSTACKSoft=16384
LimitAS=12884901888
LimitASSoft=12884901888
... (other RLIMITs omitted for terseness) ...
カーネルが考える限界が何であるかを確認することもできます。/proc/$pid/limits
(これらの制限はプロセスごとに適用されるため、個々のPIDを調べる必要があることに注意してください。)
たとえば、
$ cat /proc/12345/limits
Limit Soft Limit Hard Limit Units
Max stack size 16384 16384 bytes
Max address space 12884901888 12884901888 bytes
... (other RLIMITs omitted for terseness) ...
cgroup (メモリ cgroup)
最後に、cgroupは、サービス管理、制限の提供、および会計のためのsystemdの基本的なメカニズムです。
systemdで利用可能でサポートされているcgroup(CPU、メモリ、IO、タスクなど)がたくさんありますが、この議論ではメモリcgroupに焦点を当てます(あなたの質問に関する制限事項なので、SysV IPCを見ました) 。 RLIMITにも対応するメモリ制限があります。
RLIMITと同様に、systemctl show
cgroupを使用してsystemdによって提供されるメモリ統計を表示することもできます。
$ systemctl show postgresql.service | grep ^Memory
MemoryCurrent=631328768
MemoryAccounting=yes
MemoryLow=0
MemoryHigh=infinity
MemoryMax=infinity
MemorySwapMax=infinity
MemoryLimit=infinity
MemoryDenyWriteExecute=yes
メモリ計算が有効になっているが()制限が設定されていないことがわかりますMemoryAccounting=yes
(すべてに設定されていますinifinity
)。制限リストは、システムとカーネルのバージョンによって異なる場合があります。これはカーネル 4.20-rc0 のシステム 239 で、「低」があります。 「、「高」、「最大」、「制限」、および交換のための別々の制限があります。
MemoryCurrent=
もう一つの興味深い点は、この値を使用すると、サービスがどのくらいのメモリを使用しているかを知ることができることです。これはカーネルcgroup情報から取得され、サービスのメモリ使用量に関する最新の測定値です。
systemctl status
サービスを使用すると、次の情報も表示できます。
$ systemctl status postgresql.service
● postgresql.service - PostgreSQL database server
Loaded: loaded (/usr/lib/systemd/system/postgresql.service; enabled; vendor preset: disabled)
Main PID: 12345 (postgresql)
Tasks: 10 (limit: 4321)
Memory: 602M
CGroup: /system.slice/postgresql.service
└─12345 /usr/lib/postgresql/postgresql
ご覧のとおり、systemdはMemory: 602M
cgroup情報から取得したメモリ使用量()を報告します。また、ジョブアカウントが(対応するcgroupを介して)有効になっており、4321の最大ジョブ制限のうち、10のジョブが現在サービスを使用していることを報告していることがわかります。
ステータス出力には、サービス名を付けたデフォルトのcgroupに関する情報も含まれています(各サービスは独自のcgroupで実行されます)、これをカーネルから直接cgroupの制限とアカウント情報を確認するために使用できます。
たとえば、
$ cd /sys/fs/cgroup/memory/system.slice/postgresql.service/
$ cat memory.limit_in_bytes
9223372036854771712
$ cat memory.usage_in_bytes
631328768
(数字 9223372036854771712 は2^63 - 4096
、この場合にはinfinity
64 ビットカウンタです。)
あなたは見ることができますメモリcgroupのカーネルドキュメントこれらの制限とカウンターの詳細です。カーネルには2つのバージョンのcgroup(cgroup-v1とcgroup-v2)があるため、システムでcgroup-v2を使用している場合は、システムにいくつかの重要な違いがあります。 systemdは両方(両方を使用するハイブリッドモデルも含む)をサポートしているため、systemctl
クエリ制限とカウンタはカーネルで有効になっているcgroupバージョンに関係なく一貫したビューを提供する必要があります。