2015년 9월 23일 수요일

JBoss Clustering Session 복제시 복제 기준

맨날 해깔려서 하는김에 정리해서 적어봄

1. 개요를 말하면....

공히 WAS 들은 Session Clustering 이라는 기능을 제공한다.

여러대의 WAS (Instance)가 하나의 서비스를 제공할때 각각의 WAS 에 로그인(**)한정보(Session)를 공유하여 일부 WAS가 정지되어도 로그인이 유지되는 기능이다.

** 엄밀히 로그인은 아니다. JSessionID 라는 WAS에서 생성해 주는 쿠키값으로 접속한 클라이언트의 세션을 유지하는 것으로 당신들이 ID/Password 를 입력하는 로그인 이라는 행위는 개발자가 개발해 놓은 기능이다.

상용 WAS 들 중에서 Enterprise 라는 단어가 붙어 있는 놈들과

Standard 버젼의 차이가 이거라고 보면 된다.

- 상용  제품군-
Web logic : Ent 와 Std 로 나뉜다.
JEUS : Ent 와 Std 로 나뉜다.

- 오픈소스(OSS)비지니스 제품군 - (오픈소스이기는 한데 돈내야 지원해준다)
JBoss EAP : Infinispan 기반으로 클러스터링 제공한다.
Resin : OSS 버젼과 Pro 버젼이 있으며  기본적으로 Clustering 기능이 있다. OSS 버젼은 Pure JAVA라 성능으로 따지만 Tomcat 이나 별반 차이도 없다.

- 오픈소스 제품군- (이건 기술지원 따위는 없다. 그냥 너님이 하는거다)
WildFly(구 JBoss AS) : Infinispan  이라는 Grid OSS 가 내부적으로 구현되어 있고 이기능올 클러스터링 제공
Tomcat : Clustering 기능이 최근에 추가 되어있다. 하지만 성능은 보장 못한다(않좋아...pure java 라넘 느려)
....

2. 근데 이거 꼭 써야해?
결론 부터 이야기하자... "아니다!"

세션을 유지한다는 것은 사용자 브라우져와 서버간의 접속이 유지되지 못하는 WEB의 특성상 (HTTP Protocol 은 stateless 라고 한다.)
한번 접속해서 화면 받아오면 상태(status)가 유실된다.
하지만 사용자의 상태가 유지되어야 로그인정보나 장바구니를 다시 볼 수 있기 때문에
이런 상태를 유지하는 것을 세션(Session)이라고 하며

이 세션을 유지하는 방법은 꼭 인프라(WAS) 에서 구현되어야 함은 아니다.

예를 들어 대규모 사이트의 경우 세션 정보를 WAS에서 복제하여 상태유지를 할 경우 세션을 모든 WAS가 동기화 하기위한 부하때문에 오히려 장애포인트가 되기도 한다. (Instance 여러개 + 사용자 대박!! 이면 WAS 지들끼리 세션 복사하다가 뻗어 버리기도 한다)

물론 JBoss 나 상용 WAS들은 이런 복제 Overhead 를 줄이기 위해서 몇몇 옵션등을 제공하기도 하므로 이런일로 고생하고 있다면 제품 지원팀에 문의해 보자.
(Sync  방식을 ASync 방식으로 바꾸거나, UDP 클러스터를  TCP로 바꾸거나 등등)

이러한 문제를 해결하기 위해서
WAS의 클러스터링 기능을 쓰지 않고
로그인처리시에 암호화된 세션정보를 사용자(브라우져)에 저장(쿠키)하도록 개발해서
세션을 유지 하기도 한다.
(사용자가 대박!인 글로벌 회사의 업무시스템 또는 대형 오픈마켓)

선택는 자유다.


단 팁을 준다면

2.1. 우리사용자가 졸라 많거나(동접 몇 만명 같이...)  WAS 인스턴스가 너무 많아서 클러스터링을 하는게 부담스러운경우
(다수의 WAS를 Clustering 하는 경우 세션복제 Overhead 로 인하여 원래 1개 WAS 가 처리할 수 있는 능력이 감소한다)

상용 WAS 기준이라면

클러스터링 버젼(Enterprise)보다 Standard 버젼을 도입하고 세션을 쿠키로 유지하거나

그리드 솔루션이 있다(JBoss Data Grid, Oracle coherence, 국산도 있다 GTWorks )

쿠키를 쓰건 그리드솔루션을 사용하건 일단 개발자가 세션을 유지하기 위한 방법을 설계해야 하고 일부 세션 관리 코딩은 추가 되어야 한다.

개발자 학습비용 기준  : 코드기반으로 관리하려면 아키텍쳐 부터 설계필요
WAS Clustering  <  Grid Solution <  코드(Cookie) 기반

서버부하(Overhead) 기준 : Overhead 가 클수록 WAS 처리량은 낮아진다.
WAS Clustering  >  Grid Solution >  코드(Cookie) 기반


