세션 서버

본 장에서는 클러스터링 환경에서 세션 트래킹을 위해 운용되는 분산 세션 서버의 구조, 동작 및 설정 방법 등에 대해서 설명한다.

1. 개요

세션 서버는 클라이언트의 세션 데이터를 관리하거나 백업하는데 사용된다. 그 중에서도 특히 여러 웹 서버들과 서블릿 엔진들이 클러스터링된 환경에서 세션 데이터를 관리할 때 유용하다. 세션 데이터의 관리 방식인 세션 서버로 중앙식 세션 서버와 분산식 세션 서버를 운용한다.

JEUS 6까지는 중앙식 세션 서버가 주로 사용되었으나, 시스템의 중앙 집중으로 인한 문제를 줄이기 위해 JEUS 7 이후부터는 분산식 세션 서버만을 사용했었다. 그러나 JEUS 9부터에는 Jeus 자체 중앙식 세션서버와 외부 Storage로 Redis와 Hazelcast를 지원하여 다시 중앙식 세션 서버도 사용할 수 있다.

2. 기본 개념

본 절에서는 분산 세션 서버의 기본 개념에 대해 이해를 돕기 위해서 중앙 세션 서버와 비교해서 설명한다.

2.1. 중앙 세션 서버

간단히 세션 서버는 JEUS에서 세션 객체를 저장하는 곳이다.

세션 객체는 서블릿 API의 HTTP 세션 객체를 나타낸다. HTTP 세션같은 객체는, 상태 유지가 안 되는 프로토콜인 HTTP 요청을 임시 데이터와 매핑한다. 그래서 이 임시 데이터를 통해서 클라이언트를 구별한다. 이렇게 함으로써 WAS는 작업 중인 클라이언트를 다른 클라이언트와 구분할 수 있으며, 이전에 작업한 내용을 기억할 수 있다. 이런 "Session Tracking"은 웹 사이트에서 가장 중요한 부분이다.

그러나 문제는 HTTP 세션 객체는 그 세션이 처음 생성된 서블릿 엔진에만 저장된다는 것이다. 이는 여러 서블릿 엔진들로 클러스터링 환경을 구성했을 경우 세션을 처음 생성한 서블릿 엔진에게 해당 클라이언트의 모든 요청을 보내야 한다는 의미이다. 그렇지만 항상 특정 서블릿 엔진으로 요청이 간다고는 볼 수 없다. 예를 들어서 웹 서버가 세션 라우팅을 지원하지 않거나 서블릿 엔진이 내부 에러로 인해 갑자기 종료(Down)될 경우 세션 객체를 잃어버리게 되기 때문이다.

중앙 세션 서버는 세션 데이터들을 한 곳에 모아서 관리한다. 즉, 어떤 클라이언트를 위한 세션 객체나 특정 서블릿 엔진에서 생성된 것도 모두 중앙 세션 서버를 이용하는 것이다. 이는 2가지의 이점이 있다.

  • 첫째는 중앙 세션 서버를 사용함으로써 더 이상 웹 서버의 세션 라우팅이 필요없다.

  • 둘째는 중앙 세션 서버를 사용하고, 백업용 중앙 세션 서버를 하나 더 사용하여 세션 데이터를 백업함으로써 시스템이 더욱 안정화된다.

이로써 서블릿 엔진이 다운이 되더라도 안전하게 세션을 유지할 수 있다.

2.2. 분산 세션 서버

분산 세션 서버는 세션 클러스터링 기능을 제공하면서 확장성 및 안정성을 개선한 방식이다. 따라서 대규모 클러스터링 환경에서 성능을 발휘할 수 있다.

분산 세션 서버는 기본적으로 세션 서버로서의 동작면에서는 기존의 중앙 세션 서버와 동일하다. 여러 서블릿 엔진들로 구성된 클러스터링 환경에서 동일한 클라이언트에서 요청된 일련의 요청들이 특정 서블릿 엔진에서 처리되지 않더라도 세션을 계속 유지해주는 기능을 제공한다.

분산식 세션 서버는 해당 세션들의 관리 주체들이 분산되어 있음을 의미하며, 이에 따라 높은 확장성을 제공한다.

분산 세션 서버의 특징은 다음과 같다.

  • 여러 개의 서블릿 엔진으로 구성된 클러스터링 환경에서 지속적인 세션 유지가 가능하다.

  • 바로 이전의 요청을 처리하던 서블릿 엔진이 다운되어도 다른 서블릿 엔진들이 이후의 요청을 처리할 때 세션이 끊기지 않도록 한다.

  • 분산식 프로토콜을 사용하기 때문에 클러스터링 규모가 커지더라도 확장성이 용이하다.

3. 서버 구조

본 절에서는 중앙 세션 서버와 분산 세션의 구조를 비교해서 설명한다.

3.1. 중앙 세션 서버 구조

중앙 세션 서버는 JEUS 웹 컨테이너와 연결하여 운영되며, 웹 컨테이너에 있는 클라이언트의 세션을 라우팅하거나 백업하는 기능을 제공한다. 중앙 세션 서버는 Session Manager, Session Cache Memory, Session Storage 등으로 되어 있다. Session Storage로는 JEUS 자체 중앙식 Session Server와 Redis, Hazelcast를 지원하고 있다.

중앙 세션 서버의 서브 컴포넌트는 다음과 같다.

  • Session Manager

    • 엔진의 세션 관리를 총괄하는 모듈이다. 로컬 메모리, 세션 서버로부터 세션을 얻어오거나 관리한다.

    • 로컬 웹 엔진은 getSession을 통해 세션 매니저로부터 사용할 세션 객체를 얻어온다. Cached Session, Session Storage들 순서로 세션을 얻어온다.

    • 세션에 대한 처리가 끝나면 Session Storage로 update한다.

  • Cached session(Session Cache Memory)

    활성화되어 있거나 한 번 사용된 세션 객체는 빠른 사용을 위해서 이곳에 저장된다.

  • Session Storage

    세션을 저장하는 Session Server역할을 한다. Storage로는 Jeus자체 중앙식 Session Server와 Redis, Hazelcast를 지원한다.

3.2. 분산 세션 서버 구조

