설명
JBoss는 HTTP 세션 복제와 관련하여 다음과 같은 설정 항목이 있습니다.
- 세션 복제 사용 여부
- 세션 변경 여부(dirty check) 기 준
- 세션 복제 단위
- 세션 복제 시점
- 세션 복제 메시지 전송 방식
1) 세션 복제 사용 여부
WAS에서는 각 모듈 별로 분산 혹은 클러스터링 여부를 설정할 수 있도록 하고 있습니다.
특히 웹 어플리케이션의 경우에는 web.xml에서 <distributable/>을 설정해 표준적인 방법으로 클러스터링을 설정합니다.
WEB-INF/web.xml
<web-app>
<distributable/>
… …
</web-app>
(*) 서버 상에 클러스터링 설정을 잘 했어도 정작 웹 어플리케이션에 이 설정을 하지 않으면 세션 복제는 일어나지 않습니다.
2) 세션 변경 여부 기준
JBoss Clustering 세 션 관리자는 HTTP 요청 처리 후 변경된 세션을 클러스터를 구성하는 각 노드로 복제합니다.
그렇다면 세션 관리자는 어떻게 세션이 변경되었는지 알 수 있을까요?
가장 쉬운 방법은 프로그램에서 session.setAttribute()를 호출하면 세션이 변경된 것으로 간주하는 것입니다.
UserInfo user = session.getAttribute("user");
// user 정보 변경
session.setAttribute("user", user);
JBoss를 비롯한 대부분의 WAS는 이 방법을 지원합니다.
그런데 JBoss에 서 이 방식이 기본설정이 아니므로 이 방식을 사용하기 위해서는 해당 웹어플리케이션의 JBoss Deployment Descriptor에 추가적인 설정이 필요합니다.
WEB-INF/jboss-web.xml
<jboss-web>
<replication-config>
<replication-trigger>SET</replication-trigger>
<replication-granularity>SESSION</replication-granularity>
</replication-config>
</jboss-web>
JBoss에서 지원하는 세션 변경 여부 판단 기준은 다음과 같습니다.
SET | setAttribute() 시 세션이 변경된 것으로 간주 |
SET_AND_NON_PRIMITIVE_GET | setAttribute() 뿐만 아니라 변경 가능한 object에 대한 getAttribute() 시 세션이 변경된 것으로 간주. 디폴트 설정 |
SET_AND_GET | setAttribute() 뿐만 아니라 getAttribute() 시에도 세션이 변경된 것으로 간주 |
ACCESS | HTTP 요청이 있을 때 마다 session이 변경된 것으로 간주 |
SET_AND_NON_PRIMITIVE_GET은 개발자가 세션에서 객체를 가져와 변경한 후 setAttribute()를 해주지 않는 경우를 위한 것입니다.
이는 SET_AND_GET과 유사하지만 Integer나 String과 같이 변경 불가능한 객체에 대해서는 변경으로 간주하지 않는다는 차이가 있습니다.
주로 클러스터링을 고려하지 않고 단독 서버 용으로 개발된 어플리케이션을 클러스터 상에 디플로이할 때 사용합니다.
(*) 프로그램 상에 위와 같은 문제가 없다면 replication-trigger를 SET으 로 설정하는 것이 가장 좋습니다.
3) 세션 복제 단위
변경된 세션을 클러스터상의 각 노드로 복제할 때 가장 단순한 방법은 세션을 통째로 복제하는 것입니다.
하지만 변경된 부분만 복제한다면 전송량을 줄일 수 있어 성능이 향상될 것입니다.
JBoss는 상황에 따라 선택할 수 있도록3가지 복제 단위를 지원합니다.
SESSION | 세션을 통째로 복제 |
ATTRIBUTE | 세션에서 변경된 attribute만 을 복제 |
FIEDLD | attribute object의 변경된 필드만을 복제 |
SESSION à ATTRIBUTE à FIELD 순으로 복제 단위는 더 세분화됩니다. 그런데 복제 단위를 세분화하는데 따르는 오버헤드가 있기 때문에 단순히 세분화할수록 좋은 것은 아닙니다.
통상 세션 크기가 5K 이하라면 세션을 통째로 복제하는 것이 가장 효율적입니다.
세션 크기가 그 이상이고 일부 attribute만 변경이 잦은 경우라면 ATTRIBUTE를 선택할 수 있습니다.
세션이 아주 크고, attrribute의 특정 필드만 변경이 잦은 경우라면 FIELD를 선택할 수 있습니다.
주의할 점은 그 변경되는 attribute 또는 필드가 세션 크기의 대부분을 차지한다면 전송량 자체가 줄지 않으므로 전혀 이점이 없겠죠.
WEB-INF/jboss-web.xml
<jboss-web>
<replication-config>
<replication-trigger>SET</replication-trigger>
<replication-granularity>SESSION</replication-granularity>
</replication-config>
</jboss-web>
4) 세션 복제 시점
JBoss는 세션의 변경 사항을 즉시 (instant) 또는 일정 간격 (interval)으로 복제할 수 있습니다.
기본값은 instant로 Tomcat 서비스에 설정되어 있습니다.
deploy/jboss-web.deployer/META-INF/jboss-service.xml
<attribute name="SnapshotMode">instant</attribute>
<attribute name="SnapshotInterval">2000</attribute>
SnapshotMode를 interval로 설정할 경우에는 추가적으로 SnapshotInterval 값으로 복제 주기를 ms 단위로 설정할 수 있습니다.
만약 주기를 30초 로 잡으면 그 사이에 장애가 발생할 경우 변경된 세션 정보를 잃어버리게 됩니다.
(*) 특별히 세션 정보를 잃어버려도 되는 상황이 아니라면 instant를 그대로 두는게 안전합니다.
5) 세션 복제 메시지 전송 방식
세션이 변경되어 클러스터상의 각 노드로 세션을 전송할 때에는 각 노드로부터 전송이 완료되었다는 ACK를 받을 때까지 기다리는 동기 방식 (REPL_SYNC) 과 그냥 큐에 넣어두고 별도 쓰레드에서 전송을 처리하는 비동기 방식 (REPL_ASYNC)을 선택할 수 있습니다.
기본값은 REPL_ASYNC로 Tomcat 클러스터 서비스에 설정되어 있습니다.
deploy/jboss-web-cluster.sar/META-INF/jboss-service.xml
<attribute name="CacheMode">REPL_ASYNC</attribute>
ShapshotMode와 CacheMode를 함께 생각해보면 기본값 조합에서는 HTTP 요청을 처리한 후 세션이 변경되었으면 바로 각 노드로 세션을 복제하도록 메시지를 큐에 넣고 Servlet/JSP 수 행을 끝냅니다. 결국 클라이언트에게 응답이 간 시점에 세션 복제가 완료되었는지 장담할 수 없습니다.
만약 세션 복제가 이루어지기 전에 클라이언트가 다시 HTTP 요청을 했는데, 이 HTTP 요청이 다른 노드로 전달될 경우에는, 예 전 세션을 가지고 처리하는 문제가 발생할 수 있습니다.
이 때문에 JBoss 클러스터링 기본 설정을 그대로 사용할 경우에는 반드시 Sticky 로 드 밸런싱을 설정해 요청이 계속 세션이 생성된 노드로 가도록 해야 합니다.
동기 방식 (REPL_SYNC)을 선택했다면 모든 노드로 세션 복제를 완료한 후에야 Servlet/JSP 수행이 끝나므로 위의 문제가 발생하지 않습니다.
방문 해주셔서 감사합니다. 로그인 없이 가능한
아래 하트♥공감 버튼을 꾹 눌러주시면 감사하겠습니다!