반응형
CAP Theorem, 오해와 진실요약
각 서버에서 관리중이던 로그인 세션을 별도의 공유 저장소(Redis)로 이관했다.
다양한 신규 서비스가 생기면서 로그인 세션에 접근해야하는 일이 발생하게 되면서 아키텍처를 변경해야할 필요가 생기게 되었다.
기존의 상태 의존적인 아키텍처를 통해 어떤 제약이 있었는 지 살펴보고, 이를 개선한 무상태 아키텍처에 대해 짧게 설명한다.
그리고 세션 공유 저장소로 Redis를 선택하게 되면서 어떤 기준으로 클러스터를 구성하였는지 정리해본다.
아키텍처 개선 뒤 얻게 된 이점에 대해서도 짧게 정리한다.

👉 기존의 상태 의존적인 아키텍처

기존에는 사용자들에 대한 로그인 세션 정보가 각 웹 서버 내부에서 파일로 관리 중이었다. (별도 인증 서버 없음)
특정 사용자의 로그인 세션 정보를 유지하기 위해서는 해당 사용자의 요청이 세션 정보가 존재하고 있는 서버로 전달이 되어야한다.
아래 그림을 살펴보자. 사용자 A가 서버 1에서 로그인 인증을 하게 되면 사용자 세션 정보는 해당 서버에 보관된다. 그래서 사용자 A의 인증을 하기 위해서 이후 요청은 모두 서버 1로 전달되어야 한다. 만약 사용자 A의 요청이 서버 2로 간다면 로그인 세션 정보가 존재하지 않기 때문에 인증은 실패하게 된다.
이를 위해서, 로드밸랜서에 고정 세션(Sticky Session) 설정을 통해 특정 사용자의 모든 요청은 동일한 서버로 전송되도록 설정되어 있다. 사용자 A의 모든 요청은 서버 1로 전달되고, 사용자 B의 모든 요청은 서버 2로 전달되게 된다.

상태 의존적인 아키텍처

이로 인한 제약사항
- 다른 자사 서비스에서 세션 접근하기 어렵기 때문에 자사 서비스간 사용자 인증 정보를 유지하기 어려움
- 로드밸런서에 부담을 주게 되고, 적절한 부하 분산과 웹 서버 추가 및 제거도 까다로워지게 된다.

👉 무상태(stateless) 아키텍처로 개선

별도의 공유 저장소(ex: redis/memcached, rdb, nosql 등)을 활용하여 사용자 세션 정보를 웹서버에서 분리하였다.
나는 AWS ElastiCache - Redis 를 활용하기로 했다.

무상태 아키텍처


👉 클러스터 구성 (Redis를 어떻게 구성해야하지?)

Redis를 사용해본 적 없는 뉴비라서 처음 노드 구성부터 용량까지 하나의 선택마다 고민이 많이 됐기 때문에 그 과정을 정리해본다.

CAP 정리 (장애 상황 대응 전략)

어떻게 노드를 구성해야할 지 고민이 많이 되서 클러스터링에 대해 열심히 구글링을 했는데, 파다보니 CAP 정리라는 이론을 맞닥뜨렸다. 요약하자면 분할용인, 일관성, 가용성 세 가지를 동시에 만족할 수 있는 시스템은 없기 때문에, 분산 시스템에서는 일관성이나 가용성 둘 중 하나를 선택를 선택해야한다는 것이다.

이거를 로그인 세션에 맞게 예시를 제공하면 아래처럼 해석된다.

  • 일관성(Consistency): 모든 노드가 같은 순간에 같은 데이터를 볼 수 있다.
    • 싱글노드로 구축한다!
    • 단 한 명의 로그인도 실패없이 성공을 보장한다.
    • 대신 싱글노드기 때문에 마스터 노드가 죽으면, 모든 사용자들의 로그인 정보가 날아가기 때문에 다시 로그인해야함.
  • 가용성(Availability): 모든 요청이 성공 또는 실패 결과를 반환할 수 있다.
    • 클러스터를 구축하고 샤딩한다!
    • 가끔 몇 명의 로그인을 실패할 수 있다 (몇명일지 모름)
    • 하지만 일부 노드가 죽어도, 모든 사용자의 로그인에 영향을 받지 않는다. 다른 노드에 붙어있는 사용자는 로그인 기능에 장애가 났다는 걸 인지하지 못하고 사용할 수 있음

