[pgsql-jp: 38512] pgpoolがささり、子プロセスがゾンビになる現象が発生

TAKAO Kouji kouji @ netlab.jp
2007年 6月 19日 (火) 23:28:05 JST


高尾です。

pgpool-3.1.2をDebian GNU/Linux sargeで使用しています。
ある程度pgpoolを動かし続けていると、pgpoolのプロセスがささり、未接続の
pgpoolの子プロセスがゾンビ状態になる現象が発生しています。3日で発生す
ることもあれば、1ヶ月なこともあり、とりあえず、1日1回pgpoolを再起動さ
せるようにして、その場をしのいでいます。

それで、pgpoolがささったときにgdbでアタッチしてバックトレースを確認しました。
それが以下です。

----- ここから -----
Using host libthread_db library "/lib/tls/libthread_db.so.1".
`system-supplied DSO at 0xffffe000' has disappeared; keeping its symbols.
0x4014a321 in pthread_setcanceltype () from /lib/tls/libc.so.6
#0  0x4014a321 in pthread_setcanceltype () from /lib/tls/libc.so.6
#1  0x4010fc82 in fork () from /lib/tls/libc.so.6
#2  0x0804a1ce in fork_a_child (unix_fd=-4, inet_fd=-4) at main.c:515
#3  0x0804ad78 in reap_handler (sig=17) at main.c:989
#4  <signal handler called>
#5  0x400d8bd6 in mallopt () from /lib/tls/libc.so.6
#6  0x400d7c43 in malloc () from /lib/tls/libc.so.6
#7  0x400c710f in fgets () from /lib/tls/libc.so.6
#8  0x400c71cf in fopen () from /lib/tls/libc.so.6
#9  0x401a4d25 in _nss_files_gethostbyaddr_r () from /lib/tls/libnss_files.so.2
#10 0x401a4297 in _nss_files_gethostbyname_r () from /lib/tls/libnss_files.so.2
#11 0x4015119f in gethostbyname_r () from /lib/tls/libc.so.6
#12 0x40150a96 in gethostbyname () from /lib/tls/libc.so.6
#13 0x080567ca in connect_inet_domain_socket (secondary_backend=1)
    at pool_connection_pool.c:340
#14 0x0804c3ac in health_check () at child.c:1100
#15 0x080499eb in main (argc=2, argv=0xbfffef64) at main.c:313
----- ここまで -----

上記を元に、シグナルハンドラの中で、forkしている可能性があると思い、ソー
スコードを確認しました。すると、main.cにSIGCHLDのシグナルハンドラで
forkしていることが分かりました。

----- ここから -----
...
    pool_signal(SIGCHLD, reap_handler);
...
static RETSIGTYPE reap_handler(int sig)
{
...
    /* if found, fork a new child */
    if (!switching && !exiting && status)
    {
        pids[i] = fork_a_child(unix_fd, inet_fd);
        pool_debug("fork a new child pid %d", pids[i]);
        break;
    }
...
}
----- ここまで -----

今回、私の環境で発生したpgpoolがささり、子プロセスがゾンビになる現象は、
シグナルハンドラ中でforkしていることが原因ではないかと想像しています。

過去のMLでは、次のようなものがありました。

----- ここから -----
Subject: [pgsql-jp: 35382] Re: 太る pgpool
2005年 5月 14日 (土) 09:17:56 JST
http://ml.postgresql.jp/pipermail/pgsql-jp/2005-May/018942.html

> main -> reap_handler -> fork_a_child -> fork -> __i686.get_pc_thunk という
> 経路で来て、そこで固まっているようです。
> 
> fork() を signal handler の中から呼んでますが、これがまずいということは
> ないでしょうか。

「signal handlerの中ではなるべく余計なことをするな」ということは教訓と
して良く言われるのですが,fork()がタブーなのかはよくわかりません.もう
ちょっと調べてみようと思いますが...

> そして、子 pgpool の看取りは waitpid(WNOHANG) でやっていますし、
> 子の再起動のための fork_a_child(reap_handler)を signal handler から
> 呼ぶのではなく、main() のメインループの中から定期的にキックするようにする、
> というアイディアもあると思うんですがいかがでしょう?

とりあえずこちらの方向で検討します.heal checkを動かしているときに,起
動するタイミングを探すのがちょっと微妙ではありますが.
----- ここまで -----

上記はかなり前の話しなので、修正されているのかなと思っていましたが、
ソースコードを確認したところ、現在も同様の状態だと考えています。
「main() のメインループの中から定期的にキックするようにする」というの
は、どうなのでしょうか。何か難しい点や、問題などがあったのでしょうか。

---
株式会社ネットワーク応用通信研究所 研究員 高尾 宏治
〒690-0826 島根県松江市学園南二丁目12番5号
           HOYOパークサイドビル・2F
TEL:0852-28-9280 FAX:0852-28-9281
URL:http://www.netlab.jp/
e-mail:kouji @ netlab.jp



pgsql-jp メーリングリストの案内