분산 세션 서버는 세션 객체를 서비스하는 서버가 각각의 서블릿 엔진(웹 엔진) 또는 각각의 EJB 엔진에 분산되어 있는 분산식 구조이다.

분산 세션 서버 방식은 클러스터링에 참여하는 모든 엔진 내에 독립적인 분산 세션 서버가 존재하고, 이들 분산 세션 서버들이 Peer-to-Peer로 다른 엔진의 분산 세션 서버와 통신하여 지속적인 세션 서비스를 제공한다.

다음은 분산 세션 서버 방식을 사용하여 4개의 웹 엔진을 세션 클러스터링하는 구조이다.

figure distributed sessionserver clustering
분산 세션 서버를 이용한 세션 클러스터링 구조

위의 구조도에서 화살표는 분산 세션 서버 간의 소켓 연결을 나타낸 것이다. 항상 모든 연결을 맺는 것이 아니고, 연결에 대한 가능성을 의미한다. 일반적으로 연결이 필요없으며 세션 유지를 위해 다른 엔진과의 통신이 필요한 경우에만 연결을 맺고 유지한다. 장애 발생의 경우를 제외하고 연결은 보통 하나씩만 갖는다.

다음은 웹 엔진의 서브 컴포넌트로 동작하는 분산 세션 서버의 내부 구조이다.

figure distributed sessionserver details modify
분산 세션 서버 내부 구조
  • Session Manager

    • 엔진의 세션 관리를 총괄하는 모듈이다. 로컬 메모리, 파일 및 다른 리모트 분산 세션 서버로부터 세션을 얻어오거나 관리한다.

    • 로컬 웹 엔진은 getSession을 통해 세션 매니저로부터 사용할 세션 객체를 얻어온다. session의 sticky server, 이전 backup server들 순서로 세션을 얻어온다.

    • 수정된 세션은 리모트 백업이 있을 경우 Cluster Manager를 통해, 백업 서버로 정해진 다른 웹 엔진의 분산 세션 서버로 in-memory 백업된다(backupSession).

      수정된 세션은 'Backup Level' 설정에 따라 다르게 적용된다. 'Backup Level'이 'all’일 경우 항상 'get’일 경우 getter와 setter의 호출할 때, 'set’일 경우 setter호출할 때에만 (setAttribute, removeAttribute, setMaxInactivateInterval)의 세션 operation이 발생했을 때 수정된 세션으로 판단한다.

      'Backup Level' 항목의 설정값에 대한 자세한 설명은 세션 서버 설정을 참조한다.

  • Backup Storage

    • 자신의 분산 세션 서버를 백업으로 선택한 다른 엔진의 분산 세션 서버가 주기적으로 전송하는 백업 세션 객체를 관리한다. 이 백업 세션 객체는 원본을 가지고 있는 엔진에 장애가 발생한 경우 대신하여 세션을 제공한다.

    • 자신을 백업으로 지정한 리모트 웹 엔진이 전송하는 백업 세션을 받아서 저장 및 관리한다(backupSession, getBackupSession).

    • 로컬에서 수정된 세션 객체는 조건이 만족되면 지정된 리모트 분산 세션 서버로 백업된다. 이러한 백업은 요청이 끝나면 바로 수행되어서 장애 상황에서의 Failover가 가능하도록 한다.

  • Cluster Manager

    • 리모트 웹 엔진에 있는 세션들에 대해서 특정 operation을 할 경우 중재 역할을 하는 모듈이다.

      해당 엔진은 dynamic한 환경을 고려하여 운용된다. 즉, 기동환경 중에 운용하는 서버가 추가되거나 제거된 경우 해당 상황에 적절한 백업을 선택하여 운용되고, 이것은 환경설정 중심에서 벗어난 큰 특징 중 하나이다. 리모트 엔진(RemoteEngine)에 대한 연결은 지속적인 ping을 통한 확인이 아닌 SCF를 통한 방식으로 지속적인 장애 상황에서의 불필요한 오류 상황을 제거해준다.

      리모트 웹 엔진로부터의 getSession(), removeSession() 등을 예로 들 수 있다.

      기존 환경 중심의 구조에서는 설정으로 인해서 고정된 백업 엔진만을 바라보게 되었지만 dynamic하게 변화하는 리모트 엔진에 대해서 유동적인 변경이 가능하도록 설계되었다.

4. 동작 방식

본 절에서는 중앙 세션 서버와 분산 세션의 동작 방식을 비교해서 설명한다.

4.1. 중앙 세션 서버

웹 컨테이너는 중앙 세션 서버와 연결된다. 한 번 연결할 때 웹 컨테이너는 세션 객체가 새로 생성되거나 수정된 세션으로 판단되면 중앙 세션 서버에 세션 객체를 저장하거나 업데이트한다. 그리고 클라이언트의 요청이 들어올 때마다 저장소로부터 세션 객체를 가지고 온다.

4.2. 분산 세션 서버

분산 세션 서버 방식은 세션 라우팅 기능을 기본으로 동작한다. 세션 ID에 특정 서버의 이름을 붙여서 발급하여 기존에 생성된 서버의 위치를 알고 해당 정보로부터 세션을 유지한다. 그렇기 때문에 세션 라우팅 기술을 강제로 사용하지 않을 경우에는 성능의 효율이 떨어진다.

세션 라우팅을 지원하는 웹 서버를 앞단에 배치하면 정상적인 경우 세션 객체가 존재하는 웹 엔진으로 요청이 라우팅될 것이다. 따라서 이러한 경우의 동작 방식은 세션 라우팅에 의한 세션 클러스터링과 동일하다. 이에 대한 내용은 클러스터 환경에서 동작을 참고한다.

세션 라우팅 기능을 기본으로 동작하는 분산 세션 서버 방식에서는 SessionKey를 사용한다.

다음은 웹 엔진에서 사용되는 SessionKey의 예제이다.

<SessionID>.<primary-engine-name>
예) XXX.domain1/server1
항목 설명

XXX

<SessionID>를 상징적으로 나타낸 것으로 실제 <SessionID>는 이보다 훨씬 긴 Random String 형태이다.

domain1/server1

라우팅 정보를 의미한다. domain1이라는 서버의 서블릿 엔진을 의미한다.

