내용 목차
본 장에서는 세션 서버에 대한 개념과 설정 방법에 대해 설명한다.
세션 서버는 클라이언트의 세션 데이터를 관리하거나 백업하는 데 사용된다. 그 중에서도 특히 여러 웹 서버들과 서블릿 엔진들이 서로 클러스터링된 환경에서 세션 데이터를 관리하고자 할 때 유용하다. JEUS에서는 세션 데이터의 관리 방식에 따라 크게 2가지의 세션 서버를 제공한다.
하나는 모든 세션 데이터를 한곳에 집중하여 관리하는 중앙 세션 서버이고, 다른 하나는 세션 데이터들을 여러 컨테이너로 골고루 분산하여 관리하는 분산 세션 서버이다. 중앙 세션 서버의 경우 세션 서버 자체가 JEUS Manager에서 관리되며, 분산 세션 서버의 경우는 엔진 컨테이너에서 각각 관리된다.
세션 서버들의 모든 사용법을 알기 위해서는 “JEUS Web Container 안내서”의 “제2장 웹 컨테이너”도 함께 참고한다.
본 절에서는 JEUS 서버의 관점에서의 중앙 세션 서버에 대한 설명한다. 중앙 세션 서버는 JEUS Manager에서 운영된다.
간단히 세션 서버는 JEUS에서 세션 객체를 저장하는 곳이다.
세션 객체는 서블릿 API의 HTTP 세션 객체를 나타낸다. HTTP 세션같은 객체는, 상태 유지가 안 되는 프로토콜인 HTTP 요청을 임시 데이터와 매핑한다. 그래서 이 임시 데이터를 통해서 클라이언트를 구별한다. 이렇게 함으로써 WAS는 작업 중인 클라이언트를 다른 클라이언트와 구분할 수 있으며, 이전에 작업한 내용을 기억할 수 있다. 이런 “Session Tracking”은 웹 사이트에서 가장 중요한 부분이다.
그러나 문제는 HTTP 세션 객체는 그 세션이 처음 생성된 서블릿 엔진에만 저장된다는 것이다. 이는 여러 서블릿 엔진들로 클러스터링 환경을 구성했을 경우 세션을 처음 생성한 서블릿 엔진에게 해당 클라이언트의 모든 요청을 보내야 한다는 의미이다. 그렇지만 항상 특정 서블릿 엔진으로 요청이 간다고는 볼 수 없다. 예를 들어서 웹 서버가 세션 라우팅을 지원하지 않거나 서블릿 엔진이 내부 에러로 인해 갑자기 종료(Down)될 경우 세션 객체를 잃어버리게 되기 때문이다.
중앙 세션 서버는 세션 데이터들을 한 곳에 모아서 관리한다. 즉, 어떤 클라이언트를 위한 세션 객체나 특정 서블릿 엔진에서 생성된 것도 모두 중앙 세션 서버를 이용하는 것이다. 이는 2가지의 이점이 있다.
첫째는 중앙 세션 서버를 사용함으로써 더 이상 웹 서버의 세션 라우팅이 필요없다.
둘째는 중앙 세션 서버를 사용하고, 백업용 중앙 세션 서버를 하나 더 사용하여 세션 데이터를 백업함으로써 시스템이 더욱 안정화된다.
이로써 서블릿 엔진이 다운이 되더라도 안전하게 세션을 유지할 수 있다.
서블릿 엔진과 관련된 세션 서버의 더 자세한 사용 방법이나 Session Tracking에 관한 내용은 “JEUS Web Container 안내서”의 “제5장 Session Tracking”을 참고한다.
중앙 세션 서버는 JEUS 웹 컨테이너와 연결하여 운영되며, 웹 컨테이너에 있는 클라이언트의 세션을 라우팅하거나 백업하는 기능을 제공한다. 중앙 세션 서버는 Session Server, Session Manager, Backup Manager, Backup Session Server, Session Cache Memory, Session Storage 등 6가지 파트로 되어있다.
다음 그림은 하나의 중앙 세션 서버에 대한 구조이다. 여러 개의 서브 컴포넌트로 구성된 것을 확인할 수 있다.
중앙 세션 서버의 서브 컴포넌트는 다음과 같다.
각 Session Server에는 하나의 Session Manager가 존재한다. 이는 세션 데이터를 저장하거나 요청에 의해 그 값을 가져오는 역할을 한다. 웹 컨테이너는 이 Session Manager에 연결을 맺는다.
Cached session(Session Cache Memory)
활성화되어 있거나 한 번 사용된 세션 객체는 빠른 사용을 위해서 이곳에 저장된다.
세션 데이터를 다른 백업용 중앙 세션 서버에 백업할 때 사용된다. 백업 체크는 환경 파일에 설정된 “check-to”의 시간 단위로 이루어진다(“to”는 타임아웃(Timeout)을 의미한다).
일반적인 중앙 세션 서버와 같으나 세션 데이터의 백업용으로 설정한 중앙 세션 서버이다.
세션의 사용 빈도가 적은 세션을 위주로 세션 데이터를 다른 저장소에 저장할 때 사용된다.
Storage 공간으로는 하드 드라이브를 사용한다. Session Storage의 세션 객체는 활성화되지 않은 것으로 간주된다. Storage 기능을 사용할 경우 관리자가 지정한 이름을 사용하나, 지정하지 않았을 경우에는 기본적으로 <node-name>1.fdb라는 이름으로 파일을 가진다.
세션 데이터는 “passivationTO”가 경과되면 Session Cache Memory로부터 비활성화되어 Session Storage에 저장되고 “removalTO”가 경과되면 영원히 삭제된다.
웹 컨테이너는 중앙 세션 서버와 연결된다(“JEUS Web Container 안내서”의 “제2장 웹 컨테이너” 참조).
한 번 연결할 때 웹 컨테이너는 세션 객체가 새로 생성되거나 수정된 세션으로 판단되면 중앙 세션 서버에 세션 객체를 저장하거나 업데이트한다. 그리고 클라이언트의 요청이 들어올 때마다 저장소로부터 세션 객체를 가지고 온다.
세션의 setAttribute, removeAttribute, setMaxInactivateInterval operation이 발생했을 때 "수정된 세션"으로 판단한다(<check-level>의 값 "set"). 단, 이런 operation이 없을지라도 세션 attribute의 object 변경을 "수정된 세션"으로 감지하고 싶을 경우 세션 서버 설정 중 <check-level>의 값을 "modified"로 하면 된다. 또한 모든 세션을 항상 서버로 업데이트하려면 <check-level>의 값을 "all"로 설정한다. 자세한 사항은 “10.2.2. 중앙 세션 서버의 설정”을 참고한다.
중앙 세션 서버를 가지고 있는 JEUS Manager 또한 중앙 세션 서버를 사용할 JEUS 간에 JEUS Manager 클러스터링을 설정하면 중앙 세션 서버 간에도 자동으로 클러스터링이 형성된다. 이렇게 클러스터링된 여러 서버들 안에서는 세션 데이터를 함께 사용할 수 있다.
중앙 세션 서버는 크게 primary 타입과 backup 타입이 존재하며 클러스터링 환경에서 오직 하나씩만 존재 가능하다. primary 타입과 backup 타입은 클러스터링 환경에서 서로 간에 세션 객체들을 백업, recovery하며 장애가 발생하는 경우 각 세션 서버 타입의 역할에 따라 웹 컨테이너의 서비스가 원활히 유지되도록 동작한다.
세션 클러스터링을 원하는 경우 JEUS 매니저의 클러스터링을 해야 한다는 것은 반드시 명심해야 한다. JEUS 매니저 클러스터링에 대해서는 “제4장 JEUS 클러스터링”을 참고한다.
여러 웹 컨테이너들이 하나의 중앙 세션 서버와 연결되고 세션의 크기 또한 큰 경우 많은 세션들이 한곳의 중앙 세션 서버로 집중되기 때문에 메모리의 부담이 커질수 있다. 이를 방지하기 위해 passivation 정책을 다음과 같이 사용한다.
passivationTO의 주기
메모리에 Cache된 세션을 Storage로 옮긴다.
removalTO의 주기
메모리에 Cache된 세션을 삭제한다.
-Djeus.sessionserver.memory.max 옵션
메모리에 저장될 세션의 최대 크기를 지정한다.
예를 들어 대략 100MB만을 저장하고 싶을 경우 JEUS 실행 스크립트에 다음과 같이 추가한다.
-Djeus.sessionserver.memory.max=100m
기본값은 -1이며, 이 경우 제한이 없다(단위는 MB는 "m", KB는 "k"를 사용하며 suffix가 없을 경우 byte 단위로 취급한다).
-Djeus.sessionserver.memory.passivationratio 옵션
위에서 지정한 max 크기에 도달했을 경우 상위 몇 퍼센트를 passivation할지를 결정한다.
예를 들어 상위 20%의 세션들을 passivation할 경우 JEUS 실행 스크립트에 다음과 같이 추가한다.
-Djeus.sessionserver.memory.passivationratio=0.2
기본값은 0.2이며, 값은 0보다 크고 1보다 작아야 하며 "-Djeus.sessionserver.memory.max"의 값이 설정되어 있을 경우(-1이 아닌 경우)만 의미있다.
-Djeus.sessionserver.memory.enablegc 옵션
위에서 지정한 max 크기에 도달했을 경우 강제로 gc를 시킬지를 결정한다. (기본값: false)
"-Djeus.sessionserver.memory.max"의 값이 설정되어 있을 경우(-1이 아닌경우)에만 의미있다.
본 절에서는 중앙 세션 서버의 설정에 대해서 설명한다. 기본적으로 노드 클러스터링을 했을 경우에 대한 세션 서버의 설정과 노드 클러스터링을 하지 않았을 경우의 설정에 대해서 설명한다.
JEUS 웹 컨테이너에서 중앙 세션 서버를 사용하기 위한 설정 방법은 “JEUS Web Container 안내서”의 “제2장 웹 컨테이너”를 참고한다.
중앙 세션 서버는 JEUSMain.xml 파일의 <node> 태그 안에 하나만 존재해야 한다.
다음은 노드 'johan'과 'johan1'이 노드 클러스터링을 통한 Session Clustering을 구성한 예제이다.
[예 10.1] 중앙 세션 서버 기본 설정 : <<JEUSMain.xml>>
<jeus-system> . . . <node> <name>johan</name> . . . <session-server> <type>primary</type> <thread-pool> <min>10</min> <max>20</max> </thread-pool> <resolution>30000</resolution> <connect-timeout>60000</connect-timeout> <read-timeout>60000</read-timeout> <passivation-to>1800000</passivation-to> <removal-to>3600000</removal-to> <check-to>20000</check-to> <backup-trigger>500</backup-trigger> <check-level>set</check-level> <file-db-path>c:\sessiondata</file-db-path> <file-db-name>sessiondata</file-db-name> <min-hole>2000</min-hole> <packing-rate>0.8</packing-rate> <recovery-mode>active</recovery-mode> </session-server> . . . </node> <node> <name>johan1</name> . . . <session-server> <type>backup</type> <thread-pool> <min>10</min> <max>20</max> </thread-pool> <resolution>30000</resolution> <connect-timeout>60000</connect-timeout> <read-timeout>60000</read-timeout> <passivation-to>1800000</passivation-to> <removal-to>3600000</removal-to> <check-to>20000</check-to> <backup-trigger>500</backup-trigger> <file-db-path>c:\sessiondata</file-db-path> <file-db-name>sessiondata</file-db-name> <min-hole>2000</min-hole> <packing-rate>0.8</packing-rate> <recovery-mode>active</recovery-mode> </session-server> . . . </node> . . . </jeus-system>
다음은 설정 태그에 대한 설명이다.
노드 클러스터링을 했을 경우 중앙식 세션 서버의 설정에 대해서 설명했다. 세션 클러스터링을 할 때 노드 클러스터링을 권장하고 있지만, 노드 클러스터링을 하지 않았을 경우에도 중앙식 세션 서버를 사용할 수 있다. 노드 클러스터링을 하지 않았을 경우에 중앙식 세션 서버의 설정은 다음과 같다.
[예 10.1]과 거의 비슷하지만 차이점은 <node>가 JEUSMain.xml에 하나만 존재한다는 것과 <replicated-server>를 설정하는 것이다.
[예 10.2] 노드 클러스터링과 세션 클러스터링 설정 : <<JEUSMain.xml>>
<jeus-system> . . . <node> <name>johan</name> . . . <session-server> <thread-pool> <min>10</min> <max>20</max> </thread-pool> <resolution>30000</resolution> <connect-timeout>60000</connect-timeout> <read-timeout>60000</read-timeout> <passivation-to>1800000</passivation-to> <removal-to>3600000</removal-to> <check-to>20000</check-to> <backup-trigger>500</backup-trigger> <check-level>set</check-level> <file-db-path>c:\sessiondata</file-db-path> <file-db-name>sessiondata</file-db-name> <min-hole>2000</min-hole> <packing-rate>0.8</packing-rate> <recovery-mode>active</recovery-mode> <replicated-server>johan1</replicated-server> </session-server> . . . </node> . . . </jeus-system>
다음은 설정 태그에 대한 설명이다.
태그 | 설명 |
---|---|
<relication-server> | 노드 클러스터링 상태가 아닐 때 현재 세션의 replication 세션 서버의 JEUS 노드 이름을 설정한다. replication 서버라고 하면 현재 세션 서버의 백업 서버를 의미한다. 설정된 JEUS 노드 이름은 vhost.properties에 등록되어 있어야 한다. |
<replicated-server>에 설정되는 JEUS 노드 이름은 다음과 같이 vhost.properties에 설정되어야 한다.
jeus.vhost.enabled=true johan1=yyy.yyy.yyy.yyy:10004
중앙 세션 서버를 사용하기 위해서는 하나 이상의 웹 컨테이너가 존재해야 한다. 이의 설정 방법은 “JEUS Web Container 안내서”의 “제2장 웹 컨테이너”를 참고한다.
본 절에서는 중앙 세션 서버의 성능을 향상시키기 위한 튜닝 방법에 대해서 설명한다.
최고의 성능을 위해 중앙 세션 서버를 설정할 때 다음을 주의한다.
resolution을 증가시키면 메모리는 좀 더 소비하지만 성능을 증가시킬 수 있다. 자세한 내용은 “10.2.2. 중앙 세션 서버의 설정”을 참고한다.
"클라이언트와 중앙 세션 서버의 관계"에서 언급된 <check-level>의 값을 "set"으로 사용한다.
"modified"의 경우 추가적으로 세션의 변경을 엄격하게 검사하는 부하가 있으며 "all"의 경우 자주 중앙 세션 서버로 업데이트하는 부하가 있다.
"Session Manager의 메모리 관리"에서 언급된 "-Djeus.sessionserver.memory.max" 옵션을 사용하지 않는다. 이 옵션을 사용할 경우 메모리에 있는 세션들의 크기를 검사하여, 검사 결과에 따라 추가적인 세션 passivation이 일어날 수 있기 때문이다.
성능을 향상 시키기 위해서는 passivation 타임아웃 값을 좀 더 크게 설정한다. 그러나 이렇게 하면 시스템 메모리를 많이 소모하게 한다.
check 타임아웃과 backup trigger에 설정값을 크게 설정한다. 그러면 backup 에 대한 호출이 적어지면서 시스템이 빨라진다. 이 방식은 백업 기능을 훨씬 적게 사용한다.
기존에 사용했던 JEUS 5의 세션 서버 설정과 JEUS6의 새로운 세션 서버 설정을 비교하여 변경된 부분을 위에서 예제로 소개했던 노드 'johan'과 'johan1'의 세션 클러스터링 구성을 예로 설명한다.
다음은 JEUS 5에서의 설정 방법이다.
[예 10.3] 노드 johan : <<JEUSMain.xml>>
<jeus-system> . . . <node> <name>johan</name> . . . <session-server> . . . <!-- session-manager tag가 존재 --> <session-manager> <!-- 세션 서버 이름을 명시 --> <name>Session1</name> <!-- 백업을 지정 --> <backup-name>Session2</backup-name> . . . </session-manager> </session-server> . . . </node> . . . </jeus-system>
[예 10.4] 노드 johan1 : <<JEUSMain.xml>>
<jeus-system> . . . <node> <name>johan1</name> . . . <session-server> . . . <!-- session-manager tag가 존재 --> <session-manager> <!-- 세션 서버 이름을 명시 --> <name>Session2</name> <!-- 백업을 지정 --> <backup-name>Session1</backup-name> . . . </session-manager> </session-server> . . . </node> . . . </jeus-system>
[예 10.5] 각 노드들의 웹 컨테이너 공통 : <<WEBMain.xml>>
<web-container> . . . <session-cluster> . . . <session-server> <!-- primary type 세션 서버를 지정 --> <server-name>Session1</server-name> <connect-timeout>60000</connect-timeout> <read-timeout>60000</read-timeout> <!-- backup type 세션 서버를 지정 --> <backup-server-name>Session2</backup-server-name> </session-server> </session-cluster> . . . </web-container>
이 외에 모든 jeus 스크립트 및 <command-option>에 다음과 같이
설정한다.
-Djeus.sessionmgr.Session1=johan
-Djeus.sessionmgr.Session2=johan2
다음은 JEUS 6에서의 설정 방법이다.
[예 10.6] 노드 johan과 johan1의 공통 : <<JEUSMain.xml>>
<jeus-system> . . . <node> <name>johan</name> . . . <session-server> <!-- JEUS5 <session-manager>아래의 항목들을 대부분 바로 사용 --> <!-- 새로 추가 됨. 세션 서버 type 명시 --> <type>primary</type> <!-- JEUS5의 -D옵션이 xml로 바뀜, optional --> <check-level>set</check-level> <!-- 새로 추가됨, optional --> <recovery-mode>active</recovery-mode> . . . </session-server> . . . </node> <node> <name>johan1</name> . . . <session-server> <!-- JEUS5 <session-manager>아래의 항목들을 대부분 바로 사용 --> <!-- 새로 추가 됨. 세션 서버 type 명시 --> <type>backup</type> <!-- 새로 추가됨, optional --> <recovery-mode>active</recovery-mode> . . . </session-server> . . . </node> . . . </jeus-system>
JEUS 5 설정 중 <server-name>, <backup-server-name>의 설정이 없어지고 대신 세션 서버의 <type>만 설정한다.
JEUS 5 설정 중 <session-manager>의 tag가 없어지고 상위 tag와 합쳐졌다.
JEUS 5 설정 중 WEBMain.xml에 설정하던 부분이 없어졌다.
JEUS 5 설정 중 "-Djeus.sessionmgr.세션 서버이름=노드정보"를 추가할 필요가 없다.
JEUS 6에서는 JEUSMain.xml의 정보를 클러스터링하고자 하는 노드들끼리 동일하게 공유한다.
JEUS 6에서는 추가적으로 세션 클러스터링에 참여하길 원하는 웹 컨텍스트에 한해 <distributable>을 true로 설정한다. 이에 대한 자세한 설명은 “JEUS Web Container 안내서”의 “2.3.7. Session”을 참고한다.
본 절에서는 중앙 세션 서버와 같은 기능을 제공하는 또 다른 세션 클러스터링 방식인 분산 세션 서버를 소개한다.
분산 세션 서버는 중앙 세션 서버와 같은 세션 클러스터링 기능을 제공하면서 확장성을 개선한 방식이다. 따라서 대규모 클러스터링 환경에서 중앙 세션 서버에 비해 더 나은 성능을 발휘할 수 있다.
분산 세션 서버 방식은 대규모 클러스터링 환경에 적합한 세션 클러스터링 방식이다. 소규모 클러스터링 환경에서는 중앙 세션 서버 방식을, 대규모 클러스터링 환경에서는 분산 세션 서버 방식을 사용할 것을 권장한다. 분선 세션 서버에 대한 자세한 내용은 “JEUS Web Container 안내서”의 “제2장 웹 컨테이너”를 참고한다.
본 절에서는 분산 세션 서버의 기본적인 내용을 설명한다.
분산 세션 서버가 제공하는 기본 기능은 중앙 세션 서버와 동일하다. 여러 서블릿 엔진들로 구성된 클러스터링 환경에서 동일한 클라이언트에서 요청된 일련의 요청들이 특정 서블릿 엔진에서 처리되지 않더라도 세션을 계속 유지해 주는 기능을 제공한다.
기능적인 측면은 중앙 세션 서버와 동일하나 동작 방식이 중앙 세션 서버와 달리 완전 분산식이어서 중앙 세션 서버에 비해 확장성이 더 용이하다.
분산 세션 서버가 가지는 특징을 정리하면 다음과 같다.
여러 개의 서블릿 엔진으로 구성된 클러스터링 환경에서 지속적인 세션 유지가 가능하게 한다.
바로 이전의 요청을 처리하던 서블릿 엔진이 다운되더라도 다른 서블릿 엔진들이 이후의 요청을 처리할 때 세션이 끊기지 않도록 해준다.
분산식 프로토콜을 사용하기 때문에 클러스터링 규모가 커지더라도 확장성이 용이하다.
분산 세션 서버는 세션 객체를 서비스하는 서버가 각각의 서블릿 엔진 또는 각각의 EJB 엔진(웹 컨테이너, EJB 컨테이너)에 분산되어 있는 분산식 구조이다.
다음은 분산 세션 서버 방식을 사용하여 4개의 웹 컨테이너를 세션 클러스터링하는 구조이다.
분산 세션 서버 방식은 클러스터링에 참여하는 모든 컨테이너 내에 독립적인 분산 세션 서버가 존재하고, 이들 분산 세션 서버들이 peer-to-peer로 다른 컨테이너의 분산 세션 서버와 통신하여 지속적인 세션 서비스를 제공한다.
그림에 있는 화살표는 분산 세션 서버 간 소켓 연결을 의미하는데, 보통의 경우 연결이 필요없으며 세션 유지를 위해 다른 컨테이너와 통신할 필요가 있을 경우 연결을 맺고 유지한다. 또한 항상 모든 연결을 맺는것을 의미하는 것이 아닌 다른 모든것과 연결을 맺을 수 있는 "가능성"을 나타내는 그림이다. 장애가 발생하지 않는 한 연결은 보통 하나씩만 가지게 된다.
다음은 웹 컨테이너의 서브 컴포넌트로 동작하는 분산 세션 서버의 내부 구조이다.
컨테이너의 세션 관리를 총괄하는 모듈이다. 로컬 메모리, 파일 및 다른 리모트 분산 세션 서버로부터 세션을 얻어오거나 관리한다.
로컬 웹 컨테이너는 getSession을 통해 Session Manager로부터 사용할 세션 객체를 얻어 온다.
로컬 메모리의 Cached Session, Local File Storage Session(getLocalStorageSession), Remote Session(getRemoteSession)순으로 세션을 얻어온다.
메모리의 Cached Session은 일정주기(passivation 타임아웃)동안 사용하지 않으면 passivateLocal을 통해 파일에 저장되고 메모리에서 삭제된다.
수정된 세션은 리모트 백업이 있을 경우 SCRemoteContainer를 통해 백업 서버로 정해진 다른 웹 컨테이너의 분산 세션 서버로 in-memory 백업된다(backupSession). 이때 파일 storage 설정이 있다면 Local File storage에도 동시에 저장된다.
수정된 세션은 <check-level>에 따라 다르게 적용된다. <check-level>이 "all"일 경우 항상, "get"의 경우 getAttribute, "set"의 경우 setAttribute, removeAttribute, setMaxInactivateInterval의 세션 operation이 발생했을 때 "수정된 세션"으로 판단한다. 자세한 설정은 "분산 세션 서버 기본 설정"을 참조한다.
다른 리모트 웹 컨테이너로부터 migrate 요청이 온다면 로컬 메모리의 Cached Session, Local File storage 순서로 세션을 반환해 준다. 이때 로컬에 존재하는 세션은 지움으로써 ownership을 다른 리모트 분산 세션 서버에게 넘기게 된다.
자신의 분산 세션 서버를 백업으로 선택한 다른 컨테이너의 분산 세션 서버가 주기적으로 전송하는 백업 세션 객체를 관리한다. 이 백업 세션 객체는 원본을 가지고 있는 컨테이너에 장애가 발생한 경우 대신하여 세션을 제공한다.
자신을 백업으로 지정한 리모트 웹 컨테이너가 전송하는 백업 세션을 받아 저장/관리한다(backupSession, getBackupSession).
메모리에 Cached Session은 일정 주기(passivation 타임아웃)동안 사용하지 않으면 passivateBackup을 통해 파일에 저장되고 메모리에서 삭제된다.
backupToRemot는 로컬에서 수정된 세션 객체는 조건이 만족되면 지정된 리모트 분산 세션 서버로 백업된다. 여기서 조건은 2가지가 있다.
첫 번째는 check-to 설정으로 설정된 시간주기로 백업 프로세스가 기동된다.
두 번째는 backup-trigger 설정으로 설정된 개수만큼 수정된 세션 객체가 발생하면 백업 프로세스가 기동된다. check-to와 backup-trigger의 관계는 or(또는)관계이다.
다른 리모트 웹 컨테이너로부터 backup store에 migrate 요청이 온다면 로컬 메모리의Cached Session, Local File Storage 순으로 세션을 반환한다.
리모트 웹 컨테이너에 있는 세션들에 대해서 특정 operation을 할 경우 중재 역할을 해주는 모듈이다.
(예: 리모트 웹 컨테이너로부터의 getSession(), removeSession() 등)
리모트 웹 컨테이너로부터 세션의 특정 operation 요청이 왔을 경우 가장 먼저 요청을 처리 및 분배해 주는 모듈이다.
분산 세션 서버 방식은 세션 라우팅을 기본으로 한다.
<SessionID>.<primary-engine-name>
다음은 분산 세션 서버 방식이 사용하는 세션 Key를 갖는 웹 컨테이너에 사용되는 예제이다.
XXX.johan_servlet_engine1
'XXX'는 <SessionID>를 상징적으로 나타낸 것이다. 실제로 <SessionID>는 이보다 훨씬 긴 random string 형태이다. 'johan_servlet_engine1'은 라우팅 정보를 의미한다. 노드는 johan이고 서블릿의 engine1을 의미한다.
세션 라우팅을 지원하는 웹 서버를 앞단에 배치한다면 정상적인 경우 세션 객체가 존재하는 웹 컨테이너로 요청이 라우팅 될 것이다. 따라서 이러한 경우의 동작 방식은 세션 라우팅에 의한 세션 클러스터링과 동일하다(“JEUS Web Container 안내서”의 “제5장 Session Tracking” 참조).
웹 서버가 세션 라우팅을 지원할 수 없는 상황을 살펴보자. 웹 서버가 세션 라우팅을 지원하더라도 웹 서버에
세션 라우팅 ID에 해당하는 웹 컨테이너로의 연결이 존재하지 않거나 해당 웹 컨테이너에 장애가 발생하여 요청을 전달할 수 없는
경우가 여기에 해당한다. 이러한 경우 웹 서버는 보통 임의로 선택된 다른 웹 컨테이너로 요청을 전달한다. [그림 10.4]에 이러한 상황에서 분산 세션
서버의 동작 방식을 나타내었다.
각 컨테이너는 세션 라우팅에 사용하는 세션 라우팅 ID를 하나씩 부여받는다. ID는 웹 서버에 웹 컨테이너가 접속할 때 웹 컨테이너를 구분하는 구분자로 사용된다. 세션 라우팅 ID는 설정에 의해 자동 생성된다. [그림 10.4]의 3개의 웹 컨테이너는 다음과 같은 세션 라우팅 ID 및 백업이 할당되었다고 가정한다. 실제 백업이 선택되는 과정은 "분산 세션 서버의 백업 서버 선택 방식"을 참고한다.
engine1의 ID : johan_servlet_engine1, 백업 : johan_servlet_engine2
engine2의 ID : johan_servlet_engine2, 백업 : johan_servlet_engine3
engine3의 ID : johan_servlet_engine3, 백업 : johan_servlet_engine4
다음은 [그림 10.4]의 상황에 대한 설명이다.
Request sessionKey값의 세션 라우팅 ID는 engine1 웹 컨테이너의 것이다. 이에 따라 웹 서버는 클라이언트의 요청을 engine1 웹 컨테이너로 전달하는 것을 시도한다. 현재 engine1에 장애가 발생하였으므로 이 시도는 실패한다.
웹 서버는 나머지 2개의 웹 컨테이너 중 하나를 임의로 선택하여 클라이언트 요청을 전달하는 것을 시도한다. 선택된 웹 컨테이너는 engine3이며 이 요청 전달은 성공하였다.
웹 서버로부터 요청을 전달 받은 engine3는 세션 라우팅 ID를 분석한다. 분석 결과 이 요청을 처리할 세션 객체는 engine1에 있으며 engine1이 primary 분산 세션 서버이고 engine2가 backup 분산 세션 서버임을 알게 된다. 먼저 primary 분산 세션 서버가 engine1에 접속하여 세션 객체를 가져오려고 시도한다(primary migration). engine1에 장애가 발생하였으므로 이 시도는 실패한다.
백업 분산 세션 서버인 engine2로 다시 시도한다(backup migration). engine2는 백업한 세션 객체를 engine3로 넘긴다. 성공적으로 세션 객체를 가져온 engine3는 이후 클라이언트의 요청을 처리하여 응답 메시지를 클라이언트에게 보낸다. 이 때 새로운 세션 Key를 작성하여 클라언트에게 보낸다. 이렇게 함으로써 클라이언트의 세션 Key가 변경되고 이 후 요청이 engine3로 오도록 한다. 새로운 세션 Key를 작성할 때는 세션 라우팅 ID부분만 자신의 것으로 치환한다.
중앙 세션 서버와 마찬가지로 분산 세션 서버를 가지고 있는 JEUS Manager 간에 클러스터링을 하면 분산 세션 서버 간에도 클러스터링이 형성된다. 이렇게 되면 세션 데이터를 여러 서버에서 같이 사용할 수 있게 된다. 세션 클러스터링을 원할 경우 분산식에서도 JEUS 매니저의 클러스터링을 해야한다는것은 반드시 명심해야 한다. JEUS 매니저 클러스터링에 대해서는 “제4장 JEUS 클러스터링”을 참고한다.
본 절에서는 분산 세션 서버의 백업 선택 방식에 대해 설명한다.
다음과 같은 기준으로 분산 세션 서버의 백업을 선택한다. 다음 항목의 순서가 선택의 우선순위이다. 각 항목에 관한 설정의 세부사항은 "세부 분산 세션 서버 설정"을 참고한다.
항목 | 설명 |
---|---|
backup-group | 자신의 분산 세션 서버가 선호하는 백업 분산 세션 서버 그룹을 지정할 수 있다. 백업을 선택할 때 이 정보가 가장 우선한다. |
자신과 다른 location | 자신의 분산 세션 서버와는 다른 machine, location에 있는 분산 세션 서버를 백업으로 지정한다. |
최대한 백업의 분산 | 위의 조건이 모두 동일하다면 최대한 적게 백업으로 지정된 분산 세션 서버를 백업으로 선택한다. 백업 분산 세션 서버들이 최대한 분산되어서 선택되도록 하기 위함이다. |
다음 그림과 같이 분산 세션 서버가 세션 클러스터링된 상황을 생각해보자.
A, B, C, X, Y, Z는 분산 세션 서버를 의미한다. 각각이 웹 컨테이너의 서로 다른 서블릿 엔진에 올라간다고 가정하자.
A, X, Y는 WAS1X라는 물리적인 location에 존재한다.
B, C, Z는 WAS2X라는 물리적인 location에 존재한다.
A, B, C는 FinancialServices라는 논리적인 replication group이다.
X, Y, Z는 ConsultingServices라는 논리적인 replication group이다.
FinancialServices와 ConsultingServices은 서로 backup group관계이다. 즉, A, B, C는 backup-group으로 ConsultingServices을 선택했고, X, Y, Z는 backup-group으로 FinancialServices를 선택했다.
그렇다면 A라는 분산 세션 서버의 백업 분산 세션 서버는 어느 것일까?
A의 선호하는 백업 그룹은 ConsultingServices이다. ConsultingServices 그룹에 속하는 분산 세션 서버는 X, Y, Z이다.
X, Y, Z 중에 A와 다른 location에 존재하는 Z가 있다.
따라서 선호하는 백업 그룹 중에 A와 다른 location에 있는 Z가 A의 백업 분산 세션 서버가 된다.
이런 식으로 A ~ Z까지의 백업은 다음과 같이 정해진다.
A ~ Z까지의 백업을 선택하는 과정에서 선택을 누가 먼저 하느냐에 따라 백업으로 선택된 결과도 달라질 수 있다. 따라서 먼저 알파벳 순서로 모든 세션 클러스터링에 참여하는 분산 세션 서버들을 정렬한 후, 그 순서대로 백업 분산 세션 서버를 하나씩 결정하게 된다.
백업을 선택 할 때에는 하나씩만 선택을 하지만 여러 분산 세션 서버가 한 백업 분산 세션 서버를 선택할 수 있다(선택은 하나만 가능, 선택 받는것은 여러 개 가능, primary 분산 세션 서버로부터 backup 분산 세션 서버로의 수학적 함수 관계라 생각하면 된다).
A → Z
B → X (X, Y가 모두 선택 가능하지만 알파벳 순서에 따라 X를 선택한다.)
C → Y (backup group과 location의 정보로 X, Y가 결정이 되지만 X는 이미 선택되어졌으므로 최대한의 분산을 위해 Y가 선택된다.)
X → B
Y → C
Z → A
분산 세션 서버를 설정하는 방법은 다음과 같이 JEUSMain.xml의 <node> 하위에 <session-router>를 추가한다.
[예 10.7] 분산 세션 서버의 설정 : <<JEUSMain.xml>>
<jeus-system> . . . <node> . . . <session-router-config> . . . </session-router-config> . . . </node> . . . </jeus-system>
<session-router-config>는 JEUSMain.xml 파일의 <node> 내에 하나만 존재해야 한다.
다음은 JEUSMain.xml 에 있는 분산 세션 서버 설정의 예이다.
[예 10.8] 분산 세션 서버 기본 설정 : <<JEUSMain.xml>>
<jeus-system> . . . <node> <engine-container> <base-port>3030</base-port> <name>container1</name> <engine-command> <type>servlet</type> <name>engine1</name> </engine-command> . . . </engine-container> <engine-container> <base-port>3031</base-port> <name>container2</name> <engine-command> <type>servlet</type> <name>engine2</name> </engine-command> . . . </engine-container> . . . <session-router-config> <thread-pool> <min>10</min> <max>20</max> </thread-pool> <connect-timeout>60000</connect-timeout> <read-timeout>60000</read-timeout> <backup-trigger>10</backup-trigger> <check-to>10000</check-to> <check-level>set</check-level> <default-file-db> <startup-clear-to>86400000</startup-clear-to> <passivation-to>-1</passivation-to> <min-hole>1000</min-hole> <packing-rate>0.5</packing-rate> </default-file-db> <session-router> . . . <!-- Next sub-section --> </session-router> </session-router-config> . . . </node> . . . </jeus-system>
다음은 설정 태그에 대한 설명이다.
태그 | 설명 |
---|---|
<thread-pool> | 분산식 세션 서버에서 사용되는 소켓 커넥션 처리를 위한 Thread Pool을 설정한다. |
<connect-timeout> | 컨테이너에 존재하는 분산 세션 서버 간 소켓 커넥션을 생성할 때 적용되는 타임아웃 값이다. |
<read-timeout> | 컨테이너에 존재하는 분산 세션 서버간 응답(reply) 메시지에 대해 적용되는 타임아웃 값이다. |
<backup-trigger> | 로컬 분산 세션 서버에서 세션 객체의 업데이트가 어느 정도 발생했을 때 백업 분산 세션 서버로 업데이트 세션 객체들을 백업할지를 설정한다. 이 설정에 지정된 횟수만큼 로컬 분산 세션 서버에 업데이트가 발생하면 백업을 수행한다. |
<check-to> | 백업 과정을 수행할 지를 체크하는 주기를 설정한다. 이 설정에 지정된 시간마다 업데이트 된 세션 객체가 있는지를 조사하고 업데이트된 세션 객체가 존재하면 백업을 수행한다. 추가적으로 백업 분산 세션 서버에 장애가 발생하였을 경우 alive check를 위한 주기 역할도 한다. |
<check-level> | 사용된 세션을 리모트 분산 세션 서버(Remote Web Container) 또는 로컬 파일 DB에 백업하기 전에 백업할 필요가 있는지를 체크하는 것이 필요하다. 이 설정은 백업의 필요성을 체크하는 기준을 정한다.
|
<default-file-db> | 업데이트된 로컬 세션 객체를 백업하는 방법으로는 백업 분산 세션 서버에 백업하는 방법 외에, 로컬 파일 시스템으로 백업하는 방법도 있다. 이 설정을 통하여 업데이트된 세션 객체를 로컬 파일 시스템으로 백업한다. 실제 파일 백업은 컨테이너별로 수행되나 이 설정은 분산식 세션 클러스터링에 참여하는 모든 컨테이너(session-router설정)들에 디폴트로 동일하게 적용된다. 단, <session-router> 설정의 하위 element로 "file-db"가 설정될 경우 이 설정은 무시되고 <session-router>의 설정이 적용된다. 자세한 설정은 "세부 분산 세션 서버 설정"에서 설명한다. |
<session-router> | 분산식 세션 클러스터링에 참여할 컨테이너를 지정하고 해당 세션 서버에 대한 각종 속성을 설정한다. 반드시 하나 이상이 존재해야 하며, 자세한 설정은 "세부 분산 세션 서버 설정"에서 설명한다. |
세션 클러스터링에 참여할 분산 세션 서버에 대해 설정한다.
다음은 JEUSMain.xml에 웹 컨테이너에서 사용하는 4개의 <session-router>를 설정한 예이다.
johan 노드에는 johan_servlet_engine1, johan_servlet_engine2가 있으며 이 둘은 같은 was1x location, 같은 FinancialServices replication group을 가지고 있다. 또한 같은 ConsultingServices이라는 선호하는 백업 그룹을 가진다.
johan1 노드에는 johan1_servlet_engine1, johan1_servlet_engine2가 있으며 이 둘의 location은 was2x로 johan 노드와는 다른 location임을 알수 있다. 해당 그룹 또한 ConsultingServices로 johan 노드에서 설정한 다른 분산 세션 서버와는 다른 그룹이며 johan노드에서 설정한 분산 세션 서버들을 선호하는 백업 그룹(FinancialServices)으로 선택하였다.
[예 10.9] 세부 분산 세션 서버 설정 : <<JEUSMain.xml>>
<jeus-system> . . . <node> <name>johan</name> <engine-container> <base-port>3030</base-port> <name>container1</name> <engine-command> <type>servlet</type> <name>engine1</name> </engine-command> . . . </engine-container> <engine-container> <base-port>3031</base-port> <name>container2</name> <engine-command> <type>servlet</type> <name>engine2</name> </engine-command> . . . </engine-container> . . . <session-router-config> . . . <session-router> <engine-name>johan_servlet_engine1</engine-name> <replication-group>FinancialServices</replication-group> <backup-group>ConsultingServices</backup-group> <location>was1x</location> <file-db> <startup-clear-to>86400000</startup-clear-to> <passivation-to>-1</passivation-to> <min-hole>1000</min-hole> <packing-rate>0.5</packing-rate> </file-db> </session-router> <session-router> <engine-name>johan_servlet_engine2</engine-name> <replication-group>FinancialServices</replication-group> <backup-group>ConsultingServices</backup-group> <location>was1x</location> <file-db> <startup-clear-to>86400000</startup-clear-to> <passivation-to>-1</passivation-to> <min-hole>1000</min-hole> <packing-rate>0.5</packing-rate> </file-db> </session-router> </session-router-config> . . . </node> . . . <node> <name>johan1</name> <engine-container> <base-port>3033</base-port> <name>container1</name> <engine-command> <type>servlet</type> <name>engine1</name> </engine-command> . . . </engine-container> <engine-container> <base-port>3034</base-port> <name>container2</name> <engine-command> <type>servlet</type> <name>engine2</name> </engine-command> . . . </engine-container> . . . <session-router-config> . . . <session-router> <engine-name>johan1_servlet_engine1</engine-name> <replication-group>ConsultingServices</replication-group> <backup-group>FinancialServices</backup-group> <location>was2x</location> . . . </session-router> <session-router> <engine-name>johan1_servlet_engine2</engine-name> <replication-group>ConsultingServices</replication-group> <backup-group>FinancialServices</backup-group> <location>was2x</location> . . . </session-router> </session-router-config> . . . </node> . . . </jeus-system>
다음과 같은 세부 설정 항목이 있다.
<engine-name>
세션 클러스터링에 참여할 컨테이너의 엔진 이름을 지정한다. 필수적으로 지정해야 하며, 엔진 이름은 웹 컨테이너의 경우 <node-name>_servlet_<servlet-engine-name>, EJB 컨테이너의 경우 <node-name>_ejb_<ejb-engine-name>식의 형태를 가진다.
다음은 설정에 대한 예제이다.
johan_servlet_engine1, johan_ejb_engine1
<replication-group>
세션 클러스터링에 참여할 해당 분산 세션 서버의 논리적인 그룹 이름을 설정한다.
지정하지 않을 경우 이 값은 <node-name>으로 대체된다. 이 정보는 세션 클러스터링 환경에서 적절한 백업 분산 세션 서버를 선택할 때 사용한다.
<backup-group>
세션 클러스터링에 참여한 다른 분산 세션 서버 중 선호하는 백업 대상의 그룹 이름을 지정한다. 다른 분산 세션 서버 설정의 <replication-group> 중에 선택한다.
지정하지 않을 경우 선호하는 그룹이 없다고 간주하며, 자신의 그룹과 다른 그룹을 우선적으로 선택한다. 이 정보는 세션 클러스터링 환경에서 적절한 백업 분산 세션 서버를 선택할 때 사용한다.
<location>
세션 클러스터링에 참여할 해당 분산 세션 서버의 물리적인 machine 이름 또는 location 정보를 설정한다.
지정하지 않을 경우 이 엔진이 동작하는 hostname이 된다. 이 정보는 세션 클러스터링 환경에서 적절한 백업 분산 세션 서버를 선택하는 데 사용된다.
<file-db>
세션 객체를 파일 시스템에 백업할 때 사용하는 설정으로 기본적인 개념은 "분산 세션 서버 기본 설정"에서 설명되었고, 여기에서는 하위 태그들의 의미를 살펴 본다.
컨테이너를 기동할 때 지정된 파일에 저장된 세션 객체들이 복구되는데, 만약 현재 시간과 파일의 last modified time의 시간차가 <startup-clear-to> 설정에 지정된 값보다 크면 복구를 시도하지 않고 파일의 내용을 모두 삭제한다.
<path>는 백업 세션을 저장할 파일 이름을 절대 경로로 지정한다. 기본값은 WEBMain.xml의 <session-config>의 설정에 따라서 달라진다.
태그 | 설명 |
---|---|
true | JEUS_HOME/logs/sessiondb/ <engine-name>_1.fdb |
false | JEUS_HOME/logs/sessiondb/<context-name>_<context-path>1.fdb |
메모리에 존재하는 세션 객체를 <passivation-to>에 설정된 시간 이상 사용하지 않으면 삭제하고 대신 file-db에 저장된 객체를 사용한다. 일정 시간 file-db를 운용하면 파일의 크기가 필요이상 커지게 된다.
<min-hole>에 설정된 횟수 만큼 파일 I/O가 발생하거나, 현재 세션 객체 갯수 대비 파일 I/O 횟수가 <packing-rate>에 지정된 ratio를 넘어서면 파일 packing을 수행하여 필요이상 파일 크기가 늘어나는 것을 방지한다.
기존에 사용했던 JEUS5의 분산 세션 서버 설정과 JEUS6의 새로운 분산 세션 서버 설정을 비교하여 변경된 부분을 설명한다.
위에서 예제로 소개했던 johan 노드의 johan_servlet_engine1, johan_servlet_engine2와 johan1 노드의 johan1_servlet_engine1, johan1_servlet_engine2의 Session Clustering 구성을 예로 사용한다.
다음은 JEUS 5에서의 설정 방법이다.
[예 10.10] <<JEUSMain.xml>>
<jeus-system> . . . <node> <name>johan</name> <engine-container> <base-port>3030</base-port> <name>container1</name> <engine-command> <type>servlet</type> <name>engine1</name> </engine-command> . . . </engine-container> <engine-container> <base-port>3031</base-port> <name>container2</name> <engine-command> <type>servlet</type> <name>engine2</name> </engine-command> . . . </engine-container> . . . <session-router-config> . . . <session-router> <!-- 웹 컨테이너만 분산 세션 서버를 지원 --> <servlet-engine-name>engine1</servlet-engine-name> <!-- 백업 서버를 선택 --> <backup-session-router> <node-name>johan1</node-name> <servlet-engine-name>engine1</servlet-engine-name> <container-base-port>3033</container-base-port> </backup-session-router> . . . </session-router> <session-router> <!-- 웹 컨테이너만 분산 세션 서버를 지원 --> <servlet-engine-name>engine2</servlet-engine-name> <!-- 백업 서버를 선택 --> <backup-session-router> <node-name>johan1</node-name> <servlet-engine-name>engine2</servlet-engine-name> <container-base-port>3034</container-base-port> </backup-session-router> . . . </session-router> </session-router-config> . . . </node> . . . <node> <name>johan1</name> <engine-container> <base-port>3033</base-port> <name>container1</name> <engine-command> <type>servlet</type> <name>engine1</name> </engine-command> . . . </engine-container> <engine-container> <base-port>3034</base-port> <name>container2</name> <engine-command> <type>servlet</type> <name>engine2</name> </engine-command> . . . </engine-container> . . . <session-router-config> . . . <session-router> <!-- 웹 컨테이너만 분산 세션 서버를 지원 --> <servlet-engine-name>engine1</servlet-engine-name> <!-- 백업 서버를 선택 --> <backup-session-router> <node-name>johan</node-name> <servlet-engine-name>engine1</servlet-engine-name> <container-base-port>3030</container-base-port> </backup-session-router> . . . </session-router> <session-router> <!-- 웹 컨테이너만 분산 세션 서버를 지원 --> <servlet-engine-name>engine2</servlet-engine-name> <!-- 백업 서버를 선택 --> <backup-session-router> <node-name>johan</node-name> <servlet-engine-name>engine2</servlet-engine-name> <container-base-port>3031</container-base-port> </backup-session-router> . . . </session-router> </session-router-config> . . . </node> . . . </jeus-system>
다음은 JEUS 6에서의 설정 방법이다.
[예 10.11] <<JEUSMain.xml>>
<jeus-system> . . . <node> <name>johan</name> <engine-container> <base-port>3030</base-port> <name>container1</name> <engine-command> <type>servlet</type> <name>engine1</name> </engine-command> . . . </engine-container> <engine-container> <base-port>3031</base-port> <name>container2</name> <engine-command> <type>servlet</type> <name>engine2</name> </engine-command> . . . </engine-container> . . . <session-router-config> . . . <session-router> <!-- 노드이름, 엔진, 엔진 이름이 혼합된 full name을 이용 --> <engine-name>johan_servlet_engine1</engine-name> <!-- 특별한 백업을 원하지 않을 경우 설정이 없어도 자동 선택됨 --> . . . </session-router> <session-router> <!-- 노드이름, 엔진, 엔진 이름이 혼합된 full name을 이용 --> <engine-name>johan_servlet_engine2</engine-name> <!-- 특별한 백업을 원하지 않을 경우 설정이 없어도 자동 선택됨 --> . . . </session-router> </session-router-config> . . . </node> . . . <node> <name>johan1</name> <engine-container> <base-port>3033</base-port> <name>container1</name> <engine-command> <type>servlet</type> <name>engine1</name> </engine-command> . . . </engine-container> <engine-container> <base-port>3034</base-port> <name>container2</name> <engine-command> <type>servlet</type> <name>engine2</name> </engine-command> . . . </engine-container> . . . <session-router-config> . . . <session-router> <!-- 노드이름, 엔진, 엔진 이름이 혼합된 full name을 이용 --> <engine-name>johan1_servlet_engine1</engine-name> <!-- 특별한 백업을 원하지 않을 경우 설정이 없어도 자동 선택됨 --> . . . </session-router> <session-router> <!-- 노드이름, 엔진, 엔진 이름이 혼합된 full name을 이용 --> <engine-name>johan1_servlet_engine2</engine-name> <!-- 특별한 백업을 원하지 않을 경우 설정이 없어도 자동 선택됨 --> . . . </session-router> </session-router-config> . . . </node> . . . </jeus-system>
JEUS 5 설정 중 <servlet-engine-name>이 JEUS 6에서는 <engine-name>으로 변경되었다. 기존에는 엔진 이름(short engine name)만 써주던 것을 JEUS 6에서는 노드, 엔진 이름을 혼합한 형식(full engine name)으로 입력한다.
JEUS 5 설정 중 <backup-session-router> 부분은 모두 없어진다. JEUS6에서는 백업이 자동으로 설정된다.
JEUS 5, 6 모두 JEUSMain.xml의 정보를 클러스터링할 노드들 간에 똑같이 공유한다.
JEUS 6에서는 추가적으로 세션 클러스터링에 참여할 웹 컨텍스트에 한해 <distributable>을 true로 설정한다. 이에 대한 자세한 설명은 “JEUS Web Container 안내서”의 “2.3.7. Session”을 참고한다.