• [ 배경 ]
    • 중고거래 사이트를 개발하면서 로그인 상태 정보를 기억하기 위해 세션 정보를 이용해야 했습니다.

    • 웹 통신 특성상 HTTP는 클라이언트가 서버로 request를 한 후, 서버가 그 요청에 맞는 response 하면 그 접속을 끊는 특징(Staeless 방식)과 그 반대인  keep-alive이 있습니다.

    • HTTP 프로토콜은 왜 한 번 맺은 연결을 끊어버리는 걸까요?
      • HTTP는 인터넷 상에서 불특정 다수의 통신 환경을 기반으로 설계되었습니다.
      • 만약 서버에서 다수의 클라이언트와 연결을 계속 유지해야 한다면, 이에 따른 많은 리소스가 발생하게 됩니다.
      • 따라서 연결을 유지하기 위한 리소스를 줄이면 더 많은 연결(가용성)을 할 수 있으므로 비연결적인 특징을 갖습니다.

    • Keep Alive란?
      • Keep Alive란 연결된 socket에 IN/OUT의 access가 마지막으로 종료된 시점부터 정의된 시간까지 access가 없더라도 대기하는 구조입니다. 즉 정의된 시간 내에 access가 이루어진다면 계속 연결된 상태를 유지할 수 있다는 것 이죠.

    •  HTTP에서 Keep Alive란?
      • HTTP는 앞서 설명드린 것과 같이 connection less방식이라 매번 socket(port)를 열어야 하고 이는 비용적인 측면에서 비효율적인 구조입니다. 해서 keep Alive time out 내에 client에서 request를 재 요청하면 socket(port)를 새로 여는 것이 아니라 이미 열려 있는 socket(port)에 전송하는 구조가 됩니다. db connection pool과 비슷한 개념입니다.

  • [ 과정 ]
    • 세션이 무엇인지 세션의 저장 방식의 장단점에 대해서 알아보겠습니다.
      • 세션이란?
        동일한 사용자(브라우저)로부터 들어오는 일련의 요구를 하나의 상태로
        보고, 그 상태를 일정하게 유지시키는 기술입니다.
        여기서 일정 시간은 방문자가 웹 브라우저를 통해 웹 서버에 접속한 시점으로부터
        웹 브라우저를 종료하여 연결을 끝내는 시점입니다.

      • 세션을 쓰면 되는데 굳이 쿠키를 사용하는 이유는?
        세션은 서버에 저장되고, 서버 자원을 사용하기에 자원 소모가 상당하다.
        자원관리 차원에서 쿠키와 세션을 적절한 요소 및 기능에 병행 사용하여 
        자원 사용 낭비를 방지하여 웹사이트의 속도를 높일 수 있습니다.

      • 일반적인 세션의 동작 순서
        1. 클라이언트가 페이지를 요청한다. (사용자가 웹사이트 접근) 

        2. 서버는 접근한 클라이언트의 Request-Header 필드인 Cookie를 확인하여, 
        클라이언트가 해당 session-id를 보냈는지 확인한다. 

        3. session-id가 존재하지 않는다면,  서버는 session-id를 생성해 클라이언트에게 돌려준다. 

        4. 서버에서 클라이언트로 돌려준 session-id를 쿠키를 사용해 서버에 저장한다. 

        5. 클라이언트는 재접속 시, 이 쿠키(JSESSIONID)를 이용하여 session-id 값을 서버에 전달

    •  대규모 트래픽을 처리하기 위한 Multi Server 환경(Scale Out방식)에서 제가 찾은 Session 데이터의 정합성을 유지하는 방식들은 아래와 같습니다.
      • 세션 정합성을 유지하는 3가지 방식
        • Sticky Session
        • Session Clustering
        • Inmemory DB를 사용한 세션 storage 각각 방식에 대해 알아보겠습니다.

