(4). 부하분산(Load Balancing)및 세션공유(Session Clustering)에서 배포하기(Deployments)
1. 어플리케이션 배포 준비
- 디플로이시 Node1, Node2를 순차적으로 반영 하면 Deploy Reload에 의한 세션 중단 없이 서비스가 가능함
2. 어플리케이션 배포 준비
- 세션 복제 기준 (replication-trigger)
- ACCESS : HTTP 요청이 있을 때 마다 session이 변경된 것으로 간주
- SET : setAttribute()시 세션이 변경된 것으로 간주
- SET_AND_NON_PRIMITIVE_GET : setAttribute()뿐만 아니라 변경 가능한 object에 대한 getAttribute()시 세션이 변경된 것으로 간주. 디폴트 설정
- SET_AND_GET : setAttribute()뿐만 아니라 getAttribute()시에도 세션이 변경된 것으로 간주
- 세션 복제 단위(replication-granularity)
- SESSION : 세션을 통째로 복제
- ATTRIBUTE : 세션에서 변경된 attribute만을 복제
- FIEDLD : attribute object의 변경된 필드만을 복제
- INSTANCE : 세션의 변경 사항을 즉시 복제
- INTERVAL : 세션을 일정시간으로 복제
- REPL_SYNC : 동기방식으로 ACK를 받을때까지 기다린다.
- REPL_ASYNC : 비동기 방식으로 큐에넣어두고 별도의 쓰레드에서 전송을 처리한다.
3. 배포 구조 : jboss-deployment-structure.xml
<?xml version="1.0" encoding="UTF-8"?>
<jboss-deployment-structure>
<deployment>
<exclude-subsystems>
<subsystem name="logging" />
</exclude-subsystems>
<exclusions>
<module name="org.apache.commons.logging" />
<module name="org.slf4j" />
<module name="org.slf4j.ext" />
<module name="org.slf4j.impl" />
<module name="org.apache.log4j" />
<module name="org.slf4j.jcl-over-slf4j" />
<module name="org.apache.log4j" />
<module name="org.jboss.logging"/>
<module name="org.jboss.logging.jul-to-slf4j-stub"/>
<module name="org.jboss.logmanager"/>
<module name="org.jboss.log4j.logmanager"/>
<module name="org.jboss.as.mail"/>
</exclusions>
</deployment>
</jboss-deployment-structure>
4. 기본 속성 : jboss-web.xml
<?xml version="1.0" encoding="UTF-8"?>
<jboss-web xmlns="http://www.jboss.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation=" http://www.jboss.com/xml/ns/javaee http://www.jboss.org/j2ee/schema/jboss-web_5_1.xsd">
<server-instance>default-server</server-instance>
<context-root>/</context-root>
<virtual-host>MyWeb-Host</virtual-host>
<max-active-sessions>60</max-active-sessions>
<replication-config>
<cache-name>web</cache-name>
<replication-trigger>ACCESS</replication-trigger>
<replication-granularity>SESSION</replication-granularity>
<use-jk>true</use-jk>
<snapshot-mode>INSTANT</snapshot-mode>
</replication-config>
<passivation-config>
<use-session-passivation>false</use-session-passivation>
<passivation-min-idle-time>60</passivation-min-idle-time>
<passivation-max-idle-time>600</passivation-max-idle-time>
</passivation-config>
</jboss-web>
- 세션 복제 기준 (replication-trigger)
- ACCESS : HTTP 요청이 있을 때 마다 session이 변경된 것으로 간주
- SET : setAttribute()시 세션이 변경된 것으로 간주
- SET_AND_NON_PRIMITIVE_GET : setAttribute()뿐만 아니라 변경 가능한 object에 대한 getAttribute()시 세션이 변경된 것으로 간주. 디폴트 설정
- SET_AND_GET : setAttribute()뿐만 아니라 getAttribute()시에도 세션이 변경된 것으로 간주
- 세션 복제 단위(replication-granularity)
- SESSION : 세션을 통째로 복제
- ATTRIBUTE : 세션에서 변경된 attribute만을 복제
- FIEDLD : attribute object의 변경된 필드만을 복제
- INSTANCE : 세션의 변경 사항을 즉시 복제
- INTERVAL : 세션을 일정시간으로 복제
- REPL_SYNC : 동기방식으로 ACK를 받을때까지 기다린다.
- REPL_ASYNC : 비동기 방식으로 큐에넣어두고 별도의 쓰레드에서 전송을 처리한다.
5. WEB설정 : web.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="java.sun.com/xml/ns/javaee"
xmlns:xsi="w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="java.sun.com/xml/ns/javaee java.sun.com/xml/ns/javaee/web-app_3_0.xsd" version="3.0">
<display-name>MyWeb-main</display-name>
<distributable/>
<listener>
<listener-class>ch.qos.logback.classic.servlet.LogbackServletContextListener</listener-class>
</listener>
<listener>
<listener-class>org.springframework.web.util.Log4jConfigListener</listener-class>
</listener>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<context-param>
</context-param>
<servlet-mapping>
</servlet-mapping>
<filter>
</filter>
<filter-mapping>
</filter-mapping>
<jsp-config>
</jsp-config>
<welcome-file-list>
</welcome-file-list>
</web-app>
- 세션 복제를 설정하려면 : <web-app> <distributable/> </web-app> distributable가 필수로 설정 되어있어야 한다
6. 세션공유(Session Clustering) 테스트 하기 : session_tracking.jsp
1. 테스트 JSP 페이지
<%@ page session="true" %>
<%@ page import="java.util.*"%>
<html>
<head><title>Session Tracking Page</title>
<meta charset="utf-8">
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<meta name="viewport" content="width=device-width, user-scalable=no , initial-scale=1.0 , minimum-scale=1.0 , maximum-scale=1.0">
</head>
<body>
<div style="background-color: #efefef; width: 90%; margin-left: auto; margin-right: auto; padding: 10px; border-radius: 20px;">
<h1>Session Tracking Page</h1>
Session tracking with JSP is easy Test.....
<hr>
<%
// =============================================
// 01. Get/Set the session data value
// =============================================
Integer ival = (Integer)session.getValue("counter");
if(ival == null) ival = new Integer(1);
else ival = new Integer (ival.intValue() + 1);
session.putValue ("counter", ival);
session.setMaxInactiveInterval(3600*4380); // Keep for a month
// =============================================
// 02. Get the Server(Node) Name
// =============================================
String cookieJSESSIONID = null;
String sessionID = null;
String ServerNodeID1 = null;
String ServerNodeID2 = null;
Cookie[] cookies = request.getCookies();
if(cookies != null)
{
for(Cookie cookie : cookies)
{
if(cookie.getName().equals("JSESSIONID")) cookieJSESSIONID = cookie.getValue();
}
}
cookieJSESSIONID = cookieJSESSIONID!=null ? cookieJSESSIONID : "";
sessionID = session.getId();
ServerNodeID1 = cookieJSESSIONID.substring(cookieJSESSIONID.indexOf(".") + 1);
ServerNodeID2 = sessionID.substring(sessionID.indexOf(".") + 1);
%>
<br>
<h4 style="margin: 0px;">Server(Node) Name1 : <font color=red><%=ServerNodeID1 %></font> </h4>
<p style="margin: 0px;font-size: 0.7rem;"> - Cookie [ JSESSIONID ] : <%=cookieJSESSIONID%></p>
<br>
<h4 style="margin: 0px;">Server(Node) Name2 : <font color=red><%=ServerNodeID2 %></font> </h4>
<p style="margin: 0px;font-size: 0.7rem;"> - Session [ sessionID ] : <%=sessionID%></p>
<br>
<hr>
You have hit this page <font color=red><b><%= ival %></b></font> times.<br>
<%
out.println("Your Session ID is <b>[ "+ServerNodeID1+" ] " + sessionID + "</b><br>");
System.out.println("[ "+ServerNodeID1+" ] session=" + sessionID + ", counter=" + ival);
%>
<br>
</div>
</body>
</html>
2. 테스트 진행(최초 접속) : 쿠키(JSESSIONID)에 최초 접속 워커(Node)를 저장
[세션쿠키 변수] (중요함) : worker.wlb_common.session_cookie =JSESSIONID
- 세션 공유가 정상 작동 하려면 필수 설정 되어야 합니다.
- jvmRoute에서 어느서버로 라우팅 할지를 결정 할때 JSESSIONID 변수를 읽어서 처리 하기 때문에 설정이 안되거나 잘못 설정 되어 있으면 세션공유(Session Clustering)가 정상 작동 되지 않습니다.
- session cookie name 정의 규칙 : [ JSESSIONID(기본), JSESSIONID_INTL(세계공용), JSESSIONID_US(미국), JSESSIONID_CUSTOM(사용자정의) ]
- session_cookie=JSESSIONID_CUSTOM : Round-Robin으로만 작동됨
- session_cookie=JSESSIONID : 최초접속 서버로 유지됨
[세션 라우트 유지] : worker.wlb_common.sticky_session =True
- sticky session은 mod_jk에서 세션을 생성할 때 사용자 쿠키에 기록되는 세션 아이디를 이용하여 구분하여 보내며 기존의 세션 아이디 뒤에 jvmRoute ID를 붙혀 어느서버로 갈지 결정을 한다
- JSESSIONID 예시 : pePoybQiCxZZHx8aed6x1oCeFptZ4hmKAzE92WTe.S01-Node01 (세션ID.노드ID)
3. 테스트 진행(sticky_session) : 같은 세션에 대한 요청을 같은 워커(Node)로 라우팅 함
- [세션 유지 테스트] : Jboss( S01-Node01 ) 서버를 셧다운 하고, 페이지를 새로고침 한다
4. 테스트 진행(sticky_session) : 최조 접속 노드가 Shutdown 된경우 다른 노드로 세션을 클러스터링
- [세션 유지 테스트] : Jboss( S02-Node01 )서버로 라우트가 정상적으로 이루어진다 (세션은 그대로 유지) [ S01-Node01 -> S02-Node01 ]