본 포스트는 제우스에서 세션 확인 및 유지를 위해 jSessionId를 사용할 때 주의사항에 대한 포스트입니다.

 

HTTP 프로토콜은 기본적으로 Stateless 합니다. 클라이언트에서 서버에 요청할 때마다 새로운 연결을 생성하고 응답을 받은 후에는 연결을 끊어 버리기 때문에 상태를 유지할 수가 없습니다.

 

jSessionId

그래서 대부분의 WAS Container에서는 jSessionId라는 값을 발급합니다. 브라우저나 혹은 앱의 HttpClient 등 클라이언트가 최초에 JEUS에 접근하면 Response Header에 jSessionId 값을 발급하여 응답합니다. 클라이언트는 이후 요청부터는 이 jSessionId를 Request Header의 Cookie에 넣어서 요청합니다.

 

이 값을 Key로 서버에서는 세션 영역을 사용하고 유지할 수 있고, Request Header에 jSessionId가 전달되었을 경우에는 새로운 jSessionId를 발급하지 않습니다.

 

중복 로그인 방지

보통 서비스에서 동시 로그인을 허용하지 않을 경우 [사용자 아이디 + jSessionId] 값으로 동일한 사용자가 여러 경로로 접속했는지를 판단합니다. 사용자가 로그인을 하면 테이블에 현재 로그인한 jSessionId 값을 저장하고 매 트랜잭션에서 현재 동일한 사용자 아이디로 다른 jSessionId에서 접속하고 있지 않은지 검사합니다.

 

아래와 같은 테이블을 사용합니다. (별도의 테이블을 사용할 수도 있고, 사용자 원장을 사용할 수도 있습니다.)

-- USER table
USER_ID VARCHAR(20),
SESSION_ID VARCHAR(100)

사용자가 로그인에 성공하면 SESSION_ID를 현재 Request 영역에 전달된 jSessionId로 Update 합니다.

UPDATE  USER
   SET  SESSION_ID = ${jSessionId}
 WHERE  USER_ID = ${userId}

애플리케이션에서 비교 로직은 테이블에서 해당 사용자의 SESSION_ID를 읽어 현재 Request 영역의 jSessionId와 비교합니다.

String sessionId = userVo.getSessionId();
String jSessionId = request.getSession().getId();

if (!jSessionId.equals(sessionId)) {
	throw new Exception(~~~);
}

 

이중화 환경일 경우

AP 인스턴스가 여러 대일 경우에도 세션 클러스터링 설정을 해두었으므로 세션을 잘 복제가 됩니다. 하지만 위 로직으로 중복 로그인 방지를 구현했을 경우 접속하는 인스턴스가 변경될 경우 로그인이 풀리는 현상이 발생했습니다.

부하 분산을 Sticky Round Robin 방식으로 하여, 사용자가 접속하는 인스턴스의 변경이 거의 발생하지는 않지만 그래도 인스턴스 별 reboot 등의 작업을 수행할 때 사용자들이 불편을 겪곤 했습니다.

 

JEUS의 경우 세션 클러스터링을 하면 동일한 jSession 아이디로 잘 복제가 되지만 아래와 같이 인스턴스 구분자가 postFix로 추가됩니다. 

17:31:33.406 jSession ID : aaaaaaaaaaaaaaaaaaaaa.xyz01 -> inst01 접속 시
17:31:33.406 jSession ID : aaaaaaaaaaaaaaaaaaaaa.vwy01 -> inst03 접속 시

하여 JEUS의 세션 클러스터링 환경에서 중복 로그인 방지 등을 구현할 때는 위의 로직이 아니라 postFix 앞 쪽만 비교하는 로직으로 변경이 필요합니다. 예를 들면 아래와 같습니다.

String sessionId = (userVo.getSessionId().indexOf(".") > -1) ? userVo.getSessionId().substring(0, userVo.getSessionId().indexOf(".")) : userVo.getSessionId();
String jSessionId = (request.getSession().getId().indexOf(".") > -1) ? request.getSession().getId().substring(0, request.getSession().getId().indexOf(".")) : request.getSession().getId();

if (!jSessionId.equals(sessionId)) {
	throw new Exception(~~~);
}
300x250

JEUS 7에서 운영 중인 솔루션에 기능을 add-on 하면서 솔루션의 Spring framework 버전을 4.1.6에서 4.3.18로 올렸더니 아래와 같은 오류가 나며 WAS가 구동되지 않는 현상이 있었습니다.

java.lang.illegalStateException: zip file closed
	at java.util.zip.ZipFile.ensureOpen(ZipFile.java:634)
    at java.util.zip.ZipFile.getEntry(ZipFile.java:305)
    at java.util.jar.JarFile.getEntry(JarFile.java:227)
    ...

처음엔 신규 솔루션 인스턴스를 추가하면서 WAS 설정이 잘못된 게 아닌가 한참을 찾았지만 혹시나 하고 Spring framework 버전을 4.2.x 버전으로 낮추어 보았더니 Container가 정상 구동되었습니다.

 

구글링으로는 관련 내용이 잘 나오지 않았고, JEUS 제조사인 티맥스 온라인 메뉴얼을 찾아보니 아래와 같은 내용을 발견할 수 있었습니다.

설치되어 있는 JEUS 버전을 확인해 보니, Fix #4 였고 엔지니어의 협조를 받아 Fix #5로 업데이트 한 후에는 문제를 해결할 수 있었습니다.

 

JEUS 온라인 매뉴얼 링크입니다.

https://technet.tmaxsoft.com/upload/download/online/jeus/pver-20171211-000001/release-note/chapter_jeus_7_5.html#d4e1595

 

제2장 JEUS 7 Fix#5

본 장에서는 JEUS 7 Fix#5 릴리즈에서 추가된 새로운 기능과 변경된 기능에 대해 간략히 설명한다. 본 절에서는 JEUS의 신규 추가사항에 대하여 설명한다. deploy target이 all-target인 경우 DAS에는 deploy되

technet.tmaxsoft.com

 

300x250

+ Recent posts