偶数月なので、WEB+DB PRESSの季節です

WEB+DB PRESSで連載させて頂いている「大規模Webサービスの裏側」はVol.55にて第六回となり、最終回です。最終回は「監視」です。

「監視」の切り口を死活監視とリソース監視にわけて紹介し、後半はNagiosの設定や、Nagosの分散構成の解説です。Nagiosの分散構成はあまり資料がないので、(必要かどうかはおいておいて)面白いんじゃないかと思います。 同じVol. 55には宮川さんによるPSGI/Plackの記事もあるので、楽しみです。


昨日のデブサミ2010でRedHatの平さんとVmwareの各務さんの仮想化インフラのセッションでもでてきましたが、ハードウェアを知ることがその上で動くさまざまなソフトウェアを構築・運用していく上でも大事です。そのハードウェアを知るためにも監視を行い、リソースの利用のされかたを知るというのが重要だと思います。監視を楽に行えるよう様々なソフトウェアがあるので、どんどん活用して行きたいものです。

最終回となりますので、1年間のご愛読(まだ出てない)ありがとうございました! 1年間連載できたことがいい経験になり、記事を書くことでより深く技術を理解できたことも非常によい体験になりました。それから、執筆に協力いただいた、吉野君、加藤幹生さん、木村さん、藤沢さん、あと校正手伝ってくれたたんぽぽおよび、運用グループの方、奥さんありがとうございました。

また、何か記事の内容について詳しく聞きたいとか、「ここはどうやっているの?」とか質問がありましたら、メールなどで頂けたらと思います。ブログ等どこかで紹介していこうと思います。

PlackやAnyEventなどなど新しめのモジュールを使いたいんだけど、既存モジュールのrpmを作っていくのが面倒な場合に、それらのモジュール群をlocal::libを使ってまとめてどこかにディレクトリに入れるバンドルパッケージRPMができないかと考えてやってみた。

んで、できたので、specファイルをさらしてみる

Summary:        bundle package of Plack+AnyEvent
Name:           perl-bundle-plack
Version:        0.3
Release:        1%{?dist}
License:        Artistic
Group:          Development/Libraries
Source:         http://search.cpan.org/CPAN/authors/id/A/AP/APEIRON/local-lib-1.004009.tar.gz
Patch10:        local-lib-1.004009_destdir.patch 
BuildRoot:      %{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n)
BuildRequires:       perl(YAML)
BuildRequires:       perl(Config)
BuildRequires:       perl(File::Path)
BuildRequires:       perl(FindBin)
BuildRequires:       perl(ExtUtils::MakeMaker)
BuildRequires:       perl(ExtUtils::Install)
BuildRequires:       perl(ExtUtils::CBuilder)
BuildRequires:       perl(ExtUtils::ParseXS)
BuildRequires:       perl(Module::Build) >= 0.28
BuildRequires:       perl(CPAN)
AutoProv: no

%define buildhome %{_tmppath}/%{name}-%{version}-%{release}-home-%(%{__id_u} -n)
%define bundle_prefix /usr/local/bundle-plack
%define __perl_requires /usr/lib/rpm/perl.req --ignore_deps 'perl(Plack)'

%description
bundle package of Plack+AnyEvent

%prep
%setup -n local-lib-1.004009
%patch10 -p1

%build
[ "%buildroot" != "/" ] && rm -rf %buildroot
[ "%{buildhome}" != "/" ] && rm -rf %{buildhome}
export HOME=%{buildhome}
%{__mkdir_p} %{buildroot}%{bundle_prefix}
%{__mkdir_p} %{buildhome}/.cpan/CPAN

