1台のAPサーバでクラスタ環境を構築する手順 for Windows

(Windows7, apache2.2.17, tomcat8.6で確認, Linuxでもほぼ同じように構築できるはず)

#目的
warを更新する際、tomcatを停止、warを置き換え、tomcatを開始という手順を実施するが、
その間、システムが利用できなくなるのを回避するために、1台のAPサーバ上で冗長構成をとる。
tomcat7以降にはゼロダウンタイムデプロイ機能があるが、同時に複数バージョンが動作すると、
メモリの使用量が上がることや、メモリリークでアンデプロイできないなどリソースが枯渇する恐れがある。
その心配がなく、いつでもTomcatを再起動できる環境とするためクラスタ構成とする。
おもに、イントラシステムでの無停止メンテナンスのための環境を想定している。

#方式
メモリ上のセッションをTCP通信で他のサーバに共有する。
他にもセッション情報をDBに格納する方式があるが、Tomcatの場合、
リアルタイムにDBに格納できない、また、メモリ上のセッションを優先して使用するので、
アクセス先が切り替わった際、セッションが古い状態に戻ってしまうことがあり実用的ではない。

#構成
ロードバランサ apache
アプリケーションサーバ tomcat2台

#手順
■ XAMPPサイトからバイナリzipをダウンロードし、ドライブルートに展開(apache単体のwindowsバイナリが配布されていないため)

■ tomcatのサイトからバイナリzipをダウンロードしtomcat1, tomcat2の2つのフォルダに展開

■ tomcat1/conf/server.xmlの以下の設定を書き換え

> シャットダウンポートを閉鎖

```xml:before
<Server port="8005"
```
```xml:after
<Server port="-1"
```

> httpポートとリダイレクトポートを重複しないよう変更

```xml:before
    <Connector port="8080"
               connectionTimeout="20000"
               redirectPort="8443" />
```
```xml:after
    <Connector port="18080"
               connectionTimeout="20000"
               redirectPort="18443" />
```

> AJPポートとリダイレクトポートを重複しないよう変更

```xml:before
    <Connector port="8009" protocol="AJP/1.3" redirectPort="8443" />
```
```xml:after
    <Connector port="18009" protocol="AJP/1.3" redirectPort="18443" />
```

> route値を追加

```xml:before
    <Engine name="Catalina" defaultHost="localhost">
```
```xml:after
    <Engine name="Catalina" defaultHost="localhost" jvmRoute="r1">
```

> クラスタ有効化

```xml:before
    <!--
      <Cluster className="org.apache.catalina.ha.tcp.SimpleTcpCluster"/>
    -->
```
```xml:after
      <Cluster className="org.apache.catalina.ha.tcp.SimpleTcpCluster"/>
```

■ tomcat2/conf/server.xmlの以下の設定を書き換え

> シャットダウンポートを閉鎖

```xml:before
<Server port="8005"
```
```xml:after
<Server port="-1"
```

> httpポートとリダイレクトポートを重複しないよう変更

```xml:before
    <Connector port="8080"
               connectionTimeout="20000"
               redirectPort="8443" />
```
```xml:after
    <Connector port="28080"
               connectionTimeout="20000"
               redirectPort="28443" />
```

> AJPポートとリダイレクトポートを重複しないよう変更

```xml:before
    <Connector port="8009" protocol="AJP/1.3" redirectPort="8443" />
```
```xml:after
    <Connector port="28009" protocol="AJP/1.3" redirectPort="28443" />
```

> route値を追加

```xml:before
    <Engine name="Catalina" defaultHost="localhost">
```
```xml:after
    <Engine name="Catalina" defaultHost="localhost" jvmRoute="r2">
```

> クラスタ有効化

```xml:before
    <!--
      <Cluster className="org.apache.catalina.ha.tcp.SimpleTcpCluster"/>
    -->
```
```xml:after
      <Cluster className="org.apache.catalina.ha.tcp.SimpleTcpCluster"/>
```

