ひよっこ。

I want to…

Posts Tagged ‘setting’

PostgreSQLのSHMMAXの計算式の検証

Posted by hikaruworld : 2009 1月 8

SHMMAXの計算式の検証

PostgreSQL:8.2.4(特にカスタマイズせずにソースからインストール)
OS:RHEL4

※最近マイナーバージョンの差での問題にちょこちょこあたる(;-
今回も8.1系から8.2系で設定ファイル周りの記述が変更されているので注意。

上記でインストールした環境のデフォルト値からSHMMAX(/proc/sys/kernel/shmmax)の設定に必要な値の算出の検証を行う。

この辺りが詳しい。

※あくまで、PostgreSQLが必要とする共有メモリ。実際は当然その他のサービスのメモリを考慮する必要がある。
なお、ここでの検証はSHMMAXの値の算出を行うためであり、max_connectionsやshared_buffersの値の算出を導き出すためのものではない。
それはまたの機会に。。。

ところで、実は手っ取り早くSHMMAXの値を知るためにはとりあえずpg_ctlで起動してしまえばよい。
起動に失敗した場合は必要なサイズの詳細情報をPostgreSQLが教えてくれるからだ。

計算方法

表16-1より

大雑把には、必要とされるセグメントサイズは500キロバイト+上記表に記載された変数の量と見積もることができます。
(エラー時に表示されるメッセージには、割り当てに失敗したサイズが正確に記載されています。)
SHMMAXを1メガバイトとしてPostgreSQLを稼動させることができますが、受容できる性能を確保するためには少なくとも4メガバイト必要です。10メガバイト単位の設定を推奨します。

ドキュメントに書いてあるように、各値に対してここの計算式で値の算出を行う。
参考までにリンク先の式を張っておく。

名称 おおよその乗数(1増やした場合のバイト数)
max_connections 400 + 270 * max_locks_per_transaction
max_prepared_transactions 600 + 270 * max_locks_per_transaction
shared_buffers 8300 (BLCKSZが8Kであることが前提です。)
wal_buffers 8200 (XLOG_BLCKSZが8Kであることが前提です。)
max_fsm_relations 70
max_fsm_pages 6

算出方法

事前に(基本的には表の説明にもあるように8K)BLOCK_SIZEを確認しておく。
任意DBにログイン後、以下のSQLを実行する。

SHOW block_size

block_size
————
8192

max_connections

#max_connections = 100 # (change requires restart)

#max_locks_per_transaction = 64 # min 10 # (change requires restart)

  • 400 + 270 * 64(max_locks_per_transaction) = 17680
  • 100(max_connections) * 17680 = 1768000
max_prepared_transactions

#max_prepared_transactions = 5 # can be 0 or more

#max_locks_per_transaction = 64 # min 10
# (change requires restart)

  • 600 + 270 * 64(max_locks_per_transaction) = 17880
  • 5(max_prepared_transactions) * 17880 = 89400
shared_buffers

BLCKSZが8Kであることが前提です。

つまり、8KB辺りの増加量のため、8KB単位に乗算すると解釈。
なお、PostgreSQL8.2系からshared_buffersで設定する値が、ページ数(容量をブロックサイズで割ったもの)からByte数に変更されているとのこと。

shared_buffers = 24MB

  • 24(shared_buffers) * 1024 / 8(BLCKSZ) = 3072
  • 3072 * 8300 = 25497600
  • 24 * 1024 * 8300 = 203980800(????)
wal_buffers

XLOG_BLCKSZが8Kであることが前提です。

shared_buffers同様、8KB辺りの増加量。

wal_buffers = 64kB

  • 64(wal_buffers) / 8(XLOG_BLCKSZ) * 8200 = 65600
  • 64 * 8200 = 524800
max_fsm_relations

#max_fsm_relations = 1000 # min 100, ~70 bytes each
# (change requires restart)

  • 1000(’max_fsm_relations’) * 70 = 70000
max_fsm_pages

max_fsm_pages = 153600 # min max_fsm_relations*16, 6 bytes each
# (change requires restart)

  • 153600(max_fsm_pages) * 6 = 921600
合計値SHMMAXに必要な値の計算
  • 1768000+89400+25497600+65600+70000+921600+500*1024 = 28924200Byte
  • 28924200 / 1024 / 1024 = 27MB

実行時と計算値の検証

実際にPostgreSQLを起動し、占有する共有メモリの値をipcsで確認する。

ipcs -m

—— 共有メモリセグメント ——–
キー shmid 所有者 権限 バイト nattch 状態
0×00000002 65536 root 600 655360 2
0×00000000 196609 gdm 600 393216 2 対象
0×0052e2c1 262146 postgres 600 29237248 2

  • 29237248 / 1024 /1024 = 27M

多少誤差があるとしてもおおよその数字は計算結果と同じであることが確認できる。

OSのshmmaxの値

デフォルトの値は

cat /proc/sys/kernel/shmmax

でみてもわかるように、33554432Byteつまり32MBになっている。
ためしに、この値を小さめに設定(ここでは27Mを下回る値)にして、PostgreSQLの起動に失敗することを検証する。

[root@hoge]#echo 16777216 > /proc/sys/kernel/shmmax
[postgre@hoge]$pg_ctl start

すると、こんなエラーが発生する。

[postgres@hoge ~]$ FATAL: could not create shared memory segment: Invalid argument
DETAIL: Failed system call was shmget(key=5432001, size=29237248, 03600).
HINT: This error usually means that PostgreSQL’s request for a shared memory segment exceeded your kernel’s SHMMAX parameter. You can either reduce the request size or reconfigure the kernel with larger SHMMAX. To reduce the request size (currently 29237248 bytes), reduce PostgreSQL’s shared_buffers parameter (currently 3072) and/or its max_connections parameter (currently 100).
If the request size is already small, it’s possible that it is less than your kernel’s SHMMIN parameter, in which case raising the request size or reconfiguring SHMMIN is called for.
The PostgreSQL documentation contains more information about shared memory configuration.

DETAIL にも書いてあるように、29237248Byte確保できずに起動に失敗したと表示される。

Failed system call was shmget(key=5432001, size=29237248, 03600).

ふぅ。疲れた。

Posted in OS, server | タグ: , , | 2 Comments »

エフェメラルポートのバッティング

Posted by hikaruworld : 2008 11月 13

RHEL4上で起動しているTomcatをデフォルトの8080ポートで起動しようとしたら、唐突に以下のエラーで落ちた。

致命的: エンドポイントを初期化中のエラーです
java.net.BindException: Address already in use: JVM_Bind:8080

エラー自体は別段珍しいものではない。Tomcatのプロセスがつかみっぱなしになっているんだろう。
ただ昨日まで起動していたものが、突然起動しなくなるとはどういうことだと思いつつ、
とりあえずnetstatしてみる。

netstat -n –tcp | grep IPアドレス

必要な箇所だけ抜粋。
確かに使っているようだ。でも5432というと。。。

tcp 0 0 10.131.229.25:5432 10.131.229.25:8080 ESTABLISHED

続いて、lsof

lsof -i:8080

またまた、該当箇所のみ

COMMAND PID USER FD TYPE DEVICE SIZE NODE NAME
java 19463 root 18u IPv6 3159971 TCP hostname:8080->hostname:postgres (ESTABLISHED)

…変なものが見える。
PostgreSQLとのコネクションを張るのに8080を使っているようだ。

Tomcat上のアプリとDB間はパフォーマンスを考慮して、コネクションプーリングを持ちいているので、
Tomcat起動時にアプリ⇔DB間で、複数コネクションを複数のTCP接続で確立させ、
その際にコネクション分のポートがPostgreSQLによって確保されるわけだ。
おそらくこの際のポートの確保は、OSで設定されているエフェメラルポートから適当に割り振られるようだ。

PostgreSQLのエフェメラルポートの割り当てがどのように行われるかわからないが(挙動的にインクリメントっぽい)、
このコネクション確立時のポート確保とアプリケーションの起動ポートがバッティングする可能性があるようだ。

# この理解であっているのかな?あとで図でも書いてみるか。。

色々検索してみたが、サーバ構築時にエフェメラルポートの設定を考慮する必要があるのは周知の事実らしい。
すみません、存在すら全く知りませんでした。

RHEL4の場合は、以下のように設定すれば任意にエフェメラルポートを設定可能なようなので、
/etc/sysctl.confnet.ipv4.ip_local_port_rangeを以下のように追記した(要再起動)。

net.ipv4.ip_local_port_range = 20000 61000

上限値はメモリに依存するらしい。
なお、RHEL4のデフォルト設定は1024-65000(最大値は忘れた、確かこのあたりだった気がする)らしいが
この件に関するRHELのドキュメントが見つけられなかった。

探し方が悪い???
とりあえず検証してみて期待通りの動作をしているところまでは確認したが、気になるところである。

P.S
次のエントリーで書くが、このバグはコネクションプーリングのdestory漏れという、
あほなミスと重複して発生頻度が上がっていたようだ。(汗

参考リンク:

Posted in OS, Uncategorized | タグ: , , | Leave a Comment »