Scaling out with Spring Session

2020. 9. 1. 17:31 Spring Framework/Spring boot

스프링 세션으로 스케일 아웃하기 Scaling out with Spring Session

원문: http://www.jayway.com/2015/05/31/scaling-out-with-spring-session/

Stateless 아키텍쳐는 근 몇년간 타당한 이유로 꾸준히 인기가 올라왔다. 하지만 stateful 세션기반의 어플리케이션도 꾸준히 중요한 역할을 이어왔다. 예를 들어 더 나은 보안을 위해 CSRF 토큰이 이슈될때처럼. 낮은 부하의 단일 서버를 배포할 때, 세션관리는 당신이 합리적인 타임아웃 유효기간을 사용하고 세션에 많은 양의 데이터를 저장하지 않는 것처럼 매우 직관적이다. 문제는 스케일 아웃하기 더 힘들다는 것이다 각각의 요청은 아마 다른 서버에 있을 지도 모르는 그에 상응하는 세션과 함께 묶여져야하기 때문이다. 이를 극복하기 위해, 서버 공급자들은 서버간 다양한 종류의 세션 복제를 구현해왔다. 또다른 대안으로 로드밸런서를 세션과 붙여 같이 설정할 수 있다. 이 두가지 솔류션 다 잘 동작한다. 하지만 스프링 세션으로 스프링은 또 다른 옵션을 만들어냈다. 이 블로그는 세션을 스케일 아웃하기 위해 어떻게 스프링 세션을 레디스와 함께 설정하는 지 보여줄 거이다. 이 제안된 솔루션은 (스프링 기반이 아닌) 어떠한 서블릿에서도 작동할 것이다 - 이는 당신의 레가시 웹앱을 스케일 아웃해야할때 매우 적합하다.


예제 어플리케이션 Example Application

먼저 우리는 간단한 세션 기반의 HelloServlet 예제를 살펴보자:

HTTP GET이 호출될 때, 서블릿은 세션에 Mattias의 값을 가진 name 속성이 있으면  Hello Mattias! 를 응답하거나, 없다면 기본값인 Hello World!를 응답할 것이다.

HTTP POST이 호출될 때, 서블릿은 요청으로 부터 name 매개변수를 읽고, 새로운 세션을 만들고 (또는, 이미 세셨이 있다면 재사용하고), name의 값을 이와 상응하는 세션 속성에 저장할 것이다.

첫번째 요청은 세션이 없으므로 다음과 같이 다음과 같은 기본 응답을 받게 된다:

두번째 요청은 name 속성을 가진 POST 요청으로 세션이 생성된다:

덧붙이자면,  -i (또는 —-include) 옵션은 응답의 HTTP 헤더에 포함되는 cURL 플래그이며 -d (또는—data) 플래그는 요청의 매개변수로서 데이터를 제출하는데 사용된다. 응답에서 우리는 Set-Cookie 헤더의 값에 주목했다.

세번째 요청으로, GET 요청과 세션 상태의 유효화 검증이다:

어플리케이션의 서로 다른 인스턴스에서 같은 요청을 수행할 때 우리는 문제에 직면한다. 세션이 이미 존재함에도 불구하고 기본 응답이 되돌아왔다:

이제 스프링 세션을 써야할 때다!


스프링 세션 아키텍쳐 Spring Session architecture

스프링 세션의 컨셉은 매우 직관적이다:

  • 새 서블릿 필터를 만든다
  • 그 필터를 당신의 서블릿 필터체인filter chain에 추가한다
  • 그 필터를 레디스와 연결한다 (또는, Hazelcast, GemFire, Coherence가 지원하는 다른 MapSessionRepository 또는 당신에게  Map 레퍼런스를 제공해주는 다른 종류의 데이터 그리드data grid, 그러나 이들은 이 글의 범주에 벗어나므로 더이상 언급하지않는다)

의존성 추가하기 Adding dependencies

먼저, 우리는 몇가지 의존성을 추가해줘야한다. 메이븐에선 다음과 같이 POM에 추가해주면된다:

첫번째 의존성은 Redis 연결을 위해 필요하며 두번째는 스프링이 서블릿 필터를 만들기 위해 필요하다.


스프링 세션 설정 Spring Session Config

스프링 세션은 (내부적으로 Jedis client를 기반으로) 기본적으로 레디스 연결을 지원해준다. 아래의 XML 기반 설정의 예를 참고하거나  자바 기반 설정으로 대체할 수 있다.

마지막 두줄은 스프링에게  spring.redis.port 값을  application.properties 파일에서 찾으라고 알려주는것이다.  다음의 한줄과 같이: 


스프링 세션 설정 등록하기 Registering the Spring Session Config

(만인 당신의 어플리케이션이 이미 스프링을 사용하고 있지 않다면) 스프링 세션 설정을 불러오기위해  web.xml에 다음의 몇 줄을 추가해주어야 한다:


스프링 세션 서블릿 필터 추가하기 Adding the Spring Session servlet filter

어플리케이션에서 필요한 마지막 수정은 새로운 서블릿 필터를 추가하는 것이다. web.xml를 다시 열고 다음을 추가해준다:

single commit에서 바뀐 사항들을 모두 확인할 수 있다:


입 증 Verification

이제 어플리케이션을 모두 업데이트하였다. 원하는대로 동작하는지 입증해보자:

  • 어플리케이션을 다시 빌드한다
  • 레디스가 설치되었고 기본 포트인 6379에서 작동중인지 확인하라. 다른 포트에서 동작하고 있다면 spring.redis.port 설정을 업데이트 해주어야한다
  • 어플리케이션을 이를테면 8080 과 8081과 같이 두개의 인스턴스로 시작하라. 둘다 같은 레디스서버에 연결되어야한다.
  • 위에 언급된 이슈를 시도해보자

먼저 서버 인스턴스 한군데서 POST로 세션 상태를 만든다:

안은 인스턴스에서 GET 요청으로 세션 상태 검증하자:

다른 서버에서 같은 요청을 반복해보면 이제 같은 세션 데이터를 가지고 있는 것을 볼 수 있다:


고려 사항들 Considerations

  • 당신은 세션을 잃을지도 모른다는 걱정없이 원하는대로 서버를 시작하거나 멈출 수 있다. 이를테면 장애극복failover이나 자동 스케일링autoscaling은 세션의 관점에선 자동으로 처리된다.
  • 당신은 이제 더이상 sticky sessions 이나 복잡한 로드밸런서 설정이 필요없다. 부하를 나누려면 간단한 라운드-로빈Round-robin 전략이면 충분하다.
  • 운영의 관점에선 여전히 해줘야 할 것들이 있다. 누군가는 레디스 클러스터를 설정하고 관리해주어야 한다. (만일 AWS에서 동작한다몀 Amazon ElasticCache이 잘 맞을 것이다)
  • 스프링 부트를 사용중이라면 아마도 spring-session.xml설정이나  web.xml.을 추가하고 싶지않을 것이다.  자바 기반 설정을 위해  Spring Boot Guide를 확인하자.
  • 만일 당신이 RESTful API 를 개발중이다 쿠키를 싫어한다며? Spring Session Rest를 확인해보자.

주, 스프링 부트에서는 @EnableRedisHttpSession 어노테이션 한줄로 다 해결됨



출처: https://springboot.tistory.com/17?category=620229 [스프링부트는 사랑입니다]