[pgsql-jp: 35382] Re: 太る pgpool
Tatsuo Ishii
t-ishii @ sra.co.jp
2005年 5月 14日 (土) 09:17:56 JST
石井です.
pgsql-jpが復旧したのでそちらにもCc:します.
> 鹿持@メダカカレッジです。
>
> 直メールでごめんなさい。
> pgsql-jp が止まっているようなので。。。
>
> 引用を前後させています。
>
> At Sat, 07 May 2005 20:57:34 +0900 (JST),
> Tatsuo Ishii wrote:
>
> > > で、これを見ていて気付いたのが1点。
> > > pid 3626 のものが親だと思うんですが、こいつがやたらとメモリを喰ってます。
> > > あれれ、と思ってソースを見ると、pool_error.c の 100行目過ぎにある
> > > pool_log() の中で asprintf() を使ったあと、 free() をしてないですね。
> > > health_check を1秒ごとにする設定にしていたので、"starting health checking" が
> > > 毎秒ごとに出るんですが、これが毎度リークして太ってるんじゃないかと思います。
> > ご指摘の通りでした.
> >
> > > # あと main.c の l.247 で
> > > # pids = malloc(pool_config.num_init_children * sizeof(pool_config.num_init_children));
> > > # とあるのは
> > > # pids = malloc(pool_config.num_init_children * sizeof(pid_t));
> > > # が正しい?
> > はい,こちらもそうですね(そのすぐ後ろにも同じような間違いがあります).
>
> cvs から新しい mail.c と pool_error.c をいただいてきて、leak の修正を
> 確認しました。
> ありがとうございました。
>
> で、ゾンビの件ですが、
>
> > > pgpool 2.5.2 を replication_mode = true で運用し、2台の PostgreSQL に対して
> > > クエリを投げるようにしているサーバで、あるときアプリから接続ができなくなる
> > > ということがありました。
> > > pgpool への接続がだめで、PostgreSQL への直接接続は大丈夫でした。
> > > killall -9 で pgpool を殺して、再起動したところ無事復旧。
> > >
> > > さて、この障害が起きていたときの ps auxw | grep pgpool を見ると
> > > 以下の感じでした。
> > > (ちょっと横に長くてごめんなさい)
> > [snip]
> > > なんかやたらとゾンビがいます。(^^;
> > > num_init_children は 150 にしているのですが、数えたら 101 がゾンビに
> > > なってました。なんでじゃ。。。
> > これはちょっとわかりませんが...
>
> ふと気付いて syslog を見ると、毎秒の health check のログが途中で止まってました。
>
> - あるところで親 pgpool が刺さる
> - 子 pgpool が child_life_time 以上アイドル状態が続き、自害する
> - しかし wait() してくれる親がいないため、ゾンビになる
>
> というシナリオかしら、と。
>
> しかしどこで刺さってるかソースからだけで考えるのはしんどいので、
> 再現しないかなぁと待っていたのですが、今朝再現してくれたので、
> 親 pgpool を gdb で attach。backtrace をとりました。
>
> | (gdb) where
> | #0 0xb75ebc32 in _dl_sysinfo_int80 () from /lib/ld-linux.so.2
> | #1 0xb7540c76 in __lll_mutex_lock_wait () from /lib/tls/libc.so.6
> | #2 0xb758d660 in run_fp () from /lib/tls/libc.so.6
> | #3 0xb758cd98 in __DTOR_END__ () from /lib/tls/libc.so.6
> | #4 0xb758d660 in run_fp () from /lib/tls/libc.so.6
> | #5 0xb74cd194 in _L_mutex_lock_10108 () from /lib/tls/libc.so.6
>
> 。。。
> なんか終わろうとしてそうですが、これでは何がなんだかわからない。
> スタックからそれっぽい番地を拾っていくと fork_a_child を見つけました。
>
> | (gdb) x/10i fork_a_child
> | 0x8049ea4 <fork_a_child>: push %ebp
> | 0x8049ea5 <fork_a_child+1>: mov %esp,%ebp
> | 0x8049ea7 <fork_a_child+3>: push %ebx
> | 0x8049ea8 <fork_a_child+4>: push %eax
> | 0x8049ea9 <fork_a_child+5>: call 0x8049008
> | 0x8049eae <fork_a_child+10>: test %eax,%eax
> | 0x8049eb0 <fork_a_child+12>: mov %eax,%ebx
> | 0x8049eb2 <fork_a_child+14>: je 0x8049ef0 <fork_a_child+76>
> | 0x8049eb4 <fork_a_child+16>: cmp $0xffffffff,%eax
> | 0x8049eb7 <fork_a_child+19>: je 0x8049ec0 <fork_a_child+28>
> |
> | (gdb) x/10i 0x8049008
> | 0x8049008: jmp *0x8059468
> | 0x804900e: push $0x60
> | 0x8049013: jmp 0x8048f38
> | 0x8049018: jmp *0x805946c
> | 0x804901e: push $0x68
> | 0x8049023: jmp 0x8048f38
> | 0x8049028: jmp *0x8059470
> | 0x804902e: push $0x70
> | 0x8049033: jmp 0x8048f38
> | 0x8049038: jmp *0x8059474
> |
> | (gdb) x/1x 0x8059468
> | 0x8059468 <_GLOBAL_OFFSET_TABLE_+60>: 0xb7501060
> |
> | (gdb) x/10i 0xb7501060
> | 0xb7501060 <fork>: push %ebp
> | 0xb7501061 <fork+1>: mov %esp,%ebp
> | 0xb7501063 <fork+3>: push %edi
> | 0xb7501064 <fork+4>: push %esi
> | 0xb7501065 <fork+5>: push %ebx
> | 0xb7501066 <fork+6>: call 0xb746e57d <__i686.get_pc_thunk.bx>
> | 0xb750106b <fork+11>: add $0x8bd2d,%ebx
> | 0xb7501071 <fork+17>: sub $0x2c,%esp
> | 0xb7501074 <fork+20>: movl $0x0,0xffffffdc(%ebp)
> | 0xb750107b <fork+27>: mov 0x1a4(%ebx),%eax
>
> 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を動かしているときに,起
動するタイミングを探すのがちょっと微妙ではありますが.
--
Tatsuo Ishii
> # 「signal handler から」の fork() が犯人かどうか確定ではないですが。
>
>
> ● from: KAJI Wataru <waasuke @ medaka-college.com>
> ● 鹿持 渉 @ メダカカレッジ
> ● http://www.medaka-college.com/
>
pgsql-jp メーリングリストの案内