Apacheロードバランサ、Tomcatクラスタ

環境:OS=Windows10Pro

Webサーバ:ApacheHTTPServer2.4

APサーバ:Tomcat10(2台)

Apacheにロードバランサ設定を行い、2台のクラスタ化されたTomcatと連携する。

更に、Tomcat1台づつ停止してもSessionが引き継がれる事を確認する。

1.Tomcatインストール

(Tomcatインストール方法参照

・Tomcatを2つインストールする。(2つのインスタンスにしてインストール)

・Tomcat101のserver.xmlを修正

■server.xml


<Connector port=”8080″ protocol=”HTTP/1.1″ connectionTimeout=”20000″ redirectPort=”8443″ />

<Connector port=”18080” protocol=”HTTP/1.1″ connectionTimeout=”20000″ redirectPort=”18443” />


※デフォルトではコメントになっているのでコメントを外す
<Connector protocol=”AJP/1.3″ address=”::1″ port=”8009″ redirectPort=”8443″ />

<Connector protocol=”AJP/1.3″ address=”::1″ port=”18009” redirectPort=”18443” />


<!–
<Cluster className=”org.apache.catalina.ha.tcp.SimpleTcpCluster”/>
–>
このコメントの下に以下を追加
<Cluster className=”org.apache.catalina.ha.tcp.SimpleTcpCluster”
channelSendOptions=”6″>

<Manager className=”org.apache.catalina.ha.session.BackupManager”
expireSessionsOnShutdown=”false”
notifyListenersOnReplication=”true”
mapSendOptions=”6″/>
<!–
<Manager className=”org.apache.catalina.ha.session.DeltaManager”
expireSessionsOnShutdown=”false”
notifyListenersOnReplication=”true”/>
–>
<Channel className=”org.apache.catalina.tribes.group.GroupChannel”>
<Membership className=”org.apache.catalina.tribes.membership.McastService”
address=”228.0.0.4″
port=”45564″
frequency=”500″
dropTime=”3000″/>
<Receiver className=”org.apache.catalina.tribes.transport.nio.NioReceiver”
address=”auto”
port=”5000″
selectorTimeout=”100″
maxThreads=”6″/>

<Sender className=”org.apache.catalina.tribes.transport.ReplicationTransmitter”>
<Transport className=”org.apache.catalina.tribes.transport.nio.PooledParallelSender”/>
</Sender>
<Interceptor className=”org.apache.catalina.tribes.group.interceptors.TcpFailureDetector”/>
<Interceptor className=”org.apache.catalina.tribes.group.interceptors.MessageDispatchInterceptor”/>
<Interceptor className=”org.apache.catalina.tribes.group.interceptors.ThroughputInterceptor”/>
</Channel>

<Valve className=”org.apache.catalina.ha.tcp.ReplicationValve”
filter=”.*\.gif|.*\.js|.*\.jpeg|.*\.jpg|.*\.png|.*\.htm|.*\.html|.*\.css|.*\.txt”/>

<Deployer className=”org.apache.catalina.ha.deploy.FarmWarDeployer”
tempDir=”/tmp/war-temp/”
deployDir=”/tmp/war-deploy/”
watchDir=”/tmp/war-listen/”
watchEnabled=”false”/>

<ClusterListener className=”org.apache.catalina.ha.session.ClusterSessionListener”/>
</Cluster>

・Tomcat102のserver.xmlを修正

■server.xml


<Connector port=”8080″ protocol=”HTTP/1.1″ connectionTimeout=”20000″ redirectPort=”8443″ />

<Connector port=”28080” protocol=”HTTP/1.1″ connectionTimeout=”20000″ redirectPort=”28443” />


※デフォルトではコメントになっているのでコメントを外す
<Connector protocol=”AJP/1.3″ address=”::1″ port=”8009″ redirectPort=”8443″ />

<Connector protocol=”AJP/1.3″ address=”::1″ port=”28009” redirectPort=”28443” />


<!–
<Cluster className=”org.apache.catalina.ha.tcp.SimpleTcpCluster”/>
–>
このコメントの下に以下を追加
<Cluster className=”org.apache.catalina.ha.tcp.SimpleTcpCluster”
channelSendOptions=”6″>

<Manager className=”org.apache.catalina.ha.session.BackupManager”
expireSessionsOnShutdown=”false”
notifyListenersOnReplication=”true”
mapSendOptions=”6″/>
<!–
<Manager className=”org.apache.catalina.ha.session.DeltaManager”
expireSessionsOnShutdown=”false”
notifyListenersOnReplication=”true”/>
–>
<Channel className=”org.apache.catalina.tribes.group.GroupChannel”>
<Membership className=”org.apache.catalina.tribes.membership.McastService”
address=”228.0.0.4″
port=”45564″
frequency=”500″
dropTime=”3000″/>
<Receiver className=”org.apache.catalina.tribes.transport.nio.NioReceiver”
address=”auto”
port=”5000″
selectorTimeout=”100″
maxThreads=”6″/>

<Sender className=”org.apache.catalina.tribes.transport.ReplicationTransmitter”>
<Transport className=”org.apache.catalina.tribes.transport.nio.PooledParallelSender”/>
</Sender>
<Interceptor className=”org.apache.catalina.tribes.group.interceptors.TcpFailureDetector”/>
<Interceptor className=”org.apache.catalina.tribes.group.interceptors.MessageDispatchInterceptor”/>
<Interceptor className=”org.apache.catalina.tribes.group.interceptors.ThroughputInterceptor”/>
</Channel>

<Valve className=”org.apache.catalina.ha.tcp.ReplicationValve”
filter=”.*\.gif|.*\.js|.*\.jpeg|.*\.jpg|.*\.png|.*\.htm|.*\.html|.*\.css|.*\.txt”/>

<Deployer className=”org.apache.catalina.ha.deploy.FarmWarDeployer”
tempDir=”/tmp/war-temp/”
deployDir=”/tmp/war-deploy/”
watchDir=”/tmp/war-listen/”
watchEnabled=”false”/>

<ClusterListener className=”org.apache.catalina.ha.session.ClusterSessionListener”/>
</Cluster>

2.ApacheHTTPServerの設定

・httpd.confの末尾に以下を追加する

■httpd.conf

LoadModule access_compat_module modules/mod_access_compat.so
LoadModule proxy_module modules/mod_proxy.so
LoadModule proxy_express_module modules/mod_proxy_express.so
LoadModule lbmethod_byrequests_module modules/mod_lbmethod_byrequests.so
LoadModule lbmethod_bytraffic_module modules/mod_lbmethod_bytraffic.so
LoadModule lbmethod_bybusyness_module modules/mod_lbmethod_bybusyness.so
LoadModule lbmethod_heartbeat_module modules/mod_lbmethod_heartbeat.so
LoadModule proxy_balancer_module modules/mod_proxy_balancer.so
LoadModule proxy_http_module modules/mod_proxy_http.so
LoadModule status_module modules/mod_status.so
LoadModule slotmem_shm_module modules/mod_slotmem_shm.so

ProxyPass / balancer://mybalance/ nofailover=Off timeout=10 maxattempts=1 stickysession=JSESSIONID
ProxyPassReverse / balancer://mybalance/

<Proxy balancer://mybalance/>
BalancerMember http://localhost:18080 keepalive=On loadfactor=10 retry=2
BalancerMember http://localhost:28080 keepalive=On loadfactor=10 retry=2
</Proxy>

ProxyPass /balancer-manager !
<Location /balancer-manager>
SetHandler balancer-manager
Order Deny,Allow
Deny from all
Allow from 192.168  #環境によって変更
</Location>

 

・Apacheの動作確認

Apacheを起動する。起動方法はDos窓から起動する。(エラーの場合、Dos窓にエラーメッセージが出るから)

エラーが無かったらDos窓を終了して、サービスから起動

 

ブラウザからアクセスする

http://192.168.0.14/balancer-manager

これでOK

 

3.Sessionが引き継がれる確認用のJavaアプリを作成する

index.jsp

TopPage.java

CreateSessionPage.java

GetSessionPage.java

PersonSeri.java

web.xml

 

■index.jsp
<%@ page contentType=”text/html;charset=windows-31j”%>
<html>
<head>
<meta http-equiv=”Content-Type” content=”text/html; charset=windows-31j”/>
</head>
<body>
<br>
<form action=’./TopPage’ method=’Post’>
<input type = ‘submit’ value = ‘TopPage’>
</form>
<br>
</body>
</html>
</html>

 

■TopPage.java
import java.io.IOException;
import java.io.PrintWriter;
import javax.servlet.*;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.*;
@WebServlet(name = “TopPage”, urlPatterns = { “/TopPage” })
public class TopPage extends HttpServlet {
private static final String CONTENT_TYPE = “text/html; charset=windows-31j”;
private static final long serialVersionUID = 1L;
public void init(ServletConfig config) throws ServletException {
super.init(config);
}
public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
this.doGet(request, response);
}
public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
response.setContentType(CONTENT_TYPE);
PrintWriter out = response.getWriter();
out.println(“<html>”);
out.println(“<head><title>TopPage</title></head>”);
out.println(“<body>”);
out.println(“<br>”);
out.println(“TopPage”);
out.println(“<br>”);
out.println(“<br>”);
out.println(“<form action=’./CreateSessionPage’ method=’Post’>”);
out.println(“<input type = ‘submit’ value = ‘CreateSessionPage’>”);
out.println(“</form>”);
out.println(“<br>”);
out.println(“<br>”);
out.println(“<form action=’./GetSessionPage’ method=’Post’>”);
out.println(“<input type = ‘submit’ value = ‘GetSessionPage’>”);
out.println(“</form>”);
out.println(“<br>”);
out.println(“<form action=’./index.jsp’ method=’Post’>”);
out.println(“<input type = ‘submit’ value = ‘index.jsp’>”);
out.println(“</form>”);
out.println(“<br>”);
out.println(“</body>”);
out.println(“</html>”);
}
}

 

