고정 세션 는 특정 사용자의 요청을 해당 사용자의 세션이 있는 동일한 서버로 리디렉션하는 것을 의미합니다. 서버에 장애가 발생하면 해당 서버에 연결된 모든 사용자의 세션이 손실되므로 안티 패턴으로 간주됩니다.
사용자와 서버 간의 연결은 일반적으로 로드 밸런서를 통해 구성되며, 다음과 같은 간단한 로드 밸런싱 전략이 사용됩니다. 라운드-robin 는 헤비 유저가 모두 같은 노드에 있을 수 있기 때문에 요청을 균등하게 분산시키기에 충분하지 않은 경우가 많습니다. 스티키 세션을 피할 수 있는 방법은 여러 가지가 있지만, 애플리케이션이 사용자의 데이터를 HTTPSession에 저장하는 경우 상당한 리팩토링 없이 사용할 수 있는 옵션은 다소 제한적입니다.
이 문제에 대한 한 가지 빠른 해결 방법은 서버의 메모리를 사용하는 대신 데이터베이스에 세션을 저장하는 것입니다. 이 시나리오에서는 어떤 노드가 요청을 수신하든 데이터 저장소에서 직접 사용자의 세션을 로드합니다. 이 접근 방식은 컨테이너별 솔루션보다 간단하며 데이터베이스의 다른 모든 항목처럼 세션을 쿼리할 수 있습니다.
내부 키-값 엔진을 사용하고 내부 캐시 계층을 활용하여 최근에 사용한 세션을 메모리에 보관하기 때문에 이 시나리오에 특히 적합한 솔루션입니다. 실제로는 대규모로도 잘 작동하는 솔루션이라는 뜻입니다. 이것이 바로 저희가 커뮤니티 지원을 추가하는 이유입니다. 봄 세션:
카우치베이스 봄 세션 를 사용하면 데이터베이스에 저장하여 클러스터된 세션을 쉽게 지원할 수 있으며 개발자 입장에서는 완전히 투명합니다. 다음 종속성을 추가하기만 하면 됩니다:
|
1 2 3 4 5 |
<dependency> <groupId>io.github.couchbaselabs</groupId> <artifactId>스프링-세션-데이터-카우치베이스</artifactId> <version>1.1</version> </dependency> |
를 추가한 다음 메인 클래스에서 @EnableCouchbaseHttpSession 어노테이션:
|
1 2 3 4 5 6 7 8 9 |
스프링 부팅 애플리케이션 @EnableCouchbaseHttpSession public 클래스 세션스토어 애플리케이션 { public 정적 void 메인(문자열[] args) { 스프링 애플리케이션.실행(세션스토어 애플리케이션.클래스, args); } } |
를 입력하면 끝입니다! 이제부터는 Spring이 자동으로 HTTPS세션을 Couchbase에 저장합니다:
|
1 2 3 4 5 6 7 8 |
@GetMapping("/newSession") public 문자열 newSession(HttpServletRequest 요청, 모델 모델) 던지기 예외 { 요청.getSession().무효화(); HttpSession newSession = 요청.getSession(); newSession.setAttribute("foo", new Foo("key", "value")); 반환 기본 페이지(모델, newSession); } |
기본적으로 세션은 데이터베이스에 ""와 같은 유형의 문서로 저장됩니다.세션“:
|
1 2 3 4 5 6 7 8 9 10 11 12 |
//키 : 5b357ade-6059-4d16-aea3-6f784765e7b5 { "_principal": null, "_interval": 1800, "_expireAt": 1554743279889, "_created": 1554741479889, "_accessed": 1554741479889, "_유형": "세션", "_attr": "\"rO0ABXNyABFqYXZhLnV0aWwuSGFzaE1hcAUH2sHDFmDRAwACRgAKbG9hZEZhY3RvckkACXRocmVzaG9sZHhwP0AAAAAAAAx3CAAAABAAAAABdAADZm9vc3IAHWNvbS5jYi5zZXNzaW9uc3RvcmUubW9kZWwuRm9vO5F+XaK9pV0CAAJMAAphdHRyaWJ1dGUxdAASTGphdmEvbGFuZy9TdHJpbmc7TAAKYXR0cmlidXRlMnEAfgAEeHB0AAZ2YWx1ZTF0AAZ2YWx1ZTJ4\"" } |
그러나 유형 속성의 이름, 유형 값 및 세션 지속 시간을 변경할 수 있습니다:
|
1 2 3 4 5 6 7 8 9 |
스프링 부팅 애플리케이션 @EnableCouchbaseHttpSession(유형 이름 = "myType", 유형 값 = "myValueType", 최대 비활성 간격 인 초 = 1800) public 클래스 세션스토어 애플리케이션 { public 정적 void 메인(문자열[] args) { 스프링 애플리케이션.실행(세션스토어 애플리케이션.클래스, args); } } |
사용자 세션 쿼리하기
모든 세션의 데이터는 다음과 같은 어트리뷰트에 바이너리로 저장됩니다. _attr:
|
1 2 3 4 |
{ ... "_attr": "\"rO0ABXNyABFqYXZhLnV0aWwuSGFzaE1hcAUH2sHDFmDRAwACRgAKbG9hZEZhY3RvckkACXRocmVzaG9sZHhwP0AAAAAAAAx3CAAAABAAAAABdAADZm9vc3IAHWNvbS5jYi5zZXNzaW9uc3RvcmUubW9kZWwuRm9vO5F+XaK9pV0CAAJMAAphdHRyaWJ1dGUxdAASTGphdmEvbGFuZy9TdHJpbmc7TAAKYXR0cmlidXRlMnEAfgAEeHB0AAZ2YWx1ZTF0AAZ2YWx1ZTJ4\"" } |
Spring은 세션에 어떤 객체 유형이 있는지 알지 못하므로 사람이 읽을 수 있는 형식으로 변환할 수 있는 쉬운 방법이 없습니다. 속성을 설정하여 이 제한을 극복할 수 있습니다. keepStringAsLiteral 에서 사실과 같이 EnableCouchbaseHttpSession 어노테이션:
|
1 2 3 4 5 6 7 8 9 |
스프링 부팅 애플리케이션 @EnableCouchbaseHttpSession(keepStringAsLiteral = true) public 클래스 세션스토어 애플리케이션 { public 정적 void 메인(문자열[] args) { 스프링 애플리케이션.실행(세션스토어 애플리케이션.클래스, args); } } |
keepStringAsLiteral 가 알려줄 것입니다. 카우치베이스 봄 세션 를 사용하여 모든 세션의 문자열 속성을 문서 내의 최상위 프로퍼티로 저장할 수 있습니다. 예를 들어, 세션에 직접 인스턴스를 추가하는 대신 잭슨의 오브젝트 맵퍼:
|
1 2 |
오브젝트 맵퍼 매퍼 = new 오브젝트 맵퍼(); 세션.setAttribute("key", 매퍼.쓰기값을 문자열로(내클래스 인스턴스)) |
그런 다음 세션 카트를 읽어야 할 때 다시 객체로 변환합니다:
|
1 2 |
오브젝트 맵퍼 매퍼 = new 오브젝트 맵퍼(); 매퍼.읽기 값( 세션.getAttribute("key").toString(), MyClass.클래스); |
|
1 2 3 4 5 6 7 8 9 10 11 12 |
//키 : 5b2a2487-4825-43de-b089-1b61703556b2 { "_principal": null, "_interval": 1800, "_expireAt": 1554746972015, "_created": 1554745163803, "_accessed": 1554745172015, "key": "{\"shoppingCart\":{\"created\":1554745170784,\"items\":[{\"itemName\":\"Tennis Shoes\",\"price\":38.25186017511709,\"quantity\":3}]},\"user\":{\"username\":\"robertst\",\"phoneNumber\":\"(500)-383-1668\"},\"location\":{\"address\":\"90 Arrowhead Avenue Jonesboro, GA 30236\",\"country\":\"USA\",\"coordinates\":{\"lat\":10,\"lon\":37}}}", "_유형": "세션", "_attr": "\"rO0ABXNyABFqYXZhLnV0aWwuSGFzaE1hcAUH2sHDFmDRAwACRgAKbG9hZEZhY3RvckkACXRocmVzaG9sZHhwP0AAAAAAAAB3CAAAABAAAAAAeA==\""" } |
여전히 _att 어트리뷰트를 사용할 수 있습니다. 하지만 이제 객체에 대한 키입니다, 는 이전 예제에서 세션에 추가한 객체와 정확히 일치합니다.
이제 세션을 쿼리해 보겠습니다, N1QL 라는 함수가 있습니다. DECODE_JSON를 사용하여 JSON으로 인코딩된 문자열을 객체로 언마샬링할 수 있습니다:
|
1 2 3 4 5 |
선택 메타().id as id, _created, ARRAY_COUNT(DECODE_JSON(sessionCart).shoppingCart.items) FROM 세션스토어 주문 BY _created DESC LIMIT 10 |
참고: 프로덕션 환경에서는 쿼리 시점에 디코딩하는 대신 디코딩된 오브젝트로 인덱스를 생성하는 것이 좋습니다.
Couchbase 스프링 세션에 대해 자세히 알아보려면 다음을 확인하세요. 튜토리얼
궁금한 점이 있으면 언제든지 다음 주소로 문의해 주세요. 데니스브로사