負け組アーキテクトの憂鬱

メモしておきたいことや読書の記録を淡々と書く。

Apache httpd

mod_proxy_balancerのstickysessionは大文字小文字を区別する

何事もなかったように記事再開。

で、何が困ったかというと、apache httpd-2.2.4に添付のmod_proxy_balancerの挙動。

mod_proxy_balancerについてはこちら。要はmod_proxy系の各種モジュールでproxy先をバランシングできるわけですな。mod_proxy_balancer自体はかなり汎用性のあるモジュールなんだけど、今回困った用途はmod_proxy_ajpとの組み合わせ、つまりmod_jk(2)の代用として使ったときのこと。

たとえばweb層をapache(+mod_ajp +mod_proxy_balancer)の1台、ap層をtomcatの2台構成にしたとき、かつstatefulに振り分けをする必要があって、かつtomcatでセッションレプリケーションが使えない時にstickysessionの機能を使う。

httpd.conf中ではこんなかんじ。

 ProxyPass /webapp/ balancer://testcluster/webapp/ stickysession=ss
 <Proxy balancer://testcluster>
        # r0
        BalancerMember ajp://192.168.100.10:8009 loadfactor=1 route=r0
        # r1
        BalancerMember ajp://192.168.100.11:8009 loadfactor=1 route=r1
 </Proxy>

この設定はssという変数中にr0という文字列が含まれた場合(正しくはss=hogehhuga.r0 のようにピリオド+文字列で終わった場合)にはajp://192.168.100.10:8009に、ajp://192.168.100.11:8009にr1という文字列が含まれた場合にはajp://192.168.100.11:8009にproxyするというもの。変数とは具体的にはCookie、CGI環境変数、urlが利用できるスグレモノだ。

これをtomcatが付加してくれるjsessionidとjvmRouteと組み合わせるとstickysessionを実現できるようになる。2台のtomcatのjvmRouteにそれぞれr0, r1を指定すると、UAがCookieを使える設定になっていればCookieにJSESSIONID=hanamogerahogehoge.r0、Cookieが使えないUAにはURLパラメータとして;jsessionid=gegehogegehoge.r0といった具合に値を付加してくれる。ここでhttpd.confで以下のように設定しておけば、JSESSIONIDにr0が入っていればtomcat(r0)に、r1が入っていればtomcat(r1)にajp接続してくれる。一つのsessionは同じコンテナに接続される、という仕組み。

 ProxyPass /webapp/ balancer://testcluster/webapp/ stickysession=JSESSIONID
 <Proxy balancer://testcluster>
        # r0
        BalancerMember ajp://192.168.100.10:8009 loadfactor=1 route=r0
        # r1
        BalancerMember ajp://192.168.100.11:8009 loadfactor=1 route=r1
 </Proxy>

ただし、stickysession=JSESSIONIDではJSESSIONIDが大文字の場合にしかmatchしない。しかも良くないことにtomcatはCookieではJSESSIONIDと大文字、urlではjsessionidと小文字で変数名を指定する。たとえばCookieを有効にしたUAのみを対象にしたサイトでは問題ないが、Cookieの使えない携帯電話用サイトなども混在差せる場合これでは対応できない。しかも今の仕様ではstickysessionを複数指定することもできないようだ。