각 엔진은 세션 라우팅에 사용하는 세션 라우팅 ID를 하나씩 부여받는다. 이 ID는 웹 서버에 웹 엔진이 접속할 때 웹 엔진을 구분하는 구분자로 사용된다. 세션 라우팅 ID는 설정에 의해 자동 생성된다.

분산 세션 서버에 의한 Failover 구조의 3개의 웹 엔진은 다음과 같은 세션 라우팅 ID 및 백업 서버의 세션 라우팅 ID가 할당되었다고 가정한다.

  • WebEngine(server1)

    • 세션 라우팅 ID : domain1/server1

    • 백업 서버의 세션 라우팅 ID : domain1/server2

  • WebEngine(server2)

    • 세션 라우팅 ID : domain1/server2

    • 백업 서버의 세션 라우팅 ID : domain1/server3

  • WebEngine(server3)

    • 세션 라우팅 ID : domain1/server3

    • 백업 서버의 세션 라우팅 ID : domain1/server1

세션 라우팅 ID가 할당된 분산 세션 서버에 의한 세션 트래킹의 Failover 구조는 다음과 같다.

figure distributed sessionserver failover
분산 세션 서버에 의한 Failover 구조

다음은 분산 세션 서버에 의한 Failover 구조의 동작에 대한 설명이다.

  1. 웹 서버는 세션 라우팅 ID를 분석하여 WebEngine(server1)으로 해당 Request의 전송을 시도하지만 WebEngine(server1)은 fail 상태이다.

  2. 웹 서버는 다른 WebEngine 중에서 임의로 하나를 선택하여 요청을 보낸다. 본 예제에서는 WebEngine(server3)을 선택하였다.

    웹 서버로부터 요청을 전달받은 WebEngine(server3)은 세션 라우팅 ID를 분석한다. 분석 결과 이 요청을 처리할 세션 객체는 WebEngine(server1)에 있으며, 해당 세션의 백업은 WebEngine(server2)에 존재한다는 것을 알게 된다.

  3. 분산 세션 서버인 WebEngine(server3)은 요청 분석 결과에 따라 WebEngine(server1)에 접속하여 세션 객체를 가져오려고 시도한다. 그러나 WebEngine(server1)에 장애가 발생했으므로 해당 요청의 시도는 실패한다.

  4. 요청이 실패로 끝났기 때문에 WebEngine(server3)은 WebEngine(server1)의 백업 서버인 WebEngine(server2)로 다시 시도한다(Backup Migration). WebEngine(server2)은 요청에 대해 백업해놓은 세션 객체를 WebEngine(server3)에게 넘긴다.

  5. 성공적으로 세션 객체를 가져온 WebEngine(server3)는 이후 클라이언트의 요청을 처리하여 응답 메시지를 클라이언트에게 보낸다. 이때 새로운 SessionKey를 작성하여 보내기 때문에 클라이언트의 SessionKey가 변경되고 이후 요청이 WebEngine(server3)로 들어온다. 새로운 SessionKey를 작성할 때는 세션 라우팅 ID 부분만 자신의 것으로 치환한다.

웹 서버가 세션 라우팅을 지원해도 웹 서버에 세션 라우팅 ID에 해당하는 웹 엔진으로의 연결이 존재하지 않거나 해당 웹 엔진에 장애가 발생하여 요청을 전달할 수 없는 경우에 웹 서버는 세션 라우팅을 지원할 수 없다. 이러한 경우 웹 서버는 보통 임의로 선택된 다른 웹 엔진으로 요청을 전달한다.

다음은 세션 라우팅 기능을 사용하지 않는 상황을 가정할 경우의 분산 세션 서버에 의한 Failover 구조의 분산 세션 서버 동작에 대한 설명이다.

  1. 세션 라우팅 기능을 사용하지 않는 상태라면 세션 라우팅 ID는 존재하지 않는다. 웹 서버는 임의의 WebEngine을 선택해서 요청을 보낸다. 본 예제에서는 WebEngine(server1)이 선택되었다.

  2. 웹 서버는 WebEngine(server1)이 fail 상태임을 감지하고 다시 임의의 WebEngine을 선택하여 요청을 보낸다. WebEngine(server3)이 선택되었다.

  3. 분산 세션 서버인 WebEngine(server3) 또한 해당 세션에 대한 라우팅 정보를 알 수 없기 때문에 현재 접속 중인 분산 세션 서버로 순서대로 요청한다. 해당 요청은 WebEngine(server1)에 요청을 보냈으나 이 시도는 실패하였다.

  4. 분산 세션 서버는 해당 요청을 다시 WebEngine(server2)에 보내고 WebEngine(server2)은 해당 세션을 전달한다.

  5. 세션을 전달받은 WebEngine(server3)은 SessionKey의 변경 없이 클라이언트로 보낸다. 이에 따라 다음 요청도 해당 세션을 가지고 있는 WebEngine(server3)으로 오지 않을 수 있다.

    설명을 위해서 라우팅 정보를 domain1/server1과 같이 표기했으나 운용 중에는 해당 정보가 인코딩되어 동작한다.

세션은 한 리퀘스트 안에서 의미가 있는 객체로서 다른 JVM이나 다른 스레드에서 동시 조작등은 스펙상 보장을 하지 않는다. 즉, 애플리케이션의 책임이며 해당 환경은 지양이 되어야 하는 사항이다.

애플리케이션의 구성상 동시 요청을 보내야 한다고 한다면 해당 요청들은 각기 다른 세션을 바라보게 구성하거나 세션을 사용하지 않도록 해야 정상적으로 동작한다. 하지만 세션의 공유는 매우 매력적인 사항이며 해당 사항을 이용하고 애플리케이션을 구성하는 사례들이 증가 하고 있다.