그래서 어떤 걸 선택해야할까? 혼자서 시뮬레이션하면서 생각을 해봤는데 도저히 둘 다 포기할 수가 없는 장점이었다. 그래서 개발팀 전체에게 도움을 요청했다.
결론부터 말하자면 로그인 세션에는 '일관성'이 적합한데, 클라우드를 이용하면 두 장점을 모두 취할 수 있는 방법이 있다.

두 마리 토끼를 잡다 : 클라우드 이용

AWS ElastiCache에서 좋은 기능들을 제공하고 있었다. 이중화 기능을 제공해주기 때문에 일단 싱글 노드로 구성하되 복제본을 하나 갖고 있는다면 노드가 죽어도 빠르게 복구가 가능하다. 그래서 현재는 왼쪽으로 구성을 했고, 나중에 사용자가 미친듯이 많아지면 오른쪽처럼 샤딩을 하면 될 것 같다. 물론 CAP 정리대로 완벽하게 3마리 토끼를 얻을 수는 없다. 싱글노드가 되살아나기까지 사용자들은 로그인을 못하기 때문이다. 하지만 AWS가 노드를 복구하는 시간은 굉장히 짧을 것이기 때문에 이 정도면 세 가지 장점을 모두 취할 수 있다고 본다.

클러스터 구성안

👉 용량 산정

  • 현재 활성 사용자수에 따른 세션 용량 : 특정일 기준 사용자수 x에 대해 운영서버의 세션파일 용량은 약 48MB
  • 최대 세션 용량 : 이번년도 최대 사용자수가 b일때, 이를 비례해서 계산했을 때 150MB 정도가 예상됨
  • 용량 산정 : 근데 뭐 더 알아볼 것도 없이 AWS 기본적으로 제공하는 최소 사양도 4GB였기 때문에, cache.t2.micro 로 개발서버와 스테이지 서버용 레디스 생성함 (운영은 네트워크 성능이 더 좋은 걸로 함)
  • AWS ElastiCache는 스케일업이 가능하기 때문에 사용량을 보며 추후 업글/다운글이 가능하기 때문에 선택에 부담 적음

👉 결과

  • 로그인 세션 확인을 위한 Endpoint 통합 : 이제 연계되는 서비스에서 로그인 세션을 확인하기 위해 한 군데의 엔드포인트만 확인하면 된다.
  • API 응답속도 최대 4배 향상 : API 평균 응답 시간이 0.3~0.4초에서 0.1~0.2초 정도로 줄어들었다. API별로 적게는 2배에서, 많게는 4배까지 속도가 향상되었다.
  • 로드밸런서 알고리즘을 통한 적절한 부하분산 가능 : 기존에는 특정 사용자의 요청은 항상 동일 서버로 전달되어야 했기 때문에 최초 서버 선정 시에는 알고리즘을 통해 분산 시키지만, 특정 서버에 사용자 요청이 몰릴 경우 부하 분산이 적절하게 되지 못했다. 하지만 이제는 Round Robin, Weighted Round Robin, Least Connection 등의 알고리즘을 적절히 적용하여 서비스 성격에 맞는 부하 분산을 적용할 수 있게 되었다.
  • 웹서버 추가 및 제거가 용이해짐 : 클라이언트 상태와 무관하게 웹서버를 구성할 수 있게 되었기 때문에 웹 서버 추가와 제거가 용이해졌다.

참고자료

반응형