FreeBSDでportsでインストールしたPostgreSQL。デフォルトで、毎日、dailyによってvacuumdbが実行されるようになるんです。
ところで、あのスクリプト/usr/local/etc/periodic/daily/502.pgsqlって、いまいちなんです。vacuumdbに必ず-aオプションつけてるところが。これだと、変数daily_pgsql_vacuum_argsで、データベース名を指定することができないじゃないですか。
まあそれはいいとして、dailyのログメールで、ある日気がついたのですが、vacuumdbを実行したときに、
vacuuming of database "データベース名" failed: ERROR: out of memory DETAIL: Failed on request of size 573885600.
というようなエラーが出て、vacuumdbが失敗するようになってました。
まずいじゃん!ってことで、
vacuumdb --dbname データベース --verbose --analyze --table テーブル名
のように、テーブル名を1つずつ指定していき、どのテーブルでエラーが出るのか、調べてみたら、特定のテーブルでのみ、エラーが出ることがわかりました。
ネット検索して、いろいろ試しても、問題解決できなかったので、ソースコードを確認してみることに。
ktraceつきでvacuumdbを実行してみたら、
vacuumdb CALL recvfrom(0x3,0x8063000,0x4000,0,0,0)
vacuumdb GIO fd 3 read 101 bytes
"E\0\0\0dSERROR\0C53200\0Mout of memory\0DFailed on request of size 536\
870910.\0Faset.c\0L527\0RAllocSetAlloc\0\0"
という感じで、バックエンド(postgresプロセス。昔はpostmasterという名前だったアレ)から返ってきている、生のエラーメッセージのようなものが見えました。ここに、ソースファイルの名前、行番号、関数名のようなものが含まれているじゃないですか。
- aset.c
- L527
- AllocSetAlloc
aset.cというファイルは、./backend/utils/mmgrにありまして、
static void *
AllocSetAlloc(MemoryContext context, Size size)
という関数で、
chunk_size = MAXALIGN(size);
blksize = chunk_size + ALLOC_BLOCKHDRSZ + ALLOC_CHUNKHDRSZ;
block = (AllocBlock) malloc(blksize);
if (block == NULL)
{
MemoryContextStats(TopMemoryContext);
ereport(ERROR,
(errcode(ERRCODE_OUT_OF_MEMORY),
errmsg("out of memory"),
errdetail("Failed on request of size %lu.",
(unsigned long) size)));
という感じでになっているので、ここでmallocが失敗しているんでしょう。
というわけで、vacuumdbが出しているエラーではなく、バックエンド側で出しているエラーですね。
また
512*1024*1024 = 536870912
なので、536870910ってのは、512MBくらい。
こうなると、すぐにピンとくるのは
なんてもの。
もっとも、
なんてことがあったので、やみくもにkern.maxdsiz="2G"とかやっちゃっても、別のメモリがらみのエラーがでることもありました。
あぁ、アドレス空間が4GBまでしかない32bit OSは限界だな、なんていう感じもしてきます。
でも、FreeBSD/i386は、ちょっと、限界が低すぎじゃない?って気もします。
☆
ところで、limitで広げるのは、postgresqlプロセスのほうであり、vacuumdbにたくさんメモリを与えても、ダメっすね。
ところで、maxdsizで広げても、root権限じゃないと512MBを超えられなかったような気がするんですが、気のせい?
postgresqlって、pgsqlというユーザーで走ってますよね。
気軽にpostgresqlを再起動できない事情がありまして、今はまだ、あれこれ試すことができません。
☆
postgresql.confで、maintenance_work_mem = 512MB とか書いてあったんですが、これを増やしても、なんかダメ。
だいたい、vacuumdbがなぜそんなメモリを消費するのか、と。
あれ、vacuumdb --fullなら実行できました。なるほど、VACUUM ANALYZEがメモリ食いのもよう。
ということは、と思ってpgadmin3で、テーブルのサイズなど見てたら、テーブルのサイズはどうやら4GBをとうに超えてましたが、それよりも驚いたことに、インデックスのサイズが600MBを超えてました。
近頃は、psqlでvacuumを実行すると
データベース=> vacuum テーブル名;
ERROR: out of memory
DETAIL: Failed on request of size 609512400.
なんてことになってて、600MBくらいの値。
ひょっとして、こっち、インデックスのサイズか?!
そんな巨大なインテックスって、なんか効率が悪そう。そもそも、テーブルの設計が悪いんじゃないか?
という気がしてきまして、テーブルをいくつかに分割しようかと思います。
それでも、寿命を少しのばす程度かもしれません。
それまでの間に、FreeBSD/amd64が、もっと使いやすくなっているといいんですけど。
■ つづく
だとすると、むしろmaintenance_work_memは減らした方がいいんじゃないでしょうか。
返信削除あと、インデックスが巨大な場合はREINDEXしてやると良いと思います。
ありがとうございます。補足しておきました。
返信削除http://nhh.mo-blog.jp/ttt/2008/05/freebsd_postgre_e31a.html
なおインデックスの再構成ですが、変更よりも追記が圧倒的に多い性質のテーブルのためか、あまりインデックスのサイズは小さくなりませんでした。
だいたい、600MBが500MBに、程度でした。