이러한 동시 다발적인 요청이 세션과 연계가 된다면 제약 사항들이 존재하며 그것은 아래와 같다.

  1. 새로운 세션이 동시에 생성될 가능성이 존재하며, 해당 세션 중 하나의 세션만 쿠키로 유지가 되기에 불필요한 메모리의 낭비가 발생할 수 있다.

    각 요청이 다른 JVM으로 이동하거나, 동시에 처리될 경우에 모두 포함되는 행동이다. 세션이 존재하지 않을 경우 세션을 생성하는 것이 기본적인 동작이기에 동시에 전달된 요청은 각각 새로운 세션을 발급 받게 되는 것을 막을 수 없다. 이러한 세션들은 사용자의 브라우저의 쿠키에 저장되는데 해당 쿠키는 결국 하나의 스코프로 관리되어 마지막으로 발급 받게 되는 세션으로 덮어 씌워진다. 이로 인해 다른 요청에 의해 생성된 세션은 별도로 접근할 수 없으며 타임아웃에 의해 제거될 수 밖에 없다.

  2. 세션이 동시에 다른 JVM에서 유지되기 위한 방식에 따라 세션을 유지하지 못할 수 있다. 이 제약 사항 스티키 세션 라우팅과 연계되어 있는 제약사항으로 동일한 서버나 웹 엔진으로 전달되었을 때는 해당되지 않는 문제이다. 애플리케이션의 구성이나 환경으로 인해 다른 JVM으로 요청이 동시에 전달될 때에는 세션 유지하는 방식에 의해 세션이 유지되지 않을수 있다.

  3. 세션에 동시에 업데이트를 수행할 경우 해당 세션에 반영이 무시될 수 있다.

    2번의 사항과 마찬가지로 다른 서버나 웹엔진에 전달되었을 경우에 해당되는 문제이다. 세션의 업데이트는 하나의 요청에 의해서 처리되는 것을 가정하였기에 그 결과의 반영도 세션 생성과 동일하게 타이밍에 의해 반영이 무시될 수 있다.

제약사항에서 언급이 되었듯이 동시 요청이 동일한 서버나 웹 엔진에게 요청이 전달될 경우에는 특별한 문제가 발생되지 않는다. 하지만 애플리케이션 구성에 의해서 다른 서버로 요청이 동시에 전달될 경우에는 위와 같은 상황이 발생한다. 이를 막기 위해서 JEUS 9는 Copy&Update 방식으로 동작한다.

figure session prevent migration
동작 경로

동시 요청이 다른 서버로 가더라도 타겟이 되는 세션을 마이그레이션 하지 않고 카피하여 로컬에서 조작하고, 또한 그 결과를 다시 기존의 서버에게 업데이트 하는 방식을 수행한다. 이러한 동작으로 인해 세션의 유실은 방지할 수 있으며, 단순히 세션의 값을 확인하는 동작에서는 무리없이 서비스가 가능하다.

세션은 단순한 정보를 저장하고 관리하는 임시적인 객체이지 모든 시스템에 동시에 존재하는 데이터 베이스와 같이 사용해서는 안된다. 단순히 객체의 값을 참조하는 경우에만 사용하며, 다른 서버로의 동시 요청이 전달되는 구조 및 설정은 지양해야 한다.

5. 주요 기능

본 절에서는 분산 세션 서버의 주요 기능에 대해서 설명한다.

5.1. 중복 로그인 방지 기능

중복 로그인 방지 기능은 기본적으로 애플리케이션에서 관리 하는 중복 로그인 관리 기능 중 기본적인 기능을 분산식 세션 서버에서 제공하는 서비스이다.

분산식 세션 서버의 중복 로그인 방지 기능을 사용하게 되면 애플리케이션의 아이디에 대해 중복된 로그인을 허용하지 않음을 내부적으로 지원한다. 즉, 다른 세션에 대해 동일한 아이디로 로그인을 수행한 경우 기존의 로그인을 수행하였던 세션을 제거하여 근본적으로 중복 로그인을 방지한다.

중복 로그인 방지 기능을 위해 Login Manager는 기존의 중앙 세션 서버와 유사하게 구성된다. 여러 서버들 간의 클러스터링 안에서 로그인 정보를 저장하는 서버를 지정하여 동작하며 장애 상황을 고려하여 secondary 서버를 구성하여 동작한다.

중복 로그인 방지 기능은 Session Storage 별로 설정 가능하며 로그인 정보를 Session Storage로 관리된다. 해당 설정은 Session Storage의 property에 login-manager를 true로 설정한다.

중복 로그인 방지에 대한 동작은 다음과 같다.

figure prevent duplicate login
중복 로그인 방지 기능의 동작 방식

다음은 중복 로그인 방지 기능의 동작 방식의 동작에 대한 설명이다.

  1. SessionA를 사용 중인 Client A는 Web EngineA에 ID:UserA로 로그인을 시도한다.

  2. Web EngineA는 Login Manager에 로그인 정보를 등록한다.

  3. Login Manager는 로그인에 대한 ACK를 Web EngineA에 전달한다.

  4. Web EngineA는 요청에 대한 Response를 Client A로 전달한다.

  5. SessionB를 사용 중인 서로 다른 Client B가 동일한 ID:UserA로 로그인을 시도한다.

  6. Web EngineB는 Login Manager에 로그인 정보를 등록한다.

  7. Login Manager는 동일한 ID:UserA에 대해 중복 로그인이 일어났음을 알게 된다.

  8. Login Manager는 기존의 로그인을 수행한 SessionA를 지닌 Web EngineA에 SessionA를 제거하라는 명령을 보내며, Web EngineA는 해당 세션을 제거한다.

  9. Login Manager는 로그인에 대한 ACK를 Web EngineB에 전달한다.

  10. Web EngineB는 요청에 대한 Response를 Client B에 전달한다.

로그인은 애플리케이션에서 이벤트이므로 Jeus Login Manager에서 로그인 이벤트를 전달하는 방법에는 제약 사항이 존재한다. Jeus Login Manager에서는 기본적으로 Session Storage의 property에 user-info로 LoginID를 가지고 올 수 있는 Method를 설정한다. 동일한 키로 removeAttribute를 수행한 경우 로그아웃되며 invalidate된 세션은 자동으로 로그아웃된다.

5.2. Failback 기능

Failover 기능은 장애 상황에 대처 하여 기존의 서비스를 지속적으로 이뤄지도록 해주는 세션 서버의 기본적인 기능이다. 즉, 세션의 생성 이후 백업에 전달된 세션으로 인해 특정 서버가 장애가 발생하여도 세션의 유실이 발생하지 않으며, 기존 세션으로 지속적인 서비스를 하도록 하는 기능이다.

