Windows server上に、Windowsドメイン認証のできるSubversionサーバを構築してハマる。

主な環境
サーバ

CPU Intel(R) Xeon(R) CPU 5160 @ 3.00GHz
Memory 3.00GB
O/S Microsoft Windows Server 2003 Standard Edition Service Pack2
その他 Apache/2.2.13 (Win32), SVN/1.6.4
Compiled in modules:
 core.c
 mod_win32.c
 mpm_winnt.c
 http_core.c
 mod_so.c|

httpd.confに追加

LoadModule sspi_auth_module modules/mod_auth_sspi.so
LoadModule dav_svn_module modules/mod_dav_svn.so
LoadModule authz_svn_module modules/mod_authz_svn.so

<Location /svn>
DAV svn
SVNPath "E:/svnrepository"
AuthType SSPI
AuthName "Authentication request from Subversion."
SSPIAuth On
SSPIAuthoritative On
SSPIDomain MYDOMAIN
SSPIOfferBasic On
Require valid-user
</Location>

クライアント(代表例)

CPU Intel(R) Pentium(R) 4 CPU 2.80GHz
Memory 2.50GB
O/S Windows XP Professional Version 2002 Service Pack 2
その他 TortoiseSVN 1.6.5, Subversion コマンドラインクライアント, バージョン 1.6.4.

一応、こんな感じで基本動作はするようになった。
が、念のため、開発ピーク時の負荷を想定して、20人がかりで一斉にcheckoutをかけてみたところ、Apacheがダウン。
ここから、ハマり道が始まった。

同時接続数が多すぎて捌ききれないのかもしれない

httpd-mpm.confで、以下の値を調整。

<IfModule mpm_winnt_module>
# 150→500
   ThreadsPerChild      500
# 0→10000
   MaxRequestsPerChild    10000
</IfModule>

もう一度同じ負荷をかけたところ、Apacheが落ちなかったので、これで安心と思ったら、しばらくたつとやっぱり落ちた。

どこに負荷がかかっているのだろうか

Windows タスク マネージャでパフォーマンスタブを確認。
PF使用量が非常に高い。
プロセスタブを確認すると、httpd.exeが最大で約2GBも使用している。パフォーマンスモニターのカウンタログで、Processor/Memory/PhysicalDiskの負荷状況を記録すると、Memory/Available MBytesがどんどん落ちていく。CPU/HDDの負荷は許容範囲内。

負荷テストを毎度20人がかりで行うのはしんどい

ので、Perlスクリプトで代用してみる。

use strict;
use warnings;

my $pid;

for(my $i = 0; $i < 10; $i++){
       mkdir($i);
       if ($pid = fork()){
           print "親プロセス(" . $pid . ")です。\n";
       }
       elsif(defined $pid){
           print $i . ":子プロセス(" . $pid . ")です。\n";
           chdir($i);
           system("svn co http://foo/svn --username bar --password baz");
           last;
       }
       else{
               print "親でも子でもないです。\n";
       }
}

同一IPからのアクセスになるが、ちゃんと別々のフォルダにcheckoutされ、負荷テストの状況(メモリ空き容量がどんどん減っていく)を再現できた。処理速度的にはクライアント側のDisk I/Oが律速になっているようだが、問題は再現する。

問題の元がメモリリークならば

何度も負荷テスト→負荷テスト→負荷テスト→サーバのメモリ逼迫→何かの拍子にApacheダウンというのを繰り返してみて、感覚的に"svn coするとどんどんApacheがメモリを喰う"という線が濃厚になってきた。
Windows + Apacheの環境では、AcceptEXが問題になるケースがあるというが、今回の環境では、error.logにはその兆候は出ていない。
(参考)mpm_winnt - Apache HTTP サーバ

メモリリークに対して根本対策をする(hackする?)スキルがないため、プロセスをリセットすることで暫定対策を図る。
httpd-mpm.confで、以下の値を調整。

<IfModule mpm_winnt_module>
# 10000→5
   MaxRequestsPerChild    5
</IfModule>

何度も負荷テスト→負荷テスト→負荷テスト→…と繰り返すと、確かにプロセスがリセットされ、メモリ逼迫が解除された。
svn coの場合は、いくつファイルをダウンロードしようが、コマンド1回で、Request1回とカウントされている気がする(KeepAliveが効いてるせいかもしれない)が、コマンド5回でリセットがかかるかというとそうではないようだ。
おそらく仕掛かりのセッションが全部終わったときに、処理したRequest数が閾値を超えていればリセット、としている気がする。

長いことリセットがかからないときがある

何度も負荷テスト→負荷テスト→負荷テスト→…と繰り返すと、どうもリセットがかからないことがある。
前回の想像(仕掛かりのセッションが全部終わったときにリセット)が正しければ、何かのセッションが残ったままのはず。
httpd.confで、以下の値を有効化(#を外す)

LoadModule status_module modules/mod_status.so

ブラウザでhttp://foo/server-statusにアクセスすると、Mode of operationが"K" Keepalive (read)のままのやつがいる。
RequestはPROPFIND /CVS HTTP/1.1などとなっていて、svnサービスと関係ないリソースに対して行っている。
CVSの文字から、TortoiseCVSを疑ってみる。
共有フォルダを見たときに、TortoiseCVSが何かのバグで、WebDAVアクセスを試みているのでは?と思い、TortoiseCVS 1.2.2からTortoiseCVS 1.10.10にアップデートしてみた。
すると、PROPFIND /CVS HTTP/1.1は現れなくなった。
が、なぞのPROPFIND投げっぱなしKeep攻撃は他にもまだやってくる。

またMicrosoft

一体なんのプログラムがPROPFIND攻撃をしてくるのか確かめるべく、access.logでユーザーエージェントを記録するようにhttpd.confで、以下の値を変更(common→combind)

CustomLog "logs/access.log" combined

そうして待ち構えたところ、見事にトラップにはまってくれたのがコレ。

xxx.xxx.xxx.xxx - - [21/Oct/2009:12:21:33 +0900] "OPTIONS / HTTP/1.1" 200 - "-" "Microsoft-WebDAV-MiniRedir/5.1.2600"
xxx.xxx.xxx.xxx - - [21/Oct/2009:12:21:33 +0900] "PROPFIND /hoge HTTP/1.1" 405 346 "-" "Microsoft-WebDAV-MiniRedir/5.1.2600"

またMicrosoftか。また、Microsoftか。
server-statusとaccess.logを付き合わせたところ、これが"K" Keepalive (read)のままのやつというのはほぼ疑いない。
Microsoft-WebDAV-MiniRedirでググると、栄えある検索結果第1位がコレ。
Windows XPからファイルサーバへの接続が非常に遅い
こいつだ。間違いない。

お前の相手などしていられない

ということで、UserAgent指定でサービス拒否を行う。

# MicrosoftのWebDAVエージェントからリクエストが来た場合、サービスを拒否
SetEnvIf User-Agent "^Microsoft-WebDAV-MiniRedir/5.1.2600" deny_agent
<Location />
 Order allow,deny
 Allow from all
 Deny from env=deny_agent
</Location>

# MicrosoftのWebDAVエージェントからリクエストについて、Keep-Aliveを許可しない
BrowserMatch "^Microsoft-WebDAV-MiniRedir/5.1.2600" nokeepalive

完全にWindows XP決め打ちだが、もしVistaとか7とかから別のやつがやってきたら、そいつらもブッタKill。
ついでに自分のPCからもこのエージェントを切っておく。
[コントロールパネル]-[管理ツール]-[サービス]を開き、WebClientという名前の虫垂炎を無効にする。