とはいえ、この仕様はapacheのbugzillaにも登録されており、一応不具合として認識はされているようだ。該当のbug。とりあえずここのpatchを、httpd-2.2.4のmod_proxy_balancer.cに当たるようにしたものがこれ(ほとんど変わらないけど)。

 --- mod_proxy_balancer.c.orig   Wed May 23 11:09:16 2007
 +++ mod_proxy_balancer.c        Wed May 23 11:58:50 2007
 @@ -112,9 +112,18 @@
                              const char *name)
  {
      char *path = NULL;
 +    char *session_id = NULL;
 +    int  i;
 
 -    for (path = strstr(url, name); path; path = strstr(path + 1, name)) {
 -        path += strlen(name);
 +    session_id= apr_pstrdup(pool, name);
 +    /* Change 'JSESSIONID' to 'jsessionid' to match the value in the url */
 +    if (isupper(name[0])) {
 +      for (i=0;i<=strlen(session_id);i++)
 +       session_id[i] = tolower(session_id[i]);
 +    }
 +
 +    for (path = strstr(url, session_id); path; path = strstr(path + 1, session_id)) {
 +        path += strlen(session_id);
          if (*path == '=') {
              /*
               * Session path was found, get it's value

このpatchを当てることで、とりあえず無邪気にstickysessionを小文字でもmatchするようにしてくれる。本来の挙動(大文字と小文字を厳密に区別する)を期待する場合にはpatchを当ててはいけない。

本来この設定と挙動はどうあるべきか、という議論は、このへんから始まる一連のthreadで話合われているようなので、次回のリリース(httpd-2.2.5?)では何らかの実装の変更があるだろう。

主なhttpクロウラーのIPアドレスレンジを調査

※2009/09追記: 内容が古いです。

過去、約2年分のアクセスから統計をとってみた。

「GoogleBotを名乗るけれども実は違うもの」の考慮はせず、単純にgrepしてsort,uniqしてみた。

それぞれのアドレスが含まれるwhoisのエントリはこちら(IPアドレスレンジ以外は抜粋)

 Google Inc. EC12-1-GOOGLE (NET-64-68-80-0-1)
                                  64.68.80.0 - 64.68.87.255

 OrgName:    Google Inc.
 NetRange:   66.249.64.0 - 66.249.95.255
 CIDR:       66.249.64.0/19
 NetName:    GOOGLE
 NetHandle:  NET-66-249-64-0-1
 RegDate:    2004-03-05
 Updated:    2004-11-10

 inetnum:      202.160.176.0 - 202.160.191.255
 netname:      YAHOO-ALIBABA-1
 descr:        Yahoo Inc, Internet Content Provider
 route:        202.160.176.0/20

※INKTOMIは米Yahoo!に買収された検索エンジン提供企業
 OrgName:    Inktomi Corporation
 NetRange:   66.196.64.0 - 66.196.127.255
 CIDR:       66.196.64.0/18
 NetName:    INKTOMI-BLK-3
 NetHandle:  NET-66-196-64-0-1
 RegDate:    2001-10-30
 Updated:    2005-08-26

 OrgName:    Inktomi Corporation
 NetRange:   68.142.192.0 - 68.142.255.255
 CIDR:       68.142.192.0/18
 NetName:    INKTOMI-BLK-4
 NetHandle:  NET-68-142-192-0-1
 RegDate:    2004-03-24
 Updated:    2005-08-26

 OrgName:    Inktomi Corporation
 NetRange:   72.30.0.0 - 72.30.255.255
 CIDR:       72.30.0.0/16
 NetName:    INKTOMI-BLK-5
 NetHandle:  NET-72-30-0-0-1
 RegDate:    2005-01-28
 Updated:    2005-10-19

 OrgName:    Microsoft Corp
 NetRange:   207.46.0.0 - 207.46.255.255
 CIDR:       207.46.0.0/16
 NetName:    MICROSOFT-GLOBAL-NET
 NetHandle:  NET-207-46-0-0-1
 RegDate:    1997-03-31
 Updated:    2004-12-09

 OrgName:    MS Hotmail
 NetRange:   64.4.0.0 - 64.4.63.255
 CIDR:       64.4.0.0/18
 NetName:    HOTMAIL
 NetHandle:  NET-64-4-0-0-1
 RegDate:    1999-11-24
 Updated:    2006-01-23

 OrgName:    MS Hotmail
 NetRange:   64.4.0.0 - 64.4.63.255
 CIDR:       64.4.0.0/18
 NetName:    HOTMAIL
 NetHandle:  NET-64-4-0-0-1
 RegDate:    1999-11-24
 Updated:    2006-01-23

このレンジに含まれるアドレスは全てクロウラーだという保証はなく、またこれ以外にもクロウラーに割り当てられたIPアドレスがある可能性がある(当然、将来増える可能性もある)。

VirtualHostに関するちょっとした覚え書き

VirtualHostでname-basedとIP-basedを混在させる

IPv4アドレスは節約したいけど、IPv6アドレスは潤沢に使える場合などのちょっとしたメモ。httpd.confはこんな感じになる。

 Listen 123.45.67.89:80
 Listen [2001:3e0:4eb:9999:8000]:80
 Listen [2001:3e0:4eb:9999:8001]:80
 
 NameVirtualHost 123.45.67.89:80
 
 <VirtualHost 123.45.67.89:80 [2001:3e0:4eb:9999:8000]:80>
    DocumentRoot "/home/web/example.jp/htdocs"
    ServerName www.example.jp
 </VirtualHost>
 
 <VirtualHost 123.45.67.89:80 [2001:3e0:4eb:9999:8001]:80>
    DocumentRoot "/home/web/example.com/htdocs"
    ServerName www.example.com
 </VirtualHost>

DNSはこんなかんじで。

 www.example.jp.	IN	A	123.45.67.89
 www.example.jp.	IN	AAAA	2001:3e0:4eb:9999:8000
 www.example.com.	IN	A	123.45.67.89
 www.example.com.	IN	AAAA	2001:3e0:4eb:9999:8001

IPv4アドレス(一つしか割り振らないアドレス)NameVirtualHostを指定するのがポイント。あとは一纏めにしたいIPアドレスをVirtualHost指示子にスペースで区切って記述。別にIPv6じゃなくても、IPv4グローバルアドレスは一個しかないけど、プライベートアドレスはたくさんある、なんて状況でもおいしくいただけます。

ホストエントリにワイルドカードを指定

たとえばexample.jpドメインで全て同じVirtualHostに対応させたい場合。www.example.jpでもweb.example.jpでもexample.jpでもwwwwwwwwwwwwwwwwwwwwwww.example.jpでも・・・・

DNSはこう

 example.jp.	IN	A	123.45.67.89
 *.example.jp.	IN	A	123.45.67.89

httpd.confは、

 Listen 123.45.67.89:80
 <VirtualHost 123.45.67.89:80>
    DocumentRoot "/home/web/example.jp/htdocs"
    ServerName example.jp
    ServerAlias *.example.jp
 </VirtualHost>

ServerNameはもちろん、ServerAliasもname-basedの時にHost:リクエストヘッダとマッチさせて、どのVirtualHostに遷移するかを指定できる。文字通りエイリアス。ここでワイルドカードを指定してやり、example.jpドメインのどの名前が来ても同じVirtualHostがマッチさせる。IPv6の場合は適宜アレンジしましょう。

覚え書きと言っても2つしか思いつかなかったけど、またなんか覚えたり思い出したりしたら書きます。

SIGUSR1を食らったhttpdが上がってこない

月初にしばしば起きる問題。困ったもんだ。


Jun 1 00:00:00 ns newsyslog[92788]: logfile turned over

[Thu Jun 01 00:00:03 2006] [notice] seg fault or similar nasty error detected in the parent process




newsyslogでローテーションする時にSIGUSR1(シグナル30番)を送って、ファイル記述子を手放させてやる必要があるんだけど、そこで上がってこない。



ググってみたらどうもPHP4が原因っぽい雰囲気を醸し出していた。
http://www.freebsd.org/cgi/query-pr.cgi?pr=64904
http://bugs.php.net/bug.php?id=27899
http://bugs.php.net/bug.php?id=27810

何とかしようと思い立ったけど、やっぱりもう眠いから寝る。精査は明日〜(とか言って来月まで放置しそう)。