새롭게 제공하는 Failback 기능은 위의 1차적인 장애 상황에 대한 고려가 아닌, 연속적인 서버의 재시작 또는 장애 서버의 복구시에 제공되는 서비스이다. 해당 부분은 단순한 예로 순차적으로 서버를 재기동 하는 시나리오로 설명한다.

다음 그림은 Failback를 지원하지 않는 상태에서의 진행 상황에 대한 설명이다.

figure session fail back1
Failback을 지원하지 않는 경우

처음 Server1이 재기동되면 Server1이 가지고 있던 세션 "A"는 Server2의 백업에만 존재하게 된다. 다음으로 Server2가 재기동되면 Server2의 백업이 제거되기 때문에 세션 "A"는 전체 시스템에서 제거되게 된다. 만약 이후 세션 "A"의 요청이 온다면 세션 유지에 실패하게 되고 새로운 세션이 생성된다. 이는 기존의 분산식 세션 서버에서는 백업으로 받은 세션에 대한 처리를 수행하지 않았기 때문이다.

다음은 Failback를 지원하는 경우 결과이다.

figure session fail back2
Failback을 지원하는 경우

처음 Server1이 재기동되었을 경우 DumpToBackup에 의한 동작은 동일하다(세션 "B"가 유지되는 모습). 이후 추가적으로 Failback 기능에 의해 Server2가 지닌 세션 "A"가 다시 Server1로 전달되는 모습을 확인할 수 있다.

다음으로 Server2가 재기동되었을 경우에도 최초 환경과 동일하게 세션들이 유지되는 모습을 확인할 수 있다.

Failback을 지원하지 않더라도, 서버 장애가 발생하였을 때 특정 세션에 대한 액세스가 일어난다면 해당 세션은 정상적으로 유지 된다(Failover 기능). 이는 백업 세션의 존재로 가능하며, 이렇게 액세스된 세션은 다시 백업으로 전달되기 때문에(dumpToBackup) 추후에도 정상 동작이 가능해진다. 이를 위해 특정 웹 서버에서는 기존의 모든 세션에 대한 액세스를 수행하여 세션 유지를 위해 노력하기도 하였다.

Failback 기능은 기본적으로 설정에 의해 reply-response 방식으로 이뤄지게 된다.

기능의 시작은 자신이 백업 서버로 동작하였던 서버의 재기동을 감지함으로써 시작된다.

  1. 특정 서버가 재기동되었으며 해당 서버의 세션을 자신이 백업 받았는지 파악한다.

  2. Fail-back 설정이 true이면 기존에 서버로부터 받은 백업 세션들을 재기동된 서버에게 전송한다.

OOM으로 인한 장애 현상이 있을 경우 해당 기능은 권장하지 않는다. 세션의 과부하로 인해 많은 세션을 백업하였을 경우, Failback에 의해 지속적인 OOM을 유발할 수 있다. 해당 기능은 기존 세션의 끊김없이 서버를 순차적으로 재기동할 경우 롤링 패치 적용의 경우를 위해 제공된다.

6. 세션 클러스터 모드

본 절에서는 세션 클러스터 모드에 대해 설명한다.

세션 클러스터링은 단순히 생각하면 세션의 공유를 지원하는 기능이라고 할 수 있다. 세션의 공유는 동일한 스코일 경우 지원하는 것이 중요하며, 스코프가 다를 경우 공유를 막는 것도 중요하다.

JEUS에는 3가지 종류의 세션 클러스터 모드를 지원하며 각 모드에 의해 스코프가 결정된다.

6.1. 기본 세션 클러스터 모드

JEUS에서 기본적으로 제공하는 세션 클러스터 모드이다.

서버들을 클러스터링 설정하게 되면 자동적으로 제공되며, 세션 데이터를 클러스터링에 포함된 서버들에서 공유하여 사용할 수 있다. 서블릿의 기본 세션 스코프의 스펙을 준수하기 때문에 여러 개의 애플리케이션이 존재하더라도 서로간 독립적으로 세션관리가 가능하며, 또한 세션 클러스터링의 기본적인 기능들인 장애 상황 극복 및 로드 밸런싱의 처리를 지원한다. 스펙을 준수하여 기본적인 세션 스코프는 애플리케이션이지만, 웹 엔진 세션 매니저에서 제공하는 Session Storage의 Scope 설정을 이용하면 클러스터링 맺은 서버 스코프의 세션 클러스터링이 가능하다.

6.2. 도메인 와이드 세션 클러스터 모드

도메인 전체의 서버에 디플로이되는 모든 애플리케이션을 같은 스코프로 간주하는 세션 클러스터를 지원하는 모드이다.

기본 세션 클러스터 모드의 경우는 클러스터에 의존하기에 해당 클러스터에 의한 구조의 제약사항을 받고 있다. 그 중 서버 클러스터로의 디플로이 대상의 강제라고 볼 수 있다. JEUS 6에서는 각각 컨테이너에 별도의 애플리케이션을 디플로이하고 모든 컨테이너의 세션을 공유하여 사용할 수 있었으며 해당 구조를 직관적인 구조에 의해 많이 사용되었다.

다음은 좀더 자세한 예에 대한 설명이다.

  • 2개의 노드가 존재하고 각각 2개의 컨테이너를 생성한다.

  • 각 컨테이너에는 별도의 애플리케이션을 디플로이한다. 즉, 총 4개의 애플리케이션이 별도의 컨테이너에 존재한다.

  • 결과적으로 4개의 각 다른 컨테이너의 모든 세션은 공유된다.

서버 클러스터의 기본 개념과 맞지 않다. 클러스터링을 맺을 경우 디플로이 대상이 클러스터로 강제되기 때문에 모든 서버에 동일한 애플리케이션이 디플로이된다. 정상적 상황 속에 안정적인 서버에서 이러한 강제된 디플로이는 불필요한 리소스 낭비라고 보는 시선이 존재한다. 하지만 클러스터링을 맺었음에도 디플로이된 애플리케이션이 물리적으로 특정 서버에만 존재하여 장애 상황에 서비스를 정상적으로 하지 못하는 것을 막아주는 올바른 방향이다. 이러한 상황속에서도 물리적으로 서버마다 다른 애플리케이션을 디플로이하기 위해서는 클러스터에 참여해서는 불가능하다.

