Apacheで勝手にrouteを付加する方法
バックエンドワーカー側でStickySessionにrouteを付加できない、もしくは望みのrouteにできない場合、Apache側で勝手に適当なCookieをセットしてやることで、同一リクエストを同一ワーカーに振り分け続けることができる。はず。
ということでやってみた。使用しているのは例によってApache/trunk(2.3)だが、2.2.4でもいけるはず。mod_proxy_balancerに加えて、mod_setenvifとmod_headersが必要。
設定の意図は以下の通り。
- リクエストにRSESSIONが無い場合
- レスポンスに、適当なID+ワーカー名を値としたCookie "RSESSION" をセットする
- このキー名はアプリ側で取り扱っているStickySession名とは異なったものにしておく
- リクエストにRSESSIONがある場合
- RSESSIONに含まれるワーカーに配送されること
- レスポンスはそのRSESSIONの値をそのままセットしなおす
(設定例を7/18に微修正)
SetEnvIf ^Cookie$ "RSESSION=([^ ;]*)." R_UNIQUE_ID=$1 Header append Set-Cookie "RSESSION=%{UNIQUE_ID}e.%{BALANCER_WORKER_ROUTE}e; path=/" env=!R_UNIQUE_ID Header append Set-Cookie "RSESSION=%{R_UNIQUE_ID}e; path=/" env=R_UNIQUE_ID ProxyPass /path1/ balancer://testcluster1/ stickysession=RSESSION <Proxy balancer://testcluster1> BalancerMember http://worker1 loadfactor=10 route=worker1 BalancerMember http://worker2 loadfactor=10 route=worker2 </Proxy>
環境変数はそれぞれ、BALANCER_WORKER_ROUTE は配送先ワーカー、UNIQUE_ID はApacheが生成するユニークなID。R_UNIQUE_IDはリクエスト中のセッションIDを格納するのに名付けた。
以上の設定で、意図した通りの動作になってそう。タイムアウトとかは処理できないが、まあ仕方あるまい。
本当は「JSESSIONIDは存在するがrouteがセットされていない場合に、レスポンスのJSESSIONIDにはrouteを付加し、リクエストでJSESSIONIDが渡ってきたらrouteを削ってから望みのworkerに渡してやる」ということをやりたかった。
が、RequestHeaderディレクティブを使ってCookieからrouteを削る設定をすると、routeが無くなった状態でバランサーに渡される -> routeが無いので適当なワーカーに配送される というようになってしまい、望みの動作(配送されるワーカーを固定する)が得られないので断念。
事実上は配送先認識にJSESSIONIDが使われていようとRSESSIONが使われていようとどうでもいいだろうから、特に支障はなさそう。(実際、BIG-IPなんかも勝手に名付けた値を配送先特定に使用しているし。)