日記+コメント付きブックマーク+他人にも役に立つかもしれない情報など。
(更新情報: RSS(ツッコミ付き) / RSS(ツッコミ抜き) / LIRS)
- p (01/03)
- Thiramil (10/26)
- 久々にいまむらを食べたい通りすがり (09/28)
- Fluxadir (05/16)
- Antiprestin (11/08)
2009/07/08
_ [システム運用][ベンチマーク] Windows 版サイボウズガルーンは Linux 版より2倍重い
某環境にて、サイボウズガルーン1.5を Linux 版から Windows 版に乗り換えたところ、アクセス要求集中時などに度々レスポンスが激しく悪化しサービスに支障を来すという状況に陥るようになった。
また、サイボウズ ガルーン 2 をインストールするサーバーの環境構築例によれば、「クアッドコア インテル Xeon プロセッサー X5460 3.16GHz × 2」という環境下で、Linux 版は1000ユーザ、Windows 版は500ユーザでの利用を想定しているという。
Windows 版は Linux 版より倍近くパフォーマンスが悪いのだろうか? …ということで、サイボウズガルーン2体験版でベンチマークした結果が下記のデータだ。
テスト方法
- WWW::Mechanize を使用し、ログイン後のトップページを GET、レスポンス完了するまでの時間を計測、30秒間で何回成功するか測る
- …という処理を ithreads で同時接続数を1〜8と変えながらテスト
テストサーバ環境
- CPU: Xeon X3350
- MEM: 8GB
- OS: ESXi4
上に作られた、
- CPU: 2コアまたは4コア
- MEM: 2GB
- OS: CentOS 5 または Windows Web Server 2008 (ともに 32bit)
という仮想マシン。(thanks to ○△)
結果
| CPU | 2コア | 4コア | ||
|---|---|---|---|---|
| 同時接続数 | 成功回数 | 平均応答時間 | 成功回数 | 平均応答時間 |
| 1 | 55 | 545ms | 53 | 566ms |
| 2 | 106 | 573ms | 86 | 699ms |
| 4 | 127 | 962ms | 120 | 1,015ms |
| 8 | 134 | 1,842ms | 129 | 1,896ms |
| CPU | 2コア | 4コア | ||
|---|---|---|---|---|
| 同時接続数 | 成功回数 | 平均応答時間 | 成功回数 | 平均応答時間 |
| 1 | 28 | 1,097ms | 29 | 1,048ms |
| 2 | 56 | 1,098ms | 54 | 1,126ms |
| 4 | 59 | 2,079ms | 98 | 1,241ms |
| 8 | 63 | 3,974ms | 108 | 2,269ms |
デュアルコア環境では Windows 版は Linux 版と比べてほぼ約2倍遅いということがベンチマークからも確認できた。(ただしこの数値だと、クアッドコア環境だとその差が縮まっていたり、Linux 版は4コアの方が2コアよりスコアが悪かったりする。これはバックグラウンドで余計なタスクを動かしてしまった影響と考えられるが、面倒なので追試はしない)
悪いのが OS なのかサイボウズなのかはわからないけど、とにかくサイボウズ動かすなら Windows 版という選択肢はないな…。
それにしても、仮想環境とはいえこの遅さは (Linux 版含めて) 酷い…
そりゃ高々1000ユーザ程度で「Xeon X5460 × 2」なんて豪勢な環境を要求するわけですよ…
関連:サイボウズコミュニティ - 過去のエントリー - 【ガルーン2】Windows版の動作環境
(使用したスクリプト)
#!/usr/bin/perl
use strict;
use warnings;
use threads;
use Getopt::Long;
use POSIX;
use Time::HiRes qw(gettimeofday tv_interval);
use WWW::Mechanize;
my $user; # ex: 'username'
my $pass; # ex: 'password'
my $url; # ex: 'http://example.com/cgi-bin/cbgrn/grn.cgi'
my $threads = 1;
my $span = 60;
GetOptions(
'--user=s' => \$user,
'--pass=s' => \$pass,
'--url=s' => \$url,
'--threads=i' => \$threads,
'--span=i' => \$span,
);
if (!defined $user or !defined $pass or !defined $url) {
print <<"EOD";
$0 [options]
-us, --user=username
-p, --pass=password
-ur, --url=url
-t, --threads=threads [1]
-s, --span=seconds [60]
EOD
exit;
}
my @threads;
for (1..$threads) {
my $th = threads->new(\&stress, $_);
push @threads, $th;
}
my ($success, $successtime, $failed) = (0, 0, 0);
foreach (@threads) {
my $r = $_->join;
$success += $r->[0];
$successtime += $r->[1];
$failed += $r->[2];
}
my $avg = $success ? $successtime / $success : 0;
printf "Total: Success: $success (Avg: %.2dms), Failed: $failed\n", $avg;
# 負荷テストスレッド
sub stress
{
my $tid = shift;
my $mech;
my $count = -1;
my ($success, $successtime, $failed) = (0, 0, 0);
my $st;
while (1) {
my $result = undef;
my $login = '';
if ($count < 0 or ++$count >= 600) { # 定期的に mech 再構築
$count = 0;
$mech = WWW::Mechanize->new;
}
my $t0 = [gettimeofday];
eval {
if (my $res = $mech->get($url)) {
if ($res->content =~ /<form name="?login"?/) {
$mech->set_fields('_account' => $user, '_password' => $pass);
#↓ガルーン1.5の場合
# $mech->set_fields('_Account' => $user, 'Password' => $pass);
$mech->submit;
die unless $mech->success;
$login = ' login';
}
$result = int(tv_interval($t0) * 1000 + 0.5);
if ($login eq ' login') {
sleep 1;
$st = [gettimeofday];
}
else {
$success++;
$successtime += $result;
}
$result .= ' ' . '*' x ($result / 1000) if $result >= 1000;
}
else {
$result = 'failed';
$failed++;
}
};
if ($@) {
$result = 'failed';
$failed++;
}
print strftime('%Y-%m-%d %H:%M:%S', localtime) . ": T$tid: $result$login\n";
last if tv_interval($st) > $span;
}
my $avg = $success ? $successtime / $success : 0;
printf "T$tid: Success: $success (Avg: %dms), Failed: $failed\n", $avg;
return [$success, $successtime, $failed];
}