서버 클러스터에 참여하지 않고 세션 클러스터링을 사용하고자 할 때 이 모드를 선택하면 된다.

DOMAIN_WIDE 모드는 도메인 구조의 자체 스펙에 어긋나는 사용자 편의를 위한 설정이며 가장 넓게 또한 편리하게 사용할 수 있지만 제약사항에 유의해야 한다.

  • EJB와는 관계가 없고, 오직 웹 애플리케이션에만 영향을 미친다.

  • 클러스터링 설정과 동시에 설정할 경우 클러스터의 설정은 무시될 수 있다.

  • 설정할 경우 도메인 내(domain.xml)의 모든 서버에 대해 적용된다. 일부 서버만을 대상으로 설정하는 것은 불가능하다.

서버 클러스터링을 맺었더라도 도메인 와이드 모드를 사용하면 도메인 와이드 세션 클러스터 모드가 동작한다.

6.3. 세션 스토리지 스코프 클러스터 모드

스토리지에 포함된 애플리케이션이나 클러스터끼리 같은 스코프로 간주하는 세션 클러스터 모드이다.

세션 스토리지 스코프 클러스터 모드는 기본적인 클러스터링 구성과 관계없이 특정 애플리케이션이나 클러스터를 그룹화 하여 세션을 공유하며, 그룹이 여러개 존재할 경우 사용하는 세션 클러스터링이다. 대부분의 경우는 공유하는 그룹이 1개이기 때문에 위의 기본적인 스코프나 도메인 스코프의 모드 사용으로 대부분 해결이 가능하다. 지원되는 세션 클러스터링 자체는 스코프만 차이가 있을 뿐 내부적 동작은 중앙식/분산식 세션 서버와 동일하다. 세션 스토리지 스코프 기능으로 클러스터 간의 세션 공유도 가능하며, 한 서버 안에서 여러 개의 스코프를 구성하는 것이 가능하다. 기존의 특별 정의 스코프 세션 클러스터를 대신하여 사용 할 수 있다.

7. 세션 서버 설정

본 절에서는 세션 클러스터링의 설정 중 기본 설정에 대해 설명한다.

세션 클러스터링은 단순히 생각하면 세션의 공유를 지원하는 기능이라고 할 수 있다. 세션 공유 지원을 위해서 웹 엔진에는 세션 서버가 운영되며 해당 세션 서버가 위에서 설명한 여러 가지 기능에 대한 동작을 수행한다. 해당 동작에 대한 설정을 세션 서버 설정이라고 한다. 해당 세션 서버의 운영에 대한 설정 외에 도메인 전체적으로 운영되는 기본 설정을 한다.

세션 서버에 대한 설정은 domain.xml과 console을 통해 설정할 수 있다.

<session-server>
    <cluster-mode>DEFAULT</cluster-mode>
    <session-storage>
        <name>jeus-session-storage</name>
        <session-manager-provider>JEUS</session-manager-provider>
        <scope>
            <name>jeus-distributed-scope</name>
            <jeus-session>DISTRIBUTED</jeus-session>
            <session-config>
                <timeout>30</timeout>
                <max-session-count>-1</max-session-count>
                <reload-persistent>false</reload-persistent>
                <tracking-mode>
                    <cookie>true</cookie>
                    <url>false</url>
                    <ssl>false</ssl>
                </tracking-mode>
                <session-cookie>
                    <cookie-name>JSESSIONID</cookie-name>
                    <url-cookie-name>jsessionid</url-cookie-name>
                    <version>0</version>
                    <max-age>-1</max-age>
                    <path>/<path>
                    <secure>false</secure>
                    <http-only>true</http-only>
                    <same-site>Disable</same-site>
                    <partitioned>false</partitioned>
                </session-cookie>
            </session-config>
            <target-cluster>cluster1</target-cluster>
        </scope>
        <scope>
            <name>jeus-central-scope</name>
            <jeus-session>CENTRAL</jeus-session>
            <session-config>
                <timeout>30</timeout>
                <max-session-count>-1</max-session-count>
                <reload-persistent>false</reload-persistent>
                <tracking-mode>
                    <cookie>true</cookie>
                    <url>false</url>
                    <ssl>false</ssl>
                </tracking-mode>
                <session-cookie>
                    <cookie-name>JSESSIONID</cookie-name>
                    <url-cookie-name>jsessionid</url-cookie-name>
                    <version>0</version>
                    <max-age>-1</max-age>
                    <path>/<path>
                    <secure>false</secure>
                    <http-only>true</http-only>
                    <same-site>Disable</same-site>
                    <partitioned>false</partitioned>
                </session-cookie>
            </session-config>
            <target-application>sessionTest.war</target-application>
        </scope>
    </session-storage>
    <property>
        <key>encoding-rule</key>
        <value>BASE64</value>
    </property>
    <jeus-login-manager>
        <login-manager-type>REDIS</login-manager-type>
        <primary>server1</primary>
        <secondary>server2</secondary>
        <property>
            <key>redis-nodes</key>
            <value>redis://localhost:6379</value>
        </property>
    </jeus-login-manager>
    <jeus-central-session-server>
        <primary>server1</primary>
        <secondary>server2</secondary>
    </jeus-central-session-server>