Sticky Session 구조도

  • Sticky session
    • Load Balance(LB)가 기본적으로 라운드 로빈 방식으로 트래픽을 분산합니다.

    • 고정 세션 관리에서 핵심은 로드 벨런스가 얼마나 오랫동안 동일한 인스턴스로  
      사용자 요청을 일관되게 라우팅 하도록 하느냐입니다.
      즉, 특정 사용자가 접속을 시도했을 때 처음 접속된 서버로 계속해서 접속되도록 트래픽을
      처리하는 방식입니다.

    • 예를 들어, 브라우저 1이 WAS 1 서버에 세션을 생성하였다면, 이후에 브라우저 1이 보내는 모든 요청은
      1번 서버로만 보내지게 됩니다. LB는 브라우저 1이 첫 번째 세션을 생성한 서버로 모든 요청을 리다이렉트 하여 고정된 세션만 사용하게 됩니다.

    • 브라우저 1이 이미 http cookie를 사용하고 있으면, 해당 cookie 명을 넣어서 사용 중인 브라우저 1이 cookie를 사용하게 하고, 만약에 브라우저 1이 cookie를 사용하고 있지 않으면 LB가 cookie를 만들도록 합니다. 쿠기가 없다면 로 LB는 기존 LB 알고리즘 기반으로 서버를 선정합니다.

    • Sticky Session 방식을 사용하면 유저는 세션이 유지되는 동안 동일한 서버만 사용하기 때문에 Session 정합성 이슈에서 자유롭습니다.

    • 하지만 단점이 있습니다.
      고정된 세션을 사용한다는 것은 특정 서버에 트리팩이 집중될 때 위험합니다.
      사용자가 접속해야 하는 서버가 정해져 있어 하나의 서버에 트래픽이 집중되어 있어도 
      유저는 자신의 세션이 없는 다른 서버를 사용할 수 없습니다.

    • 그리고 서비스 중에 하나의 서버에 장애가 발생한다면 해당 서버를 사용하는 사용자들은 세션 정보를 잃어버리게 됩니다. 다시 로그인을 해야 합니다. 즉 가용성이 떨어지게 됩니다.
      Sticky Session을 사용하면 정합성 이슈를 해결할 수 있지만 스케일 아웃의 장점인 가용성과 트래픽 분산을 이용할 수 없습니다.

    • 가용성과 트래픽 분산까지 확보할 수 있는 세션 관리 방식인 Session clustering 방식에 대해 알아보겠습니다.

Session clustering 구조도

  • Session clustering
    • 여러 대의 컴퓨터들이 하나의 시스템처럼 동작하도록 만드는 것을 클러스터링이라고 합니다.

    • 예를 들어 DB가 두대가 있고 클러스터링 상태이면 한대가 시스템 장애가 나도 다른 한 DB가 그 역할을
      대신 수행하도록 하여 지속적인 서비스가 가능해집니다. 

    • 세션 클러스터링은 WAS가 2대 이상 설치(Scale out) 형태일 때 동일한 세션으로 관리하는 것을 의미합니다.
      세션 클러스터링의 여러 가지 방식이 궁금하시면 제 블로그의 "세션 클러스터링 이란?" 글을 참고해 주시길 바랍니다.

    • 위 그림과 같이 세션을 복제하면 유저가 이후에 어떤 서버에 접속하더라도 로그인 정보가 세션에 복제되어 있으므로 정합성 이슈가 해결됩니다. 하지만 모든 서버가 동일한 세션 객체를 가져야 하기 때문에 많은 메모리가 필요합니다. 또한 세션 저장소에 저장될 때마다 모든 서버에 입력해야 하므로 트래픽 증가로 인해 서버수가 증가할 때 성능 저하게 발생하게 됩니다.

    • 이보다 가장 치명적인 단점은 여러 대의 서버로 하나의 서비스를 위해 사용함으로써 데이터 불일치가 잠재적으로 발생할 수 있습니다. 4개 이하 서버의 소규모 클러스터일 때 적합한 방식입니다.
      Session clustering은 scale out의 가용성과 LB의 트래픽 분산을 이용할 수 있지만 세션 저장소를 저장할 때마다 성능적 한계가 명확합니다. 

    • Scale out형태의 가용성과 LB의 트래픽 분산 그리고 트래픽 처리 시 성능의 한계를 보완한 
      세션 스토리지 분리(Inmemory DB)에 대해 알아보겠습니다.

