여러 대의 서버에 흩어져 있는 세션을 어떻게 관리해야할까?

허진혁·2023년 6월 5일
0

🤔 고민 사항

서버에 저장된 세션을 사용자의 로그인을 확인할 수 있는데, 분산시스템에서는 어떻게 확인을 해야하는 것일까?

스프링에서 세션관리

세션은 웹에서 애플리케이션 간에 정보를 일시적인 상태를 유지하기 위해 서버에서 관리를 해줘요. 위 그림과 같이 스프링은 cookie에 JESSIONID 라는 쿠키명에 따른 value를 저장해요. 웹에서 request가 오면 Header에서 쿠키 내 세션아이디를 가져와 식별자로 사용하지요.

⚒ 접근 방법과 해결 과정

문제점

위 그림을 보며 진행해 볼게요. A유저가 로그인 요청을 보내서 Server 1에서 로그인을 성공하고 이제 서비스를 진행하려고 해요.

로그인 한 유저만 SNS에 글을 작성가능 하다고 가정을 할거에요. A유저는 글을 작성하고 글쓰기 완료를 누르려 했는데 인증이 되지 않아 글 작성이 실패하게 되요. 글쓰기 요청은 Server 3에 요청이 갔기 때문이에요.

🤨 '난 로그인했는데 글이 안써지네??' 이렇게 되면 큰 문제가 발생하는 것이죠.

1. Sticky Session

Sticky Session은 세션이 처음 생성된 서버에만 접속이 가능한 방식이에요.

로드 밸런서에 의해 user1의 로그인 요청은 Server1로 보내져 Server1에 user1의 세션 정보가 저장되어 있고, user2의 로그인 요청은 Server3로 보내져 Server3에 user2의 세션 정보가 저장되어 있는 상태가 되요.

이 상태 이후에 각각 유저들의 request 요청들은 로드 밸런서에서 요청을 보낸 사용자의 IP주소나 쿠키로부터 어떤 서버에 고정되어 있는지 확인한 후, 해당 요청을 지정된 서버로 보내게 되죠. 따라서, 사용자는 세션이 유지되는 동안에는 같은 서버를 통해 서비스를 이용할 수 있기 때문에 데이터 불일치가 발생하지 않게 되요.

Sticky Session을 통해 데이터의 정합성 문제는 해결했어요.

👀 하지만 다음과 같은 단점이 발생해요.

  1. 하나의 서버에 트래픽이 몰릴 가능성이 존재한다.

사용자들의 로그인 요청은 로드밸런서에 의해 적절하게 분배되어 서버 간 균형을 맞출 거에요.

하지만 사용자들의 활동까지는 예측할 수 없어요. 예를 들어, 유저 1은 활발한 유저라 계속해서 요청을 보내면 서버 1은 계속해서 요청이 가요. 하지만 유저 2는 로그인만 하고 아무 활동을 하지 않으니 서버 2는 요청이 더이상 오지 않아요.

🙇 이렇게 될 경우, 로드 밸런싱의 효과가 사라지게 되요.

  1. 세션 정보가 사라질 가능성이 존재한다.

서버는 의도하든, 의도하지 않든 서버가 종료되어 멈추는 경우는 다양해요. 어느 경우이던 간에 서버가 종료되면 로드 밸런서는 트래픽을 해당 서버를 제외하고 나머지 서버로 보낼 거에요. 그럼 종료된 서버에 저장된 세션 정보는 사라질 거에요. 이렇게 되면, 문제점을 해결하기 위해 이 방식을 썼는데, 문제점이 그대로 유지되는 거에요.

2. Session Clustering

'클러스터'의 의미는 다양하지만 저는 '특정 목적을 갖는 그룹'으로 간단히 정의 할거에요.
클러스터링은 여러대의 서버(컴퓨터)들이 네트워크로 연결되어 마치 하나의 애플리케이션처럼 동작하는 것이에요. 이처럼 세션 클러스트링도 여러 서버에 저장되어 있지만 마치 하나의 서버에서 세션 그룹을 동일하게 관리하는 것처럼 하는 방식이에요. 조금 더 자세히 설멍하면, 모든 서버에 같은 세션 클러스터링을 복사해두는 것이에요.

WAS에 따라서 세션 클러스터링 방식이 다를 거에요. 그 중에서도 Spring Boot가 채택하여 내장 WAS에 해당하는 Tomcat의 세션 클러스터링 방식을 위주로 살펴볼 거에요.

톰캣 공식문서에서 다음과 같이 설명해요.

Using the above configuration will enable all-to-all session replication using the DeltaManager to replicate session deltas. By all-to-all, we mean that every session gets replicated to all the other nodes in the cluster.

Tomcat은 all-to-all 세션 복제 방식을 사용하고 있으며, 이는 각 서버에서 생성된 모든 세션들을 클러스터로 모든 노드에 복제한다는 것이다.

This works great for smaller clusters, but we don't recommend it for larger clusters — more than 4 nodes or so. Also, when using the DeltaManager, Tomcat will replicate sessions to all nodes, even nodes that don't have the application deployed.

그리고 작은 클러스터에서는 이 방식이 효율적이지만, 4개 이상의 서버일 경우 추천하지 않는다.

로그인 요청 후에 새로 세션이 생성되었거나 세션 정보가 변경될 때마다 Tomcat에서 세션을 제어해요. 세션 복제를 처리하는 DeltaManager가 클러스터로 묶인 다른 모든 서버에 이와 동일한 세션 데이터를 복제해요.

결과적으로 위와 같은 그림이 될 거에요.

👀 서비스를 이용하는 사용자가 늘어날수록 세션을 복제하는 횟수와 세션 데이터의 양이 증가하기 때문에 과부하가 발생한다는 한계점이 존재해요.

3. 세션 스토리지 분리

지금까지 살펴본 방식들은 모두 각 서버의 메모리(WAS)에 세션을 저장했어요. 이와 달리 세션 스토리지를 분리는 아래 그림처럼 세션을 저장을 위한 새로운 저장소를 따로 두고 이곳에서 세션 정보를 공유하는 것이에요.

세션 스토리지 분리 방식을 사용하면 각 서버는 외부 스토리지에 대한 정보만 알면 되요. 그래서 서버를 추가하거나 삭제하는 것이 비교적 쉬워져요.

Sticky Session처럼 세션이 처음 생성된 서버에 따라 트래픽이 분배되지 않아도 되요. 로드 밸런서의 효과를 그대로 가져 갈 수 있어요.

또한 세션을 복제하지 않고 서버와 분리된 하나의 저장소에서 모든 서버의 세션을 공유하기 때문에 데이터 정합성 이슈는 물론 톰켓 세션 클러스터링 방식의 한계점도 해결했어요.

그러나 하나의 저장소를 사용하여 세션을 관리하기 때문에 해당 저장소가 다운되면 모든 서버가 세션을 사용할 수 없다는 단점이 존재해요. 그렇기 때문에 세션 저장소에 대한 클러스터링도 별도로 진행해야 해요.

✅ 결과

세션 스토리지 방식을 통해 분산 환경에서도 로그인한 유저를 식별할 수 있게 되었어요. 다만, 세션 스토리지를 분리하기로 결정했다면 이제 어떤 세션 스토리지를 사용할 것인가에 대한 고민도 하게 되요. 가장 많이 사용하는 것은 Redis에요. 왜 Redis를 선호하는지 찾아보는 것도 좋은 공부가 될거 같아요.

참고자료

톰켓 공식문서
분산 서버를 이용하며 세션을 유지하는 방법

profile
Don't ever say it's over if I'm breathing

0개의 댓글