오픈소스기반이라면

여하간 Tomcat Clustering은 사용하지 말라
게시판 뒤져보면 알겠지만 아직 성능이나 안정성이나 그다지 좋다고 못하겠다.

JBoss EAP 자체의 Clustering 을 사용하거나 위에 말한 그리드 솔루션(JBoss Data Grid)을 같이 검토하도록 한다.


또 다른 방법으로 클러스터를 쪼개는 방법이 있다.
(나는 개인적으로 이 구조를 좋아하고 많이들 이렇게 한다...
근데...실제 운영해야하는 사람들이 WEB/WAS/HA등을 잘 모르면 맨날 장애를 일으킨다......
예를들어 공무원조직에 담당자는 그게뭔지 모른다...장애나면 사람부른다....사람도착할 때 까지 장애다.)

예를 들어 인스턴스가 8개라면 클러스터를 8개 통째로 묶는게 아니라

4개 + 4개  로 클러스터를 두개로 나누어 운영하도록 하고
사용자 트래픽을 웹에서 분산구조에서 제어해서  최대한 장애가 발생하지 않도록 한다.

WEB :    1,2     3,4  
WAS :  1234   5678

위 구조에서 웹서버 1 또는 2로 들어온 사용자는  WAS1,2,3,4 로 접속이 되고 세션이 유지된다.  만약  was1,2,3,4 가 동시에 중지된다면 장애가 된다.

이러한 운영상의 논리적인 구조를 쪼개서 운영하는 경우  HA를 위하여 작업절차나 장애처리시 재구동 방법등을 세밀하게 조정하고 운영해야 한다.
(Ex, 배포후 재구동시 WAS를 1,2,3,4,5,6,7,8 순으로 재구동하지 말고 1,5,2,6,3,7,4,8 순으로 재구동 한다거나...)

2.2 걍걍 일반적인 업무 시스템 이라면
WAS의 Clustering 기능을 사용하도록 한다.
세션을 개발자가 코드상에서 생성하고 서버에 저장해서 유지를 한다는 일은......머리아프다....
기술적인 부하 문제가 없다면 Clustering 되는 제품간의 가격 비딩이 될 것이니...
알아서 하자.



3. JBoss EAP 에서 클러스터링 할 때 방법

아... 사실 Config를 하나하나 이야기 하려면 너무 많은 것을 설명해야 한다....
(UDP 냐 TCP 냐... 복제방식은 뭐냐...등등)

그냥 일단 클러스터링 되어 있다치고

개발자 입장에서 알아야할 세션 복제에 집중해서 적어본다.

일단 소스에서 /WAR_ROOT/WEB-INF/web.xml 파일안에 아래 볼드체가 있어야 동작한다.

<?xml version="1.0" encoding="UTF-8"?>
<web-app version="3.0" xmlns="http://java.sun.com/xml/ns/javaee"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd">

    <session-config>
        <session-timeout>30</session-timeout>
    <tracking-mode>URL</tracking-mode>
    </session-config>

  <distributable></distributable>

</web-app>

두번째
세션 복제는 RMI 같이 네트워크 통신을 해서 복제 된다.
그래서 세션에 저장하는 모든 Object는 Serializable 해야 한다. (JAVA Spec)
이건 WAS 할아버지가 와도 지켜야 할 법칙이다. (제품 마다 다르다는 뻘소리 하지 말자)

복잡하게 세션 객체를 만들어 쓰는 개발자 라면 아래 같이 하자.

class UserSessionObj implements Serializable
{

}

UserSessionObj InstUserSessionObj = UserSessionObj();
InstUserSessionObj.setUDI = "이름";
....

session.setAttribute("SESSION_OBJ", InstUserSessionObj);



세번째

/WAR_ROOT/WEB-INF/jboss-web.xml 파일안에 이런게 있다.
없으면 만들어도 된다. 하지만 기본 값이 있으므로 클러스터링 부하로 인한 문제
또는 개발한 기능상 복제될 세션객체에 대한 제어가 필요하지 않다면 꼭 만들 필요는 없다.

아래 뻘건 글씨를 잘 보자, 일단 이게 기본값이다.

<jboss-web>
    <context-root>/</context-root>
    <replication-config>
        <replication-trigger>SET_AND_NON_PRIMITIVE_GET</replication-trigger>
        <replication-granularity>SESSION</replication-granularity>
        <replication-field-batch-mode>true</replication-field-batch-mode>
        .... 이거 말고도 잔뜩
    </replication-config>
</jboss-web>


==========================================

웅??? 그게 뭐냐구???

메뉴얼 상에 글을 옮겨 보겠다.