■ xampp/apache/conf/httpd.conf の以下の設定を書き換え

> ロードバランサ有効化

```xml:before
#LoadModule proxy_balancer_module modules/mod_proxy_balancer.so
```
```xml:after
LoadModule proxy_balancer_module modules/mod_proxy_balancer.so
```

■xampp/apache/conf/httpd-vhosts.conf の末尾に以下の設定を追加

```apache:add
Listen 12121
NameVirtualHost *:12121
<VirtualHost *:12121>

	#管理画面をプロキシ対象から除外
	ProxyPass /balancer-manager !
	
	#管理画面をローカルホストのみからアクセスできるよう設定
	<Location /balancer-manager>
		SetHandler balancer-manager
		Order Deny,Allow
		Deny from all
		Allow from 127.0.0.1
	</Location>
	
	#エラーページをプロキシ対象から除外
	ProxyPass /sorry.html !
	
	#APサーバがすべて停止しているときの表示ページ
	ErrorDocument 503 /sorry.html
	
	#リバースプロキシとして使用
	ProxyRequests off
	
	#ロードバランスの設定
	ProxyPass / balancer://tomcat/ stickysession=JSESSIONID nofailover=Off timeout=2 maxattempts=1
	
	#リクエスト転送先
	<Proxy balancer://tomcat/>
		BalancerMember ajp://127.0.0.1:18009 keepalive=On retry=2 route=r1 loadfactor=50
		BalancerMember ajp://127.0.0.1:28009 keepalive=On retry=2 route=r2 loadfactor=50
	</Proxy>
</VirtualHost>
```

> 12121番ポート（適当に設定）にアクセスした場合、
18009ポートと28009ポートに半々(loadfactor=50)でリクエストを振り分ける。
セッションができた場合は同じポートに連続して振り分ける(stickysession, route)
2秒間(timeout=2)で2回転送を実施(retry=2)し、200が返ってこない場合は別の転送先に切り替えを1回(nofailover=off, maxattempts=1)実施する
転送先がすべて停止している場合はxampp/htdocs/sorry.htmlを表示(ProxyPass, ErrorDocument)

```xml:sorry.htmlの例
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="utf-8"/>
</head>
<body>
ただいまメンテナンス中です...
</body>
</html>
```

■war内の web.xmlの web-app タグの直下に &lt;distributable/&gt; を追加
単純な動作確認をしたい場合はindex.jsp, web.xmlを以下の内容で作成。(ROOTフォルダは大文字で作成すること)

```jsp:tomcat1/webapps/ROOT/index.jsp
[r1]
<%
  Integer n = (Integer)session.getAttribute("count");
  n = n == null ? 1 : n + 1;
  session.setAttribute("count", n);
%>
<%= n %>
```

```jsp:tomcat2/webapps/ROOT/index.jsp
[r2]
<%
  Integer n = (Integer)session.getAttribute("count");
  n = n == null ? 1 : n + 1;
  session.setAttribute("count", n);
%>
<%= n %>
```

```xml:tomcat1/webapps/ROOT/WEB-INF/web.xml,tomcat2/webapps/ROOT/WEB-INF/web.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee" version="3.1">
    <distributable/>
</web-app>
```

# 確認
■ apacheとtomcat1, tomcat2を起動してブラウザで http://localhost:12121 にアクセス

>
apacheはxampp-controlから起動
tomcatはstartup.batをダブルクリックで起動

ブラウザをリロードすると数値が増えていく
r1が表示されているときにtomcat1を停止するとr2に数値が引き継がれて表示される
tomcat1を起動して、tomcat2を停止するとr1に切り替わる
tomcat1,tomcat2両方停止すると sorry.html が表示される
スティッキーセッションを有効にしているので、一度カウントを開始すると、アクセスできる間は同じサーバにアクセスする

以上