</session-server>
  • 기본 설정

    다음은 도메인 전체에 적용되는 기본 설정 부분이다. domain.xml을 통해 항목 수정이 가능하다.

    항목 설명

    cluster-mode

    • DEFAULT : 서버 클러스터를 맺을 경우 세션 클러스터를 지원하고 서버 클러스터를 맺지 않을 경우 세션 클러스터를 지원하지 않는다. 애플리케이션 단위의 세션 클러스터가 기본적으로 제공된다. (기본값)

    • DOMAIN_WIDE : 전체 도메인의 모든 서버의 모든 애플리케이션의 세션을 공유하는 세션 클러스터를 지원한다.

    각 세션 클러스터링 모드는 스코프만 다를 뿐 동일한 형식의 분산식 세션 서버의 설정을 사용한다. 세션 스토리지 관련 설정하는 방법은 아래에서 설명한다.

    property

    property에 들어갈 수 있는 key들은 2가지가 있다.

    • excluded-servers : 클러스터에 포함되지 않을 서버의 이름을 나열한다. 구분자는 콤마(,)로 한다.

    • encoding-rule : 스티키 라우팅의 대상이 되는 정보에 대해 인코딩 룰을 지원한다. 현재는 세 가지의 방식을 지원한다.

      • BASE64 : 설정의 기본값으로 스티키되는 정보를 BASE64 룰에 의해 인코딩하여 전달된다. 세션 아이디를 통해 엔진정보나 도메인 정보가 노출되는 것을 원치 않아 직관적으로 의미 없는 정보로 보이도록 인코딩하여 전달한다. (기본값)

      • BASE64_WITHOUT_PADDING : 설정의 기본값으로 스티키되는 정보를 BASE64 룰에 의해 인코딩 후 PADDING("=") 없이 전달된다.

      • RAW : 스티키되는 정보를 인코딩하지 않고 그대로 노출하여 전달한다. 인코딩되는 정보는 내부에서도 직관적으로 어떤 엔진에서의 요청인지에 대한 판단이 어렵기에 디버깅을 위해 설정하거나, 엔진 이름 노출이 보안상 영향을 주지 않을 경우에 설정한다.

    property는 console을 통해서도 설정이 가능하다. JEUS Reference 안내서의 set-sessionserver-property를 참고한다.

  • Session Storage 영역

    domain.xml 또는 console 명령어를 이용하여 추가/수정/삭제가 가능하다.

    JEUS Reference 안내서의 세션 관련 명령어를 참고한다.

    항목 설명

    Name

    스토리지의 이름이다.

    Session Manager Provider

    세션 매니저로 사용할 구현체를 설정하거나 예약어를 설정한다. 예약어 외에는 package 전체 이름을 설정해야 한다.

    설정 가능한 예약어는 4가지가 존재한다. 해당 예약어에 대한 설명은 표 아래의 [예약어] 설명을 참고한다.

    Property

    해당 스토리지에서 사용 할 프로퍼티를 설정한다. Property에서 유효한 키는 표 아래의 [Property 유효한 키] 설명을 참고한다.

[예약어]