세션 스토리지 분리(Inmemory DB) 구조도

  • Inmemory DB
    • 기존 서버가 갖고 있는 세션 저장소를 이용하는 것이 아니라, 별도의 세션 저장소를 사용하는 것입니다.
      즉 세션 스토리지를 분리한다는 것입니다.

    • Inmemory DB란 데이터 스토리지의 메인 메모리에 설치되어 운영되는 방식의 데이터베이스 시스템입니다.
      메모리 접근이 디스크 접근보다 빠릅니다. 내부 최적화 알고리즘이 더 단순하며 더 적은 CPU 명령을 실행합니다. 메모리의 데이터에 접근하면 데이터를 조회할 때 검색 시간이 줄어듭니다. 

    • 단점도 존재합니다. 메모리가 휘발성입니다. DB서버 전원이 꺼진다면 자료들이 삭제됩니다. 
      그래서 로그인 세션 같은, 서버가 꺼져도 상관없는 임시 데이터를 주로 사용합니다. 
      단점을 극복하기 위해 DB가 재 구동될 때 디스크로부터 로그 파일을 읽어와 DBMS 구조를 재구축하는 방법도 있습니다.

    • 인메모리 db중 Redis와 memcached에 대해 궁금하시면 제 블로그 글 중"Redis와 memcahced 비교" 글을 참고해주시길 바랍니다.

    • 메모리 사용량, 읽기/쓰기 속도, 디스크 I/O Dumping, Scaling 면에서 redis가 memcached 보다 월등히 좋습니다. 결과적으로 redis를 중고거래 프로젝트에서 사용하였습니다.

    • 세션 스토리지 분리(Inmemory DB) 구조는 세션정보 정합성, Scale out의 가용성, LB의 알고리즘을 이용한 트래픽 분산, 세션정보 입력 시 성능도 양호한 편입니다. 하지만 Session Storage가 한 개이기 때문에 장애 발생 시 모든 세션이 이용이 불가합니다.  가용성 확보를 위해 복제를 구성하는 것이 좋습니다.

    • 데이터베이스 transaction의 대부분은 read인데 slave를 두어 분산 처리하여 가용성을 높이고 조회 성능을 향상할 수 있습니다.

Master-Slave Replication(복제) 구조도

  • 최종적으로 중고거래 사이트 프로젝트에서 채택한 Inmemory DB (Redis Server) 구조는 아래와 같습니다.

WEB - WAS - Redis(Inmemory DB) 이중화 구조


  • [ 결과 ]
    • 로그인 상태 정보인 세션 데이터를 저장하는 방식은 아래와 같았습니다.
      • Sticky Session
      • Session Clustering
      • Inmemory DB를 사용한 세션 storage

    • Scalue out환경에서 가용성 적인 측면에선 Sticky Session 방법이 단점이 있었고
      Session Clustering과 Inmemory DB에선 가용성과 세션동기화를 모두 해결하였지만 
      서버와 서버끼리 전부 네트워크 통신 기회비용이 있어 Inmemory DB인 Redis가 적합하다 생각하였습니다.
      추가로 아래와 같은 내용도 고려하였습니다.
      • LB알고리즘을 이용한 트래픽 분산
      • Session Storage의 1개 일 때 위험성을 극복하기 위해 Replication 구조로 세션 스토리지 분리
      • 디스크 저장 시에 오는 속도 저하

    • 결과적으로 Inmemory DB 인 Redis를 사용함으로써 가용성과 성능을 향상하는 방식을 선택하였습니다.

  • [ 성과 ]
    • 웹의 Stateless 한 특성을 이해하였습니다.
    • 스케일 업과 스케일 아웃의 개념에 대해 학습하였고 도메인 서비스의 특징을 고려하게 되었습니다. (웹 환경, 실시간성 서버 애플리케이션 ex 게임 서버)
    • HttpSession 동작 원리와 Spring 환경에서 적용하는 방법을 이해하였습니다.
    • 웹서버와 WAS의 차이에 대해 이해하였습니다.
    • Tomcat의 StickySession, 클러스터링 방식의 장단점과 차이점을 이해하였습니다.
    • NoSQL인 Redis와 Memcached의 차이점과 장단점에 대해 이해하였습니다.

 

junshock5/used-market-server

중고거래 프로젝트. Contribute to junshock5/used-market-server development by creating an account on GitHub.

github.com

+ Recent posts