SET: With this policy, the session is considered dirty only when an attribute is set in the session (i.e., HttpSession.setAttribute() is invoked.) If your application always writes changed values back into the session, this option will be most optimal in terms of performance. The downside of SET is that if an object is retrieved from the session and modified without being written back into the session, the session manager will not know the attribute is dirty and the change to that object may not be replicated.
>> 코드상에서 setAttribute()시 세션을 복제한다.
가장 클러스터링 부하가 낮다.
이렇게 해놓으면 값은 바뀌지만 복제가 안 될 수 있다.(코드 잘 짜면 그런 걱정 안해도 된다.)
세션에 저장되는 정보를 코드상에서 크게 컨트롤 하지 않는다면 부하를 줄이기 위해 사용해 볼 만 하다.


SET_AND_NON_PRIMITIVE_GET:(기본값) This policy is similar to the SET_AND_GET policy except that get operations that return attribute values with primitive types do not mark the attribute as dirty.
Primitive system types (i.e., String, Integer, Long, etc.) are immutable(수정불가능한), so there is no reason to mark an attribute with such a type as dirty just because it has been read.
If a get operation returns a value of a non-primitive type, the session manager has no simple way to know whether the object is mutable, so it assumes it is an marks the attribute as dirty.
This setting avoids the downside of SET while reducing the performance impact of SET_AND_GET. It is the default setting.

>> setAttribute()시 세션복제  + getAttribute()시 기본형(primitive type)들을 빼고 복제
(기본설정)

기본형(char,int,String, Integer**..등)는 재 할당은 가능하지만 할당된 값 자체를 변경할 수 없다. (이 객체들에는 set method가 없다)  - 개발을 해보지 않으면 좀 해깔릴 수 있다. immutable  객체에 대한 내용을 인터넷에서 찾아볼 것을 권한다-

그래서 이 값들은 GET 하는 순간에는 변경이 일어나지 않았음을 보장할 수 있으므로 (대체한다는 것은 SET 을 수행했다는것을 의미하므로 이미 복제 되었다.)
GET할때 Primitive 형을 복제 대상으로 지정하지 않는다.

이 방식은  SET의 누락에 대한 위험(오류)성과
SET_AND_GET이 너무많은 데이터를 복제할 수 있는 위험(성능관련)을 적절하게 타협한 방식으로 기본값으로 적용되어 있다.

이 설정이 기본이고 보통 이설정으로 큰 문제 없이 사이트 들은 운영된다.


SET_AND_GET: With this policy, any attribute that is get or set will be marked as dirty. If an object is retrieved from the session and modified without being written back into the session, the change to that object will be replicated. The downside of SET_AND_GET is that it can have significant performance implications, since even reading immutable objects from the session (e.g., strings, numbers) will mark the read attributes as needing to be replicated.
>> setAttribute()시 세션복제  + Obj getAttribute()시 세션복제
세션에 속성으로 객체나 프리미티브정보를 최초생성 하거나 이 값에 접근할 때 여하간 복제한다.
SET 이나 SET_AND_NON_PRIMITIVE_GET 보다는 복제 부하가 크겠찌???  그지??


ACCESS: This option causes the session to be marked as dirty whenever it is accessed. Since a the session is accessed during each HTTP request, it will be replicated with each request. The purpose of ACCESS is to ensure session last-access timestamps are kept in sync around the cluster.. Since with the other replication-trigger options the time stamp may not be updated in other clustering nodes because of no replication, the session in other nodes may expire before the active node if the HTTP request does not retrieve or modify any session attributes. When this option is set, the session timestamps will be synchronized throughout the cluster nodes. Note that use of this option can have a significant performance impact, so use it with caution. With the other replication-trigger options, if a session has gone 80% of its expiration interval without being replicated, as a safeguard its timestamp will be replicated no matter what. So, ACCESS is only useful in special circumstances where the above safeguard is considered inadequate.

>> HTTP 요청이 있으면 Session변경으로 간주하여 복제...여하간 무조건 복사
내 생각에 이거 하면 복제 트리거를 신경을 안써도 되니 간단해 보이지만 프로덕션환경에 적용하는 경우 그냥 사이트 무너진다고 보면 되겠다 (개인 홈페이지라면 상관없다)

.이상.

댓글 4개:

  1. 내용중에 거짓말(?)이 있어서 업데이트쳐서 다시 올림....

    답글삭제
  2. 가슴아파서~ 나 이렇게 웃어요~~
    wildFly 찡..


    6000

    /


    COOKIE
    URL


    위와 같이 해줘도
    ear 내에 war 컨텍스트 루트명이 바뀌면 ㅋㅋ 어떤건 잘 쉐어되고 ㅋㅋ 어떤건 페이지 리로드 될때마다 jsessionId가 바뀌는 기이한 현상 ㅠㅠ

    답글삭제
  3. 하아 ㅋㅋ 정리 감사합니다..




    6000

    /


    COOKIE



    이렇게 해줘도
    ear 내에 있는 웹 애플리케이션들중에 세션 계속 새로 생성하는넘 있네옄ㅋㅋ 짜증난다..

    답글삭제

본 블로그의 댓글은 검토후 등록됩니다.