다음은 Session Storage 설정의 'Session Manager Provider' 항목에 설정 가능한 예약어에 대한 설명이다.

  • JEUS

    JEUS에서 제공하는 다른 구현체가 존재하더라도 JEUS의 구현체를 사용한다. (기본값)

  • REDIS

    Session Storage로써 Redis를 사용한다. Redis는 5버전 이상을 지원한다. Redis에 대한 설정은 session-storage의 property에 입력한다.

    다음은 유효한 키에 대한 설명이다.

    • Redis의 아키텍처를 입력한다. 아키텍처에는 standalone과 cluster가 있다. (기본값: standalone)

      예시
      <key>redis-architecture</key>
      <value>standalone</value>
    • Redis의 노드를 입력한다. 아키텍처가 클러스터인 경우 콤마(,)로 클러스터 멤버를 기재한다. (기본값: redis://localhost:6379)

      예시
      <key>redis-nodes</key>
      <value<redis://127.0.0.1:7006,redis://127.0.0.1:7007,redis://127.0.0.1:7008</value>
  • HAZELCAST

    Session Storage로써 Hazelcast를 사용한다. Hazelcast는 4.2 버전을 지원한다. Hazelcast에 대한 설정은 session-storage의 property에 입력한다.

    다음은 유효한 키에 대한 설명이다.

    • Hazelcast의 아키텍처를 입력한다. 아키텍처에는 standalone과 cluster가 있다. (기본값: standalone)

      예시
      <key>hazelcast-architecture</key>
      <value>standalone</value>
    • Hazelcast의 노드를 입력한다. (기본값: localhost:5701)

      예시
      <key>hazelcast-nodes</key>
      <value>localhost:5702</value>
    • Hazelcast의 cluster를 입력한다. (기본값: dev)

      예시
      <key>hazelcast-cluster</key>
      <value>dev</value>
  • RUNTIME

    JEUS에서 제공하는 프로바이더 외 다른 구현체가 존재한다면 해당 구현체를 사용하도록 설정한다. 다른 구현체가 존재하지 않는다면 JEUS에서 제공하는 세가지 중 하나로 선택된다.

[Property 유효한 키]

다음은 Session Storage 설정의 'Property' 항목에 대한 추가 설명이다.

  • Provider가 JEUS일 때

    항목 설명

    reserved-thread-num

    분산식 세션 서버로 들어온 요청을 처리하기 위한 Thread Pool에 대해 부가적인 설정이다. 기본적으로 System Thread Pool을 사용하기 때문에 특별히 설정할 필요는 없다. 이 서비스를 위한 Thread를 미리 할당할 필요가 있을 경우에만 설정하기를 권장한다.

    connection-timeout

    웹 엔진에 존재하는 세션 서버 간의 소켓 커넥션을 생성할 때 적용되는 Timeout 값이다.

    read-timeout

    웹 엔진에 존재하는 세션 서버 간의 통신에 적용되는 Read Timeout 값이다. 데이터를 보낸 후 응답을 최대 이 시간만큼 기다린다.

    backup-level

    사용된 세션을 리모트 웹 컨테이너 또는 로컬 파일 데이터베이스에 백업할 때 사용된 세션에 대한 기준을 설정한다.

    • access : 세션 Attribute 별로 update를 수행하며 해당 객체는 setAttribute/putValue/removeAttribute/removeValue/getAttribute/getValue 함수 호출한 특정 Attribute 들 만을 백업한다. (기본값)

    • set : 해당 세션의 setAttribute/putValue/removeAttribute/removeValue 함수 호출이 발생한 경우에만 업데이트된 것으로 간주하여 해당 세션 객체를 백업한다.

    • get : 해당 세션의 setAttribute/putValue/removeAttribute/removeValue/getAttribute/getValue 함수 호출이 발생한 경우에만 업데이트된 것으로 간주하여 해당 세션 객체를 백업한다.

    • all : 사용된 세션은 모두 백업한다. 해당 세션 객체가 HttpServletRequest.getSession() API로 호출될 경우 업데이트된 것으로 간주하여 해당 세션 객체를 백업한다.

    backup-unit-size

    세션의 백업을 수행할 때의 단위에 대한 설정이다. 최대로 함께 보낼 갯수를 설정한다.

    backup-queue-size

    네트워크 지연으로 인해 백업이 정상적으로 전송되지 못할 경우 대기하는 큐 사이즈에 대한 설정이다. 분산식 세션 서버에서 백업이 존재하지 못할 경우 장애 상황에 세션 유지에 실패하기 때문에 해당 큐에 가득찰 경우 요청은 자연스럽게 지연되어 플로우 컨트롤된다.

    backup-flowcontrol-enabled

    백업 큐가 가득 차더라도 서비스를 지속적으로 수행하고자 할 때 설정하는 옵션으로 세션 유실보다 서비스가 우선시 될 경우에 사용된다.

    failover-delay

    장애 상황에서 해당 엔진의 복구를 기다리는 시간을 설정한다.

    웹 엔진에 장애가 발생했을 때 해당 엔진을 제외한 나머지 엔진에서 다시 클러스터링 연결을 맺을 Timeout 값이다.

    restart-delay

    웹 엔진을 정상적으로 다운시켰을 때 해당 엔진을 제외한 나머지 엔진에서 다시 클러스터링 연결을 맺을 Timeout 값이다. 다운되는 가장 많은 케이스인 재기동의 성능향상을 위한 설정이다.

    user-info

    user 정보를 가지고 올 수 있는 경로를 입력한다.

    login-manager

    로그인 매니저의 사용여부를 선택한다.

    • false (기본값)

    • true

    login-manager-strategy

    로그인 매니저의 방법을 선택한다.

    • invalidate-before : 중복 로그인 시 이전 세션을 invalidate한다. (기본값)

    • invalidate-after : 중복 로그인 시 나중 세션을 invalidate한다.

  • Provider가 REDIS일 때

    항목 설명

    redis-nodes

    Redis의 노드를 입력한다. 아키텍처가 클러스터인 경우 콤마(,)로 클러스터 멤버를 기재한다. (기본값: redis://localhost:6379)

    redis-architecture

    Redis의 아키텍처를 입력한다. 아키텍처에는 2가지가 있다.

    • standalone (기본값)

    • cluster

  • Provider가 HAZELCAST일 때

    항목 설명

    hazelcast-nodes

    Hazelcast의 노드를 입력한다. (기본값: localhost:5701)

    hazelcast-cluster

    Hazelcast의 cluster를 입력한다. (기본값: dev)

    hazelcast-architecture

    HAZELCAST의 아키텍처를 입력한다. 아키텍처에는 2가지가 있다.

    • standalone (기본값)

    • cluster

  • Scope 영역

    항목 설명

    name

    Scope의 이름이다.

    jeus-session

    Jeus session을 사용할 경우 분산식을 사용할 지, 중앙식을 사용할 지에 대한 설정이다. Storage의 provider가 Redis나 Hazelcast일 경우는 해당 설정은 무시된다.

    • DISTRIBUTED: 분산식 세션을 사용할 경우에 설정한다.

    • CENTRAL: 중앙식 세션을 사용할 경우에 설정한다.

    target

    scope에 포함될 applitaion 또는 cluster를 설정한다. (둘 중 하나만 설정)

    • target-application: 해당 스코프에 포함될 애플리케이션을 지정한다.

    • target-cluster: 해당 스코프에 포함될 클러스터를 지정한다.

    session-config

    해당 스코프에 포함된 컨텍스트에서 사용할 세션 설정이다. 상세 설정은 세션 설정을 참고한다.

    • jeus-central-session-server 영역

      JEUS 자체 Session Server로 사용할 server를 설정한다. domain.xml 또는 console 명령어를 통해 항목 수정이 가능하다. JEUS Reference 안내서의 set-jeus-central-session-server를 참고한다.

      항목 설명

      primary

      Primary Session Server를 설정한다. 동적 변경이 불가능하다.

      secondary

      Secondary Session Server를 설정한다. 동적 변경이 불가능하다.

    • jeus-login-manager 영역

      Jeus Login Manager를 사용할 경우 설정한다. domain.xml을 통해 항목 수정이 가능하다.

      항목 설명

      login-manager-type

      Login Manager로 사용할 구현체를 설정하거나 예약어를 설정한다.

      예약어는 다음과 같이 세 가지가 존재한다.

      • JEUS: JEUS에서 제공하는 다른 구현체가 존재하더라도 JEUS의 구현체를 사용한다.

      • REDIS: Session Storage로써 Redis를 사용한다. Redis는 5버전 이상을 지원한다. Redis에 대한 설정은 property에 입력한다.

      • HAZELCAST: Session Storage로써 Hazelcast를 사용한다. Hazelcast는 4.2버전을 지원한다. Hazelcast에 대한 설정은 property에 입력한다.

      primary

      JEUS Login Manager의 Primary 서버를 설정한다. 동적 변경이 불가능하다. 해당 설정은 'Login Manager' 항목이 'JEUS’일 때만 유효하다.

      secondary

      JEUS Login Manager의 Secondary 서버를 설정한다. 동적 변경이 불가능하다. 해당 설정은 'Login Manager' 항목이 'JEUS’일 때만 유효하다.

      property

      JEUS Login Manager에서 사용할 프로퍼티를 설정한다.

      다음은 Property에서 유효한 키에 대한 설명이다.

      • 'Login Manager' 항목이 'REDIS’일 때

        • redis-nodes : Redis의 노드를 입력한다. 아키텍처가 클러스터인 경우 콤마(,)로 클러스터 멤버를 기재한다. (기본값: redis://localhost:6379)

          예시
          <key>redis-nodes</key>
          <value>redis://127.0.0.1:7006, redis://127.0.0.1:7007,redis://127.0.0.1:7008</value>
      • 'Login Manager' 항목이 'HAZELCAST’일 때

        • hazelcast-nodes : Hazelcast의 노드를 입력한다. (기본값: localhost:5701)

          예시
          <key>hazelcast-nodes</key>
          <value>localhost:5702</value>
        • hazelcast-cluster : Hazelcast의 cluster를 입력한다. (기본값: dev)

          예시
          <key>hazelcast-cluster</key>
          <value>dev</value>