세션 이슈로 최근 며칠 토스트 클라우드 LB의 로드밸런싱 정책 및 세션 관련 옵션에 대해 알게된 것들을 공유해드리고자 글을 작성했습니다.
로드밸런싱 정책
로드밸런싱 정책의 경우 가이드(http://docs.toast.com/ko/Network/Load%20Balancer/ko/overview/) 페이지에 잘 나와있지만 간단히 정리하면 아래와 같습니다.
1. Round Robin
단순히 순차적으로 리스너를 선택하는 방식(이와 유사하게 Weighted round robin 방식은 리스너에 가중치를 부여하여 각 리스너가 1:1 비율이 아닌 리스너별로 비율(가중치)를 설정하여 라운드 로빈하는 방식으로, 토스트 클라우드에서 지원하고 있지는 않지만 참고하시면 좋을 것 같습니다)
2. Least Connections
현재 커넥션 연결 수가 가장 적은 리스너를 선택하는 방식
3. Source IP
클라이언트(출발지) 아이피에 따라 리스너를 선택하는 방식으로 동일 아이피에서의 접속은 동일 리스너로 전달됩니다. 소스 아이피를 해싱(고정된 길이의 데이터로 매핑)하여 리스너와 매핑 테이블을 만드는 방식으로 해쉬(Hash)방식이라고도 부릅니다.
위에 기재한 세 가지 로드밸런싱 정책 중 세션 지속성이 보장되는 방식은 Source IP 방식입니다. 나머지 라운드로빈 방식과 최소연결 방식은 접속할 때마다 리스너가 변경될 수 있기 때문에 세션을 유지해야하는 페이지의 경우 문제가 생길 수 있습니다. 반대로 Source IP 방식은 세션 지속성은 보장되지만 모든 트래픽이 각 리스너로 균등하게 전달되지는 않습니다.
Cookie를 이용한 세션 지속성
HTTP 통신은 기본적으로 stateless(상태를 저장하지 않는 통신) 프로토콜로 이전 통신의 상태가 다음 통신의 상태에 영향을 주지 않지만, 로그인 등 상태 정보를 유지하기 위해 WAS에서는 session을 이용하여 일정 시간 사용자의 상태를 stateful(상태를 저장하는 통신)하게 유지합니다. WAS 에서는 클라이언트 최초 접속 시 Set-Cookie 헤더를 이용하여 session id 값과 매칭되는 일종의 키를 발급하고, 이후 접속 시 클라이언트가 보내오는 cookie를 통해 접속한 클라이언트가 해당 session의 주인이 맞는지 검증합니다. Cookie를 이용한 세션 지속성을 유지하는 방법은 크게 2가지입니다.
1. 클라이언트가 가진 쿠키 값에 따라 매번 동일한 WAS로 연결되도록 하는 방법
이 방법은 WAS로 도달하기 전에 로드밸런서에서 설정 가능한 방법입니다.
2. 어떤 WAS로 접속되든 session을 유지하도록 session 정보를 WAS에서 분리하는 방법
session은 기본적으로 WAS 서버 로컬에 저장되기 때문에 동일한 역할의 WAS를 다수 구성하여 분산처리를 하는 경우 세션을 WAS 로컬이 아닌 별도의 저장소(대표적으로 redis)에 저장하여 모든 WAS가 동일한 세션 정보를 공유하도록 할 수 있습니다. 이것을 세션 클러스터링이라고 합니다.
IP를 이용한 세션 지속성
다수의 WAS가 구성되어 있는 경우 클라이언트에서 어떤 WAS로 접속이 이뤄질지 알 수 없기 때문에 동일한 클라이언트에서의 접속이 매번 동일한 WAS로 연결되도록 클라이언트의 아이피주소와 리스너를 매핑하는 방법으로 WAS로 도달하기 전에 로드밸런서에서 설정 가능한 방법입니다.
토스트 클라우드 로드밸런서
토스트 클라우드 로드밸런서에서 사용 가능한 세션 지속성 옵션은 아래와 같이 3가지이며, 자세한 내용은 가이드(http://docs.toast.com/ko/Network/Load%20Balancer/ko/overview/#_6)에서 확인이 가능합니다.
Source IP
로드밸런싱 정책에서의 Source IP 방식과 완전히 동일합니다. 하지만 Round Robin 방식 혹은 Least Connections 방식과 조합하여 설정할 수 있다는 점이 다릅니다.(Least Connections 방식과 조합하여 사용하는 경우 초기 접속은 현재 커넥션 수가 적은 리스너로 선택하되, 이후 접속부터는 클라이언트 아이피주소에 따라 리스너를 선택)
HTTP Cookie
초기 접속 시 연결될 리스너 정보를 담은 SRV라는 이름의 쿠키를 클라이언트에게 발급하고, 이후 접속 시 SRV 쿠키에 포함된 리스너 정보를 확인하여 동일 리스너로 프록시하는 방식, SRV쿠키는 로드밸런서를 지날 때 제거되어 기존 쿠키만 리스너로 전달됩니다.
APP Cookie
초기 접속 시 리스너(WAS)에서 발급한 쿠키 중 지정한 쿠키에 리스너 정보를 기존 쿠키 앞단에 이어붙이고, 이후 접속 시 해당 쿠키에 포함된 리스너 정보를 확인하여 리스너를 결정하는 방식, 예를들어 톰캣의 쿠키인 JSESSIONID로 APP Cookie를 지정한 경우 기존 쿠키인 "JSESSIONID=FFC272D158C65B88D9D4AD6B1505A9D7"에 리스너 정보인 "23246355-c66b-4e6a-90ff-473f66336c1d"를 더해 "JSESSIONID=23246355-c66b-4e6a-90ff-473f66336c1d~FFC272D158C65B88D9D4AD6B1505A9D7" 와 같이 쿠키가 구성되고 추가된 리스너 정보는 로드밸런서를 지날 때 제거되어 기존 쿠키만 리스너로 전달됩니다.
참고로 토스트 클라우드 가이드 문서(http://docs.toast.com/ko/Network/Load%20Balancer/ko/overview/#_6)에 Keepalive timeout 옵션에 대한 설명은 아래와 같이 되어 있습니다.
[참고] 로드 밸런서에 TCP 세션 연결 유지시간을 설정할 수 있습니다. Keepalive timeout 값을 설정하여 클라이언트와 로드 밸런서, 로드 밸런서와 서버간 세션 유지 시간을 조정할 수 있습니다.
하지만 여기서 말하는 Keep-alive timeout 옵션의 세션은 HTTP 최초 요청이 있었을 때 새로운 HTTP 소켓이 열리고 서버에서 클라이언트로 응답을 전송한 후에 다음 요청까지 소켓을 열어둔 채로 유지하여 TCP 세션을 유지하는 keep-alive timeout 값으로 위에서 말하는 WAS 세션의 timeout과는 다른 의미의 용어이기 때문에 혼동하지 않도록 유의해야합니다. 톰캣의 경우 $CATALINA_HOME/conf/web.xml 파일에 아래와 같이 WAS 세션 타임아웃을 분 단위로 설정 가능하니 참고하시면 좋을 것 같습니다.
<!-- ==================== Default Session Configuration ================= -->
<!-- You can set the default session timeout (in minutes) for all newly -->
<!-- created sessions by modifying the value below. -->
<session-config>
<session-timeout>30</session-timeout>
</session-config>