cat <<EOF > %{buildhome}/.cpan/CPAN/MyConfig.pm
\$CPAN::Config = {
  'urllist' => [q[ftp://ftp.jaist.ac.jp/pub/CPAN/], q[ftp://ftp.riken.jp/lang/CPAN/]],
};
1;
__END__
EOF

perl -Ilib Makefile.PL  --bootstrap=%{buildroot}%{bundle_prefix}
make
make install
rm -rf %{buildroot}%{bundle_prefix}/.modulebuildrc

%install
export HOME=%{buildhome}
export ORIGINAL_PREFIX=%{bundle_prefix}
export DESTDIR=%{buildroot}
sed -i "s/'urllist' => \[\],/'urllist' => [q[ftp:\/\/ftp.jaist.ac.jp\/pub\/CPAN\/], q[ftp:\/\/ftp.nara.wide.ad.jp\/pub\/CPAN\/], q[ftp:\/\/ftp.riken.jp\/lang\/CPAN\/]],/" %{buildhome}/.cpan/CPAN/MyConfig.pm

perl -I%{buildroot}%{bundle_prefix}/lib/perl5 -Mlocal::lib=--self-contained,%{buildroot}%{bundle_prefix} -MCPAN -e '
$ENV{PERL_MM_OPT} .= " INSTALLMAN1DIR=none INSTALLMAN3DIR=none";
$ENV{PERL_MM_USE_DEFAULT} = 1;
for my $m (qw/EV IO::AIO AnyEvent AnyEvent::AIO Coro 
              HTTP::Parser::XS Plack Plack::Request Plack::Server::AnyEvent/){
    CPAN::Shell->rematein("notest", "install", $m);
}
'
#↑にいれるモジュールを書く

find %{buildroot}%{bundle_prefix} -name *.so -type f | xargs -I{} sed -i "s@%{buildroot}@@g"  {}
sed -i "s@%{buildroot}@@g" %{buildroot}%{bundle_prefix}/.modulebuildrc

find %{buildroot} -name perllocal.pod -or -name .packlist | xargs rm -f
find %{buildroot}%{bundle_prefix} -type f -print |
        sed "s@^$RPM_BUILD_ROOT@@g" |
        grep -v ^%{_mandir} |
        grep -v perllocal.pod |
        grep -v "\.packlist" > %{name}.files
if [ "$(cat %{name}.files)X" = "X" ] ; then
    echo "ERROR: EMPTY FILE LIST"
    exit -1
fi

%clean
rm -rf %{buildroot}
rm -rf %{buildhome}
%post

%preun

%postun

%files -f %{name}.files
%defattr(-, root, root, -)
%dir %{bundle_prefix}

%changelog

どこかからのコピペが混ざっていたりと、あまりきれいではないけど。このspecファイルによって、/usr/local/bundle-plack以下にlocal::libと依存モジュールがすべてインストールできる。

使用するときは、普通のlocal::libと同じようにshellだったら

eval $(perl -I/usr/local/bundle-plack/lib/perl5 -Mlocal::lib=/usr/local/bundle-plack)

とやればOK。

この方式を利用することで、サービスで用いている他のモジュールに影響することなく、新しいモジュールをインストールでき、一部の必要としているところだけに適用できるってのがいいですね。

以下はlocal::libにあてているpatch

diff -ur local-lib-1.004009.orig/lib/local/lib.pm local-lib-1.004009/lib/local/lib.pm
--- local-lib-1.004009.orig/lib/local/lib.pm    2009-11-08 10:27:23.000000000 +0900
+++ local-lib-1.004009/lib/local/lib.pm 2009-11-26 11:59:21.000000000 +0900
@@ -235,6 +235,20 @@
   File::Spec->catdir($class->install_base_perl_path($path), $Config{archname});
 }

+sub install_base_path {
+    my ($class, $path) = @_;
+    $ENV{ORIGINAL_PREFIX} ? $ENV{ORIGINAL_PREFIX} : $path;
+}
+
+sub destdir {
+    my ( $class ) = @_;
+    if ( $ENV{DESTDIR} && $ENV{DESTDIR} !~ m!/$! ) {
+        $ENV{DESTDIR} .= '/';
+    } 
+    $ENV{DESTDIR};
+}
+
+
 sub ensure_dir_structure_for {
   my ($class, $path) = @_;
   unless (-d $path) {
@@ -253,8 +267,11 @@
     warn "Attempting to create file ${modulebuildrc_path}\n";
     open MODULEBUILDRC, '>', $modulebuildrc_path
       || Carp::croak("Couldn't open ${modulebuildrc_path} for writing: $!");
-    print MODULEBUILDRC qq{install  --install_base  ${path}\n}
+    print MODULEBUILDRC qq{install  --install_base  } . $class->install_base_path(${path}) . qq{\n}
       || Carp::croak("Couldn't write line to ${modulebuildrc_path}: $!");
+    if ( my $destdir = $class->destdir ) {
+        print MODULEBUILDRC qq!         --destdir $destdir\n!;
+    }
     close MODULEBUILDRC
       || Carp::croak("Couldn't close file ${modulebuildrc_path}: $@");
   }
@@ -344,9 +361,10 @@

 sub build_environment_vars_for {
   my ($class, $path, $interpolate) = @_;
+  my $destdir = ( $class->destdir ) ? " DESTDIR=" . $class->destdir : "";
   return (
     MODULEBUILDRC => $class->modulebuildrc_path($path),
-    PERL_MM_OPT => "INSTALL_BASE=${path}",
+    PERL_MM_OPT => "INSTALL_BASE=" . $class->install_base_path(${path}) . $destdir,
     PERL5LIB => join($Config{path_sep},
                   $class->install_base_perl_path($path),
                   $class->install_base_arch_path($path),

もっとスマートな方法があればだれか教えてくださいませ(_ _)

memcachedに依存するシステムやコードを書く人は大嫌いな訳だけど、スケーラビリティを向上させてレスポンス時間の高速化には必須なmemcachedですが、最近のプロトコル変更には疑問を感じてしまう。

1.4.0では、こちらに書いた通り、いつの間にかdeleteのtimeoutがサポートされなくなった。なので、

delete key timeout noreply

というコマンドが無効になって困ることになった。それでも

delete key timeout

というコマンドは、timeoutにどんなも文字列が入っていてもエラーになることはなかった。timeoutは効かないけど。

ここから1.4.4ではさらに悪化。timeoutが0でないとエラーになるようになった。つまり

delete key 0 noreply
delete key 0

は有効なんだけど、

delete key 10

がエラーになるようになった。 この変更のコミットはこれ

実際試す。

% telnet localhost 11234
 Trying 127.0.0.1...
 Connected to localhost.
 Escape character is '^]'.
 version
 VERSION 1.4.4
 delete key 10
 CLIENT_ERROR bad command line format.  Usage: delete <key> [noreply]
 quit

プロトコルの変更は下位互換が基本中の基本だと思うんだ。また1つmemcachedが嫌いになった。

ひさびさにnginxなどいじっている。

nginxがnon-blockingで動いているので、組み込みのPerlでもblockingする処理をいれることはおすすめされていないのですが、sleepだけは機能が用意されていました。使い道がよくわからないけど、とりあえずレスポンスを遅延させるのだけやってみた。

まず、handlerとなるperlモジュール

package delay; 

use nginx; 

sub handler {
    my $r = shift; 
    my $args = $r->args;
    $args =~ m/sleep=([^&]+)/;
    my $sleep = $1 || 1;
    $r->variable("sleep", $sleep);
    if ( $sleep ne "no" ) {
        $r->sleep($sleep * 1000, \&next);
        return;
    }
    $r->send_http_header("text/html");
    $r->print("<html><head><title>title</title></head><body>sleep:$sleep</body></html>\n");
    return OK; 
}

sub next {
    my $r = shift;
    my $sleep = $r->variable("sleep");
    $r->send_http_header("text/html");
    $r->print("<html><head><title>title</title></head><body>sleep:$sleep</body></html>\n");
    return OK;
} 

1;

このコードの中の$r->sleepが遅延実行ようにするところ

$r->sleep( msec, func )

となるようです。

これを利用するnginx.conf

worker_processes  16;

events {
    worker_connections  32768;
}

http {
    include       /usr/local/nginx-server/conf/mime.types;
    default_type  application/octet-stream;

    sendfile        on;
    tcp_nopush      on;
    keepalive_timeout  60;

    perl_modules /path/to/lib;
    perl_require  delay.pm;

    server {
        listen       80;
        server_name  localhost;
        access_log off;

        location / {
            perl  delay::handler;
        }
    }
}

ApacheBenchでベンチマークをとったところ、

 ab -c 1000 -n 100000 'http://localhost/?sleep=0.1'
 Concurrency Level:      1000
 Time taken for tests:   10.449 seconds
 Complete requests:      100000
 Failed requests:        0
 Write errors:           0
 Total transferred:      19100000 bytes
 HTML transferred:       6900000 bytes
 Requests per second:    9570.41 [#/sec] (mean)
 Time per request:       104.489 [ms] (mean)
 Time per request:       0.104 [ms] (mean, across all concurrent requests)
 Transfer rate:          1785.11 [Kbytes/sec] received

想定通り、1コネクションあたり10req/secできるみたい。

これだけだと使い道があまりわからないだけど、nginxのevent loopが組み込みperlから利用できるようになる最初の一歩だと期待すればwktkです。

あと、調べた感じ、組み込みperlを入れるオーバーヘッドは5%ぐらいだった。7万req/secが6万6千req/secぐらい

もっと詳しい方のフォロー募集です

アプリケーションがマルチスレッドになってもネットワーク処理が分散されなければマルチコアを活かせない典型的な例です。id:viverの古橋さんがs100kpsとしてあげていた件にも近いかも。

memcachedで現象を確認します。最近のmemcachedはマルチスレッドで動くようになっているので、まずはそれを確認します。

$ memcached-tool localhost stats|grep threads
threads           4

スレッドが4つで起動しています。

負荷がそれなりにある状態(8000req/sec程度)で、コマンドラインでtopを開き、「1」キーを押して、CPUごとの使用率を表示します。(例はFedora8 kernel-2.6.23)

Tasks:  77 total,   1 running,  76 sleeping,   0 stopped,   0 zombie
Cpu0  :  0.0%us,  0.0%sy,  0.0%ni,100.0%id,  0.0%wa,  0.0%hi,  0.0%si,  0.0%st
Cpu1  :  3.0%us,  5.7%sy,  0.0%ni, 75.3%id,  0.0%wa,  7.7%hi,  8.3%si,  0.0%st
Cpu2  :  0.0%us,  0.3%sy,  0.0%ni, 99.7%id,  0.0%wa,  0.0%hi,  0.0%si,  0.0%st
Cpu3  :  0.0%us,  0.0%sy,  0.0%ni,100.0%id,  0.0%wa,  0.0%hi,  0.0%si,  0.0%st

PID USER      PR  NI  VIRT  RES  SHR S %CPU %MEM    TIME+  COMMAND                                                                                            
3692 nobody    20   0 10.9g  10g  716 S   10 44.0  10253:09 memcached

*メモリの行は削除しています。

CPUは4つ認識されていますが、CPU1しか使用されていないのがわかると思います。おそらく、CPU1のアイドルがなくなった時点で他のCPUに空きがあってもそれ以上の処理ができなくなります。なぜCPU1しか使われないかは「/proc/interrupts」をみるとなんとなくわかります。NICはBroadcom BCM5722です。

$ cat /proc/interrupts
           CPU0       CPU1       CPU2       CPU3 
  0:      10569          0      10460          0   IO-APIC-edge      timer
 16:        301        301        302     303161   IO-APIC-fasteoi   aerdrv, aerdrv, aerdrv, ioc0, eth0
 17:          8 3570118309          7          7   IO-APIC-fasteoi   eth1

memcachedの通信は主にeth1で行われるのですが、このeth1に関する割り込み処理がCPU1でしか行われていません。ソフトウェア割り込みはハードウェア割り込みが行われたCPUでしか行われないのもこの傾向を強めます。

マルチコアCPUの性能を活かすために考えられることは、ネットワークの割り込み処理を複数のCPUに分散することだと思うのですが、最新のNICにはRX/TX Multiple Queue(正式名称がわからない。Receive Side ScalingとかScalable I/O?)機能が備わっています。もともとRX/TX Multiple Queueは10GbpsのNICなどに備わっていた機能で、複数の割り込みチャンネルを持つことでネットワーク処理の分散を実現しています。最近のIntelやBroadcomの1GbpsのNICにも同じ機能があります。

以下はBroadcomのBCM5709を搭載しているマシンのinterrupts。(CentOS 5.3)

           CPU0       CPU1       CPU2 ..  CPUy      CPUz
  0:  342688765          0          0         0          0    IO-APIC-edge  timer
114:         55         34      19613     39212         11       PCI-MSI-X  eth0
122:         23          0        145       193          0       PCI-MSI-X  eth0
130:        243          0         75       138          0       PCI-MSI-X  eth0
138:         24         12      10423     35836          6       PCI-MSI-X  eth0
146:       2141          0        110       556          0       PCI-MSI-X  eth0
154:         21          4      12802     17806          7       PCI-MSI-X  eth0
162:        561          0        216        72          0       PCI-MSI-X  eth0
186:         72         76      97076    137548     197952       PCI-MSI-X  eth1
194:         24      45478     100337    140189     554148       PCI-MSI-X  eth1
202:         24     527452      94677     87876     305476       PCI-MSI-X  eth1
210:         23     220400     175792     56390     205521       PCI-MSI-X  eth1
218:         24      37023      30778      6169      11788       PCI-MSI-X  eth1
226:         21     349792      48599     91969          0       PCI-MSI-X  eth1
234:         23     206063       5911     43536          4       PCI-MSI-X  eth1

*加工済み

こんな感じで、割り込み処理用のチャンネルが複数個存在して、CPU間で分散ができています。

まとめると、マルチコアCPU、SSDの普及によってハードウェアの性能があがり、epoll/kqueue/event portsによって大量のコネクションをさばけるようになると、こういった複数のCPUに分散できない処理がボトルネックになってくるので、最新のハードウェアとか対応しているカーネルを利用しようということです。

WEB+DB PRESS Vol.51の連載で、サーバRFPを設定してそれに基づいて購入していると書きましたが、来年度(2010年度)ぐらいのRFPになりそうな主流となるサーバを考えてみました。

まず、共通していること、前提など

  • CPUのコア数はHTなどによる論理コア含む計算
  • ネットワークインターフェイスは1Gbpsを2つ以上。RX/TX MultiQueueをサポートしていること
  • SSDはIntel X25-M 160GBもしくは同等製品

サーバは主に4タイプあります。

■Utility Server

小規模DB、Q4MやGearmanなどのJobQueue/Workerサーバ、memcachedやSquid/Varnishなどのキャッシュサーバに利用するサーバ。目的に応じてHDDをSSDに換装して利用できることが必要となります。

  • CPU 8コア以上 * 1
  • Memory 16GB
  • HDD SAS 15krpm 146GB
  • SSDに換装可能

■Application Server

アプリケーションサーバやリバースプロキシーに使う。おそらく最もCPU(ユーザ)の負荷が高い。性能の高く、コア数が多いCPUでぶん回して全体のサーバ台数は減らしたい。

  • CPU 8コア以上 * 2
  • Memory 16GB
  • HDD SAS 15krpm 300GB

■High Memory DB

中負荷〜高負荷DBとして利用。SSDについて入れ替えではなく追加としてしているのはデータベースのデータ部分をSSD、バイナリログをHDDとそれぞれの特性に応じて使い分けるためになります。メモリについては後述します。

  • CPU 6コア以上 * 2
  • Memory 48〜64GB
  • HDD SAS 15krpm 146GB
  • SSDを追加可能

■Large Data DB

メモリにすべてのデータが乗り切らないデータ蓄積型、大規模なDB用。

  • CPU 6コア以上 * 2
  • Memory 48〜64GB
  • HDD SAS 15krpm 300GB * 6本以上
  • RAID5

48〜64GBとしたメモリに関して、64GBを積むためには1本8GBのものを買わないとならなく、4GBと比べると3倍程度するのが悩みどころ。メモリの値段は上がってきている中で8GBの値下がりするのか注目。また、今年の後半(前半?)には、Westmere-EPが出て、6コア/12スレッドになるので、また少し状況が変る可能性がありますね。こちらも注目

奥一穂さんの「ウェブアプリケーションサーバを複数台構成とか2010年代には流行らない」にフォローのような感じで。 例によってタイトルは煽りです。

奥一穂さんのエントリーでは、「5,000万PV/Month」という見積もりでアプリケーションサーバの台数を1台と計算していますが、これからは「1,000万PV/Day」を超えるサイトが多く生まれてくると予想しています。どんなサイトかというと、mixiアプリやモバゲーなどにソーシャルゲームを提供するサイトです。

ソーシャルゲームサイトのキャパシティプランニングについては中澤さんのエントリーが参考になります。

最も人気がでた場合には数千万から数億PV/Dayという数字がならんでいます。怖い怖い

1,000万PV/Dayとなると、ピークのリクエスト数が平均の2倍として秒間に230リクエストとなります。

( 10,000,000 pv / 86400 sec/day ) * 2 = 231.481481


奥一穂さんの試算であれば、クアッドコアのサーバで秒間40回の処理が可能なので、6台程度のアプリケーションサーバがあれば、1日1,000万PV、月に3億PVがさばけることになります。冗長性や安全をとるためにサーバを増やしたり、またクアッドコアを2つ搭載するマシンを採用することも考えられますが、この数字は自分の経験と比べても大きなずれはない数字です。

さて、ここからが本題で、1,000万PV/Day(秒間230 req/sec)には何台のデータベースが必要となるのでしょうか。Shardingを行ってデータベースの分散を行い多くのデータベースサーバを運用する必要があるのでしょうか。

1リクエストにつき、SQLを8回発行した場合、秒間のクエリー数の最大は1840query/sec

230 req/sec * 8 = 1840 query/sec


このうち、5%程度が更新系のクエリーだったとしたら、更新系クエリは92 query/secとなり、

1840 query/sec * 0.05 = 92 query/sec


残りが参照クエリとなり、1748 query/secとなります。1リクエストあたりのSQL数や更新回数はアプリケーションにより大きく変動しますが、この程度のクエリー数の場合、MySQLであれば1台で処理することは可能です。冗長性やバックアップのためのSLAVEサーバも追加して1組2台あれば安定稼働できます。

多くのSQLをさばくためには、クアッドコア以上のCPUや十分なメモリー、最適なデータベースサーバの設定や、効率のよいスキーマとSQLの設計が必要です。Blogサービス等でなければデータをあまり蓄積しないのも重要です。MySQLであれば次の書籍が非常に参考になります。


もし、アプリケーションがもっと多くのクエリーを発行していたり、負荷が大きな場合には、安くなったSSDを使ったり、SLAVEサーバを追加して参照クエリーを分散を行ったり、memcachedを利用して参照クエリを減らしたり、また、更新が多いテーブルだけを別のMySQLサーバに移動したり、データが単純なkey-valueであればTokyo TyrantRedisなどを利用すれば、データベースサーバを最小限にとどめることができます。

2010年代は手軽に購入できるようになった高性能なハードウェアでスケールアップし、OSやミドルウェアのチューニングを行うことで、アプリケーションサーバ、データベースサーバを最小限に食い止め、サービスの収益率を改善してお給料を増やしてもらうのがよいのだろうと思う。

あけおめ!ことよろ!今年は耐えた感じです!

R0012587.jpg

プライベートでは、昨年は子供が生まれ生活ががらりと変わった一年でした。仕事の方に目を向けると、前回に続いてのYAPC::Asiaでの発表、mixiアプリの開始による変化への対応、また、技術評論社様のWEB+DB PRESSで連載をさせて頂くなど新しいチャレンジもできました。

今年は息子が保育園に入る予定があるなどなどまだまだ激動は続きそう。そして6月には0x20歳。仕事も去年の激動の余波が残っていますが、2011年、2012年と何を目指すのかも自分なりに考えていたいなぁと思っています。

ってことで今年もよろしくお願いします。

2009年もそろそろ終わりですね。

WEB+DB PRESSで連載させて頂いている「大規模Webサービスの裏側」もVol.54にて第五回となりました。


第五回目の今回は、「ログ&データ解析 .. 現状の改善と新サービス開発のために」ということで、アクセスログの解析やデータマイニングの話題を、システム運用グループの加藤幹生さん、研究開発の木村さんと藤澤さんに書いて頂きました。

一般にシステム運用の仕事のイメージとは少し異なりますが、大量のデータをさばく重要な技術のひとつです。

Preforkした上でAnyEventのloopを動かすPlack::Server::AnyEvent::Preforkを、先週のPlack Hackathonの時間で形にしてgithubにpushしました。

はなぼくろ師との共作です。

目的は、AnyEventでもマルチコアを使いたいよねという理由ですが、それほど一般的な利用はないと思います。plackupの方でprefork処理を行うとかいう話もあったりなかったりなので、しばらくCPANにはアップロード予定ありません。不足している部分もありますので、fork & patchウェルカムです

Hello Worldだけのテストで生AnyEventとの比較 ベンチマークをしたサーバはVMware ESXi上の仮想マシン。一応CPU 2つ割当てある

起動はこんな感じ

plackup -a hello.psgi --server AnyEvent::Prefork --max_workers 2 --max_reqs_per_child 10000 --port 8080 --env production

AnyEvent

Concurrency Level:      100
Time taken for tests:   3.941 seconds
Complete requests:      10000
Failed requests:        0
Write errors:           0
Total transferred:      680000 bytes
HTML transferred:       40000 bytes
Requests per second:    2537.41 [#/sec] (mean)
Time per request:       39.410 [ms] (mean)
Time per request:       0.394 [ms] (mean, across all concurrent requests)
Transfer rate:          168.50 [Kbytes/sec] received

AnyEvent::Prefork

Concurrency Level:      100
Time taken for tests:   2.673 seconds
Complete requests:      10000
Failed requests:        0
Write errors:           0
Total transferred:      680000 bytes
HTML transferred:       40000 bytes
Requests per second:    3740.71 [#/sec] (mean)
Time per request:       26.733 [ms] (mean)
Time per request:       0.267 [ms] (mean, across all concurrent requests)
Transfer rate:          248.41 [Kbytes/sec] received

preforkにするだけで、req/secが50%アップしてます。 これで多少CPUを使ったり、block処理が入ってもAnyEventで動かすことができるんじゃないかなと思います。

現在残っている課題としては、子プロセスがmax request per childに達した際にまず、新規のacceptを行わないようにしていますが、その際に既存のコネクションをいつまで保持するかの処理が入っていない点です。streamingをやっていた場合は新規のacceptを受けない状態でいつになってもプロセスが死なない→新規のプロセスが立ち上がらない→リクエストを全く受けれない。なんていうことが起こることです。 現状としては、アプリケーションに応じてそのあたりの処理を入れていくしかないと思われます。

会社の最新サーバでも試してみたいな。

ウェブページ

Amazon

Powered by Movable Type 4.27-ja

アイテム

  • R0012587.jpg
  • R0011798.JPG
  • google_reader.jpg
  • mt-ping.jpg
  • fb-pingshot.jpg
  • yapc2009_logo.gif
  • remedie-menu.jpg
  • remedie-bonjour.jpg
  • vmware-esxi-power-tab.jpg
  • vmware-esxi-power-details.jpg

最近のコメント

Ads by Google

最近のコンテンツはインデックスページで見られます。過去に書かれたものはアーカイブのページで見られます。