■CreateSessionPage.java

import java.io.IOException;
import java.io.PrintWriter;
import javax.servlet.*;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.*;
@WebServlet(name = “CreateSessionPage”, urlPatterns = { “/CreateSessionPage” })
public class CreateSessionPage extends HttpServlet {
private static final String CONTENT_TYPE = “text/html; charset=windows-31j”;
private static final long serialVersionUID = 1L;

public void init(ServletConfig config) throws ServletException {
super.init(config);
}

public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
this.doGet(request, response);
}
public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
HttpSession session = request.getSession();

//Sessionはシリアライズ化する
session.setAttribute(“personSeri”, new PersonSeri(“TESTTEST”));
response.setContentType(CONTENT_TYPE);
PrintWriter out = response.getWriter();
out.println(“<!DOCTYPE html>”);
out.println(“<html>”);
out.println(“<head>”);
out.println(“<title></title>”);
out.println(“</head>”);
out.println(“<body>”);
out.println(“<br>”);
out.println(“CreateSessionPage”);
out.println(“<br>”);
out.println(“Session=name1<br>”);
out.println(“<form action=’./GetSessionPage’ method=’Post’>”);
out.println(“<input type = ‘submit’ value = ‘GetSessionPage’>”);
out.println(“</form>”);
out.println(“<br>”);
out.println(“<br>”);
out.println(“<form action=’./TopPage’ method=’Post’>”);
out.println(“<input type = ‘submit’ value = ‘TopPage’>”);
out.println(“</form>”);
out.println(“<br>”);
out.println(“<form action=’./index.jsp’ method=’Post’>”);
out.println(“<input type = ‘submit’ value = ‘index.jsp’>”);
out.println(“</form>”);
out.println(“<br>”);
out.println(“</body>”);
out.println(“</html>”);
}
}

 

