처음엔 로그인 기능에 HTTP 세션을 사용했었는데, 세션정보가 앱서버에 저장되기 때문에, 서버가 Scale-out한다고 가정했을 때 문제가 될 수 있습니다.
Scale-out이란?
같은 기능을 수행하는 서버 갯수를 늘려 처리량을 늘리는 것을 말한다. 대조적으로 Scale-up은 서버를 늘리는게 아닌, 해당 서버의 CPU나 메모리 등 스펙을 올리는 것을 의미한다.
클라이언트가 요청을 보내게 되면 로드밸런서가 로드밸런서가 클라이언트와 서버간 연결 정보를 기억해서 요청이오면 해당 서버로만 라우팅해주는 방법입니다. 이 경우 특정 서버에만 트래픽이 몰리거나, 서버에 장애 발생 시 해당 세션들이 모두 소실되는 문제가 있었습니다. 로그인 유지를 세션방식으로 구현했다면 로그인을 다시해줘야하는 문제가 발생했겠죠?
그렇다고 모든 서버가 세션 정보를 주고 받으며 동기화하기에는, 동기화에 필요한 네트워크 비용과 지연이 문제가 됩니다.
위 문제들이 바로 서버가 클라이언트와의 정보를 들고있게 됨으로써 생기는 문제인데, 이를 보고 서버가 "Stateful"하다고 말합니다. 서버가 클라이언트의 정보(state)를 알고있어야하고, 그를 기반으로 연산을 처리하기 때문에 scaling이 어려워지고 서버 장애 발생에도 크게 영향을 받는 것입니다.
그래서 세션정보를 데이터베이스에 저장하고 모든 서버가 데이터베이스를 통해 세션정보를 참조하는 방식을 사용했습니다. 로드밸런서는 그저 트래픽을 골고루 나눠서 서버에 전달하면되고, 서버는 stateless하기 때문에 어느 클라이언트와 연결되어도 데이터베이스의 세션 정보 덕분에 클라이언트의 세션정보를 얻을 수 있습니다.
클라이언트는 로그인 시에 세션에 해당하는 key인 ‘토큰’을 발급 받습니다. 대부분의 API 호출에 인증이 필요하기에, 필터 계층에서 이 토큰의 유효성을 검사함으로써 인증을 수행하고 요청한 클라이언트가 누구인지 알게됩니다.
담배200의 경우 인증 Filter를 정의해서 거의 모든 요청에 대해 인증을 실시합니다. 그리고 캐시를 활용해서 인증과정이 빠르게 진행되도록 했습니다.
JWT는 쉽게 말하면 별도의 세션정보를 DB에 담아둘 필요 없이, 해당 토큰 자체로 인증이 되는 방식입니다. 전세계를 대상으로하는 서비스에서는 세션 정보를 담은 DB를 전세계에 설치해야하고 이는 비용이 매우 큽니다. 바로 중앙화된 DB의 단점입니다. 이 때 JWT를 사용하면 중앙화된 서버 없이 인증이 가능하다는 장점이 있습니다.
이렇게 들으면 좋은 방법 같지만 분명 트레이드오프가 존재합니다.
이런 단점들 때문에, 짧은 유효기간의 일회용 인증 토큰으로 활용하면 좋습니다.(OAuth 토큰 발급, MSA에서 서비스간 명령 전송 등 짧은 통신)
국내 서비스를 가정한 저의 담배200 프로젝트의 경우 JWT를 사용할 필요 없이 DB 중앙화방식이 적합하다고 생각해서 JWT는 사용하지 않았습니다.
지금까지 서버가 여러 대일 때 세션을 관리하는 법을 배웠는데요, 세션 관리방법 뿐만 아니라 scale-out과 stateful, 서버 장애가 서비스를 어떻게 힘들게 하는지 감이 왔으면 좋겠습니다.
감사합니다!