mixi大規模障害について
こんにちは。システム本部技術部たんぽぽGの森本です
先日のmixi大規模障害についてのブログです。
はじめにお断りしておきますが、弊社CTOがtwitterで公開した以上の情報はまだ得られておりません。
twitterでは書ききれなかった細部を補足してみたいと思います
- memcachedに大量の接続・切断を行うとmemcachedプロセスが突然終了することがある
- memcachedには異常時に終了するフローもあるが、同時に出力されるはずのエラーログは出ていなかった
- coreも出力されていなかった
./memcached -vv -p 11222 -u nobody -m 16000 -c 40720 -C -U 0 -t 4 -b 4096クライアントマシンは 3 台 各クライアントでは 5000 個 fork、1 プロセスでは最大 50 個コネクション生成。最大に達すると 1 つコネクションを再生成し get 命令を 1 つ発行。専用クライアントライブラリでは無く、ソケットを直接操作 クライアントコードは以下
#!/usr/local/bin/activeperl use strict; use warnings; use IO::Socket::INET; my $host = shift; my $port = shift; foreach my $sig (keys %SIG){ next if($sig eq '__WARN__'); next if($sig eq '__DIE__'); next if($sig eq 'INT'); next if($sig eq 'TERM'); $SIG{$sig} = sub { my $sig = shift; print "Cought a sig[$sig]\n"; }; } for(1 .. 50*100){ foo(); } sleep 1 while(1); sub foo { fork && return; my @sock; for (;;) { if(50 < @sock){ my $nth = int(rand(@sock)); my $s = splice(@sock, $nth, 1); print $s "get foo\n"; my $ret = <$s>; close($s); next; } my $s = IO::Socket::INET->new(PeerAddr => $host, PeerPort => $port, Proto => 'tcp'); if ($s) { print $s "get foo\n"; my $ret = <$s>; print STDERR "."; push @sock, $s; } else { warn "XX [$$]Can't open port:[$!]\n"; if (@sock) { my $nth = int(rand(@sock)); my $s = splice(@sock, $nth, 1); print STDERR "close socket\n"; print $s "get foo\n"; my $ret = <$s>; close($s); } else { sleep 1; } } } }memcachedにいくつかdebug文を仕込んだところ、以下のことがわかりました。
- memcached.c:main()にある event_base_loop から抜けていた 通常はここで無限ループするはず
- event_base_loop()中の event_haveevents(base) が false を返していた
- event_haveevents()で base->event_count が0になったため return (base->event_count > 0); で false を返していた
5000プロセスとかなり負荷を掛けているつもりなのですが再現度はかなり低いです
もしかすると1台のクライアントで同時に行えるopen/closeはコア数が上限になってしまうなどの制限があるのでしょうか
引き続き確実な再現方法と原因究明に向けて調査を行っていきます