■GetSessionPage.java

import javax.servlet.*;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.*;
@WebServlet(name = “GetSessionPage”, urlPatterns = { “/GetSessionPage” })
public class GetSessionPage extends HttpServlet {
private static final String CONTENT_TYPE = “text/html; charset=windows-31j”;
private static final long serialVersionUID = 1L;

public void init(ServletConfig config) throws ServletException {
super.init(config);
}
public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
this.doGet(request, response);
}

public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
response.setContentType(CONTENT_TYPE);
PrintWriter out = response.getWriter();
out.println(“<html>”);
out.println(“<head><title>GetSessionPage</title></head>”);
out.println(“<body>”);
out.println(“<br>”);
out.println(“GetSessionPage”);
out.println(“<br>”);
out.println(“PersonSeri ” + ((PersonSeri)request.getSession().getAttribute(“personSeri”)).getName());
out.println(“<br>”);
out.println(“<br>”);
out.println(“<form action=’./TopPage’ method=’Post’>”);
out.println(“<input type = ‘submit’ value = ‘TopPage’>”);
out.println(“</form>”);
out.println(“<br>”);
out.println(“<form action=’./index.jsp’ method=’Post’>”);
out.println(“<input type = ‘submit’ value = ‘index.jsp’>”);
out.println(“</form>”);
out.println(“<br>”);
out.println(“</body>”);
out.println(“</html>”);
}
}

 

■PersonSeri.java
import java.io.Serializable;
public class PersonSeri implements Serializable {
@SuppressWarnings(“compatibility:-6848355860387642004”)
private static final long serialVersionUID = 1L;
private String name;
public PersonSeri(String name) {
this.name = name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}

 

■web.xml

  <distributable/> ※最後尾に追加する

</web-app>

 

・作成したアプリをTomcat1,2にデプロイする

 

4.動作確認

2台のTomcatを停止→起動→停止を繰り返してSessionが消えない事を確認する

・Tomcat1,2起動

ブラウザからアクセス

http://localhost/Cluster2/CreateSessionPage

・GetSessionPageボタン押下

これはTomcat1,2が起動しているのでSession取れて当たり前

・Tomcat1停止

・TopPageボタン押下→GetSessionPageボタン押下

Sessionが取得できること確認

・Tomcat1起動→Tomcat2停止

・TopPageボタン押下→GetSessionPageボタン押下

Sessionが取得できること確認

 

これでApacheのロードバランサが効いて、Tomcatのクラスタが効いて、Sessionレプリカが効いていることを確認できた