개요
지난 시간에 서버의 성능을 업그레이드하는 두 가지 방법을 알아보았습니다. 그중 스케일 아웃을 하면 여러 대의 서버가 각각 세션 저장소를 독립적으로 갖게 되므로 정합성 이슈가 발생하였습니다. 이번 시간에는 스케일 아웃을 하였을 때 세션을 어떻게 공유하여 정합성 이슈를 해결하는지에 대해 알아보겠습니다.
Multi Server 환경에서 Session이 어떻게 구성되는지 다시 한번 볼까요?
보시는 바와 같이 세션은 서버 1대에 하나의 저장소가 형성됩니다. 지난 시간에 알아보았듯이 나누어진 세션 저장소에 대한 별도의 처리가 없다면 각각의 세션들은 정합성 이슈를 발생시킵니다. 위 그림처럼 여러 대로 나뉜 서버가 하나의 서비스를 운영하기 위해서는 4개의 분리된 세션을 하나의 시스템처럼 동작하게 하거나, 고정된 세션을 사용하여야 합니다.
먼저 Sticky Session을 사용하여 세션을 유지하는 방법에 대해 간단히 알아보겠습니다.
Sticky Session 방식은 어떻게 세션을 유지할까?
Sticky Session 이란 말 그래로 고정된 세션을 의미합니다. 아래 그림을 먼저 보겠습니다.
예를 들어, User1 이 1번부터 3번까지의 서버 중 1번 서버에 세션을 생성하였다면, 이후에 User1이 보내는 모든 요청은 1번 서버로만 보내지게 됩니다. 즉, Load Balancer는 User가 첫 번째 세션을 생성한 서버로 모든 요청을 리다이렉트 하여 고정된 세션만 사용하게 합니다.
이를 위해서 로드 밸런서는 요청을 받으면 가장 먼저 요청에 쿠키가 존재하는지 확인합니다. 쿠키가 있으면 해당 요청이 쿠키에 지정된 서버로 전송됩니다. 쿠키가 없는 경우에는 로드 밸런서가 기존 로드 밸런싱 알고리즘을 기반으로 서버를 선정합니다.
동일한 사용자가 계속 해당 서버에 요청을 보낼 수 있도록 지속적으로 서버 정보가 쿠키를 통해 응답에 삽입되어 보내집니다.
이러한 방식을 사용하면 유저는 세션이 유지되는 동안 동일한 서버만을 사용하기 때문에 정합성 이슈에서 자유로워질 수 있습니다.
하지만 이 방식에도 단점은 존재합니다.
먼저, 고정된 세션을 사용한다는 것은 특정 서버에 트래픽이 집중될 위험이 있습니다. 왜냐하면 사용자가 접속해야 하는 서버가 정해져 있기 때문에 하나의 서버에 트래픽이 집중되어 있더라도 사용자는 자신의 세션이 없는 다른 서버를 사용할 수 없습니다.
또한, 아래 그림을 보면 알 수 있듯이 서비스 중에 하나의 서버에 장애가 발생하게 되면 해당 서버를 사용하는 사용자들은 세션 정보를 잃어버리게 됩니다. 그러므로 가용성이 떨어지게 됩니다.
Sticky Session을 사용하면 정합성 이슈를 해결할 수 있지만 스케일 아웃의 장점인 가용성과 트래픽 분산을 완벽히 사용할 수는 없어 보입니다.
그렇다면 정합성 이슈를 해결하고, 가용성과 트래픽 분산까지 확보할 수 있는 세션 관리 방식은 없을까요?
지금부터 이를 고려한 세션 클러스터링 방식에 대해 알아보겠습니다!
TOMCAT으로 알아보는 세션 클러스터링!
여러 대의 컴퓨터들이 연결되어 하나의 시스템처럼 동작하도록 만드는 것을 클러스터링이라고 합니다. 서버 또한 컴퓨터로써 여러 대가 하나의 서비스를 하기 위해서는 클러스터링이 필요합니다. Tomcat Document의 내용을 참고하여 세션 클러스터링을 통해 세션을 공유하는 방법에 대해 알아보겠습니다.
- Tomcat 9.0 Document
http://tomcat.apache.org/tomcat-9.0-doc/cluster-howto.html
첨부된 Tomcat 9.0 Document를 보면 톰캣이 세션 클러스터링을 구현하는 방법으로 `DeltaManager` 를 사용하여 all-to-all 세션 복제 방식을 제안합니다.
그렇다면 all-to-all 세션 복제 방식이 무엇일까요?
지금부터 우리가 고민해오던 로그인을 예로 들어서 알아보도록 하겠습니다!
All-to-all Session Replication
all-to-all 세션 복제란 하나의 세션 저장소에 변경되는 요소가 발생하면 변경된 사항이 다른 모든 세션에 복제가 된다는 것을 말합니다.
그림과 같이 세션을 복제한다면 유저가 이후에 어떤 서버에 접속하더라도 로그인 정보가 세션에 복제되어 있으므로 정합성 이슈가 해결 가능합니다. 이로써 서버 하나에 장애가 발생하더라도 서비스는 중단되지 않고 운영 가능합니다. 하지만 Tomcat의 all-to-all 세션 복제 방식은 고려해야 할 단점들이 존재합니다.
우선, 모든 서버가 동일한 세션 객체를 가져야 하기 때문에 많은 메모리가 필요합니다.
또한 세션 저장소에 데이터가 저장될 때마다 모든 서버에 값을 입력해야 하므로 서버 수에 비례하여 네트워크 트래픽이 증가하는 등 성능 저하가 발생하게 됩니다.
그러므로 해당 방식은 소규모 클러스터에서 좋은 효율을 보여줍니다. 4개 이상의 서버를 가진 대규모 클러스터들에는 추천하지 않는 방식입니다.
위에서 언급한 바와 같이 all-to-all 세션 복제 방식을 사용하면 스케일아웃에 한계가 존재하는데 이를 해결할 수 있는 방법은 없을까요?
Tomcat 은 이를 해결할 방법으로 `BackupManager` 을 활용한 primary-secondary 세션 복제 방식을 제시합니다.
그림과 같이 Primary 서버는 Secondary(Backup) 서버에 세션 객체의 Key-Value 전체를 복제합니다. 하지만, 이외의 서버에는 Key에 해당하는 JSESSION ID만을 복제하기 때문에 메모리 사용이 all-to-all 방식보다 줄어들게 됩니다. 세션 객체 전체를 복제하는 시간보다 Key만 복제하는 것이 상대적으로 시간도 절약되겠죠?
그러므로 이러한 방식은 4개 이상의 대규모 클러스터에서 사용이 용이합니다. Tomcat 8.0 버전까지는 공식문서에서 해당 방법이 all-to-all 복제 방식만큼 검증된 방식이 아니라고 명시되어 있었으나, Tomcat 9.0 Document에서 해당 내용이 빠진 것을 미루어 보아 안정화되어 사용할 수 있을 것으로 예상됩니다.
그럼에도 불구하고, 아직 문제점은 존재합니다. 세션을 복제하는데 걸리는 시간은 줄일 수 있었으나, Primay 서버와 Secondary 서버를 제외한 Proxy 서버에 세션 정보를 요청할 경우에는 다시 Primary 서버에 요청하여 해당 Key에 해당하는 객체를 받아와야만 합니다. 이러한 단점도 무시할 수 없겠죠?
이처럼 Tomcat의 세션 클러스터링은 정합성 이슈를 해결할 수 있지만, 성능적인 한계가 존재합니다. 그렇다면 위의 두 방식의 단점을 보완하여 다중 서버에서 세션을 공유할 수 있는 방법은 없을까요?
마지막으로 제가 프로젝트를 하면서 선택한 별도의 세션 서버를 사용하는 방법을 소개하겠습니다.
세션 스토리지 분리를 통해 Scale-Out 시, 발생하는 정합성 이슈를 해결해보자!
세션 스토리지를 분리한다는 건 어떤 것일까요?
이는 기존 서버가 갖고 있는 로컬 세션 저장소를 이용하는 것이 아니라, 별도의 세션 저장소를 사용하는 것을 의미합니다! 어떻게 가능할까요?
아래 그림을 보시면 쉽게 이해하실 수 있습니다.
보시는 바와 같이 세션 스토리지가 분리되면, 서버가 아무리 늘어난다고 할 지라도 세션 스토리지에 대한 정보만 각각의 서버에 입력해주면 세션을 공유할 수 있게 됩니다.
이러한 방식을 사용한다면 로드밸런싱 알고리즘만 잘 구현되어 있다는 가정 하에 Sticky Session처럼 트래픽이 비정상적으로 몰리는 현상을 고려하지 않아도 되게 됩니다.
또한 서버가 하나 장애가 발생하더라도 별도의 세션 저장소가 존재하기 때문에 서비스를 계속해서 제공할 수 있겠죠? 즉, 가용성을 확보할 수 있습니다.
뿐만 아니라 우리가 가장 근본적으로 해결하고자 하던 정합성 문제도 해결할 수 있습니다. 여러 대의 서버가 하나의 세션을 사용하기 때문에 기존에 개별적으로 갖고 있던 로컬 세션 저장소의 데이터 불일치가 발생하지 않기 때문입니다.
무엇보다도 세션 저장소가 하나이기 때문에 데이터 정합성 해결을 위한 별도의 세션 복제를 할 필요가 없어서 이에 대한 성능적인 문제도 해결이 가능합니다.
단, 세션 저장소도 세션 객체를 복제해야 할 필요가 있습니다. 이는 데이터 정합성 문제를 해결하기 위한 것이 아니라, 하나의 세션 저장소를 운영한다는 것은 그만큼 해당 서버에 장애가 발생하면, 모든 세션 이용이 불가하다는 뜻이기 때문에 가용성을 확보하기 위해 동일한 세션 저장소 하나를 더 구성하여 복제하는 것입니다.
그럼 세션을 저장하는 저장소는 무엇을 사용해야 할까요?
이에 대해서 다음 포스팅에 자세히 알아보도록 하겠습니다!
정리해보기
1. Sticky Session 방식은 세션을 최초에 생성한 서버로 요청을 고정하는 방식입니다. 정합성 이슈를 해결할 수 있으나, 로드 밸런싱과 가용성면에서 문제가 있을 수 있습니다.
2. Session Clustering 은 세션을 생성될 때마다 복제하여 각 서버의 세션 정보를 일치시켜 정합성 이슈를 해결합니다. 하지만, 매번 세션 객체를 복제하는데 오버헤드가 발생하므로 사용 시, 이를 고려해야 합니다.
3. 세션 스토리지 분리 방식 별도의 세션 저장소를 사용하는 것으로, 서버가 아무리 늘어난다고 할 지라도 세션 스토리지에 대한 정보만 각각의 서버에 입력해주면 세션을 공유할 수 있게 됩니다.
참고
- Tomcat 8.0 Document, http://tomcat.apache.org/tomcat-8.0-doc/cluster-howto.html
- Tomcat 9.0 Document, http://tomcat.apache.org/tomcat-9.0-doc/cluster-howto.html
- AWS Elastic Load Balancing Document, 클래식 로드 밸런서를 위한 고정 세션 구성, https://docs.aws.amazon.com/ko_kr/elasticloadbalancing/latest/classic/elb-sticky-sessions.html
- New Elastic Load Balancing Feature: Sticky Sessions, https://aws.amazon.com/ko/blogs/aws/new-elastic-load-balancing-feature-sticky-sessions/
- 이것이 레디스다, 정경석 지음, 2015년 2월 2일 전자책 발행본
- 톰캣 운영 노하우, jieunsys, Dec 30, 2015, https://www.slideshare.net/jieunsys/ss-56543446
프로젝트 참고
- Social Network Service AGORA, https://github.com/f-lab-edu/sns-project
다음 포스팅에는!
'다중 서버 환경에서 Session은 어떻게 데이터를 공유하고 관리할까? - 3편 (Disk Based Database vs In-Memory Database)'에 대해 알아보겠습니다!