2021.09.24 - [개발 지식/Spring Framework] - [Redis Session] Spring Boot에서 Redis Session 활용하기 - 03
이어서 이번 포스팅은 Session을 set하고 get하는 API를 하나 뚫어놓고 redis-cli.exe로 확인해보고자 한다.
@RestController
public class JustController {
@Autowired
HttpSession httpSession;
@GetMapping(path = "/setsession")
public String setsessionAPI() {
String value = "Erjuer";
httpSession.setAttribute("KEY", value);
String returnValue = LocalDateTime.now().toString() + " \nsession set id : " + httpSession.getId() + " \nsession set Value : " + value;
return returnValue;
}
@GetMapping(path = "/getsession")
public String getsessionAPI() {
Random random = new Random();
String value = (String) httpSession.getAttribute("KEY");
String returnValue = LocalDateTime.now().toString() + " \nsession get id : " + httpSession.getId() + " \nsession get value " + value;
return returnValue;
}
}
코드를 보면 "KEY" : "Erjuer" 이라는 Key-Value값으로 httpSession에 set하고 get하는 간단한 API이다.
HttpSession에 set을 요청해보고 redis에 저장되어 있는 keys 값들을 조회해보면
application.yml에 설정되어 있는 session.redis.namespace가 prefix로 붙고 session Id값이 저장되어 있는 것을 확인할 수 있다.
그렇다면
- spring:session:Erjuer:sessions:09897d67-7b4c-4570-94e9-d9ffad974b16
- spring:session:Erjuer:expirations:1632582240000
- spring:session:Erjuer:sessions:expires:09897d67-7b4c-4570-94e9-d9ffad974b16
은 각각 무슨 의미일까?
application.yml에 보면 server.servlet.session.timeout: 8m 즉 session timeout이 8분으로 설정되어 있다.
여기서 각각의 TTL(Time to live)를 체크해보면
음?
ttl 조회 시간 차이 (명령어 타이핑 시간) 로 정확히 맞지는 맞지는 않지만
spring:session:Erjuer:sessions:09897d67-7b4c-4570-94e9-d9ffad974b16, spring:session:Erjuer:sessions:expires:09897d67-7b4c-4570-94e9-d9ffad974b16
두개의 시간차이가 5분이 난다.
이 5분은 어디서 생겨난 것일까?
세션이 만료 될 때는 redis에서 해당 세션 ID값에 액세스하여 해당 세션값을 Expire(SessionDestroyedEvent를 실행) 해야한다. 사용자가 설정한 timeout(여기서는 8분)에 바로 만료가 되어버리면 redis가 해당 세션에 액세스 할 수가 없다. 그렇기 때문에 redis 자체에서 실제 만료 시간을 임의로 5분 추가하여 설정한다.
Note: findById 메서드를 사용하면 만료된 세션이 반환되어서는 안된다. 이는 세션을 사용하기 전에 만료 여부를 확인할 필요가 없음을 의미한다. (그래서 5분을 늘렸다는 소리..)
즉 spring:session:Erjuer:sessions:expires은 우리가 설정한 timeout에 해당하는 8분이 설정되어 있고spring:session:Erjuer:sessions은 그 시간보다 5분이 추가된 13분으로 설정이 된 것이다.
우리가 session값에 설정한 것들은
spring:session:Erjuer:sessions:09897d67-7b4c-4570-94e9-d9ffad974b16에 Hash 형태로 저장되어 있지만 redis가 접근하는 값은 spring:session:Erjuer:sessions:expires이다.
그렇다면 httpsession.set(#{Key}, #{Value}); 만 했을 뿐인데 어떻게 redis에 저장이 되는 것일까?
Spring 공식문서에 있는 RedisIndexedSessionRepository 를 살펴보면
The sections below outline how Redis is updated for each operation. An example of creating a new session can be found below. The subsequent sections describe the details.
HMSET spring:session:sessions:33fdd1b6-b496-4b33-9f7d-df96679d32fe creationTime 1404360000000 maxInactiveInterval 1800 lastAccessedTime 1404360000000 sessionAttr:attrName someAttrValue sessionAttr2:attrName someAttrValue2
=========
EXPIRE spring:session:sessions:33fdd1b6-b496-4b33-9f7d-df96679d32fe 2100
==========
APPEND spring:session:sessions:expires:33fdd1b6-b496-4b33-9f7d-df96679d32fe ""
EXPIRE spring:session:sessions:expires:33fdd1b6-b496-4b33-9f7d-df96679d32fe 1800
==========
SADD spring:session:expirations:1439245080000 expires:33fdd1b6-b496-4b33-9f7d-df96679d32fe
EXPIRE spring:session:expirations1439245080000 2100
HMSET, EXPIRE, APPEND, SADD 명령어를 통해 saving Session을 수행하며 각각의 의미는 다음과 같다.
- HSET: 입력한 해시 키 밑에 지정한 필드에 값을 저장하고 필드 값이 존재하면 덮어쓴다.
- EXPIRE: 키값에 대한 Timeout을 명시한다.
- APPEND: 해시값이 존재하면 그 Value값 끝에 추가한다.
- SADD: 키값에 리스트 형식으로 더한다. 단, 값이 존재하는 경우 무시한다.
redis-cli.exe에 monitor 명령어를 입력 후 session을 get했을 때
1632585039.476935 [0 127.0.0.1:57771]
"HGETALL" "spring:session:Erjuer:sessions:09897d67-7b4c-4570-94e9-d9ffad974b16"
1632585039.478381 [0 127.0.0.1:57771]
"HMSET" "spring:session:Erjuer:sessions:1a61bf7b-5978-438c-a57f-82f9fd9df76f"
"lastAccessedTime" "\xac\xed\x00\x05sr\x00\x0ejava.lang.Long;\x8b\xe4\x90\xcc\x8f#\xdf\x02\x00\x01J\x00\x05valuexr\x00\x10java.lang.Number\x86\xac\x95\x1d\x0b\x94\xe0\x8b\x02\x00\x00xp\x00\x00\x01|\x1d\xa6\xbet"
"maxInactiveInterval" "\xac\xed\x00\x05sr\x00\x11java.lang.Integer\x12\xe2\xa0\xa4\xf7\x81\x878\x02\x00\x01I\x00\x05valuexr\x00\x10java.lang.Number\x86\xac\x95\x1d\x0b\x94\xe0\x8b\x02\x00\x00xp\x00\x00\x01\xe0"
"creationTime" "\xac\xed\x00\x05sr\x00\x0ejava.lang.Long;\x8b\xe4\x90\xcc\x8f#\xdf\x02\x00\x01J\x00\x05valuexr\x00\x10java.lang.Number\x86\xac\x95\x1d\x0b\x94\xe0\x8b\x02\x00\x00xp\x00\x00\x01|\x1d\xa6\xbet"
"sessionAttr:KEY" "\xac\xed\x00\x05t\x00\x06Erjuer"
========================
1632585039.478973 [0 127.0.0.1:57771]
"SADD" "spring:session:Erjuer:expirations:1632585540000" "\xac\xed\x00\x05t\x00,expires:1a61bf7b-5978-438c-a57f-82f9fd9df76f"
1632585039.479212 [0 127.0.0.1:57771]
"PEXPIRE" "spring:session:Erjuer:expirations:1632585540000" "780000"
========================
1632585039.479465 [0 127.0.0.1:57771]
"APPEND" "spring:session:Erjuer:sessions:expires:1a61bf7b-5978-438c-a57f-82f9fd9df76f" ""
1632585039.479730 [0 127.0.0.1:57771]
"PEXPIRE" "spring:session:Erjuer:sessions:expires:1a61bf7b-5978-438c-a57f-82f9fd9df76f" "480000"
========================
1632585039.479965 [0 127.0.0.1:57771]
"PEXPIRE" "spring:session:Erjuer:sessions:1a61bf7b-5978-438c-a57f-82f9fd9df76f" "780000"
========================
1632585039.480334 [0 127.0.0.1:57771]
"PUBLISH" "spring:session:Erjuer:event:0:created:1a61bf7b-5978-438c-a57f-82f9fd9df76f" "\xac\xed\x00\x05sr\x00\x11java.util.HashMap\x05\a\xda\xc1\xc3\x16`\xd1\x03\x00\x02F\x00\nloadFactorI\x00\tthresholdxp?@\x00\x00\x00\x00\x00\x04w\b\x00\x00\x00\x04\x00\x00\x00\x00x" 1632585039.482415 [0 127.0.0.1:57771]
"HGETALL" "spring:session:Erjuer:sessions:09897d67-7b4c-4570-94e9-d9ffad974b16"
이런식의 명령어를 통해 redis에 save되었을 것이다.
각각의 data를 조회해보면
spring:session:Erjuer:sessions:1a61bf7b-5978-438c-a57f-82f9fd9df76f 의 Type과 Value는 다음과 같다.
특히 httpsession에 get한 부분은
이다.
spring:session:Erjuer:sessions:expires:1a61bf7b-5978-438c-a57f-82f9fd9df76f의 Type과 value는 다음과 같다.
특히 모든 데이터값 앞에 \xac\xed\x00\x05sr\x00\x0와 같이 인코딩 된 것과 같은 형태로 붙여져 있는데 이것은 Redis template에서 데이터의 직렬화를 통해 데이터를 저장하기 때문이다.
직렬화를 통해 데이터를 저장하므로 session 클러스터링을 진행 했을 때 각각의 session에서 해당 데이터들을 조회할 수 있다.
[참조] The Redis template uses serializers for keys, values and hash keys/values. Serializers are used to convert the Java input into the representation that is stored within Redis
spring:session:Erjuer:expirations:1632585540000의 값은
1632585540000 millis-> Sun Sep 26 2021 00:59:00 Date에 만료되는 것을 의미한다.
추가로 8분이 지나고 session ID값이 1a61bf7b-5978-438c-a57f-82f9fd9df76f인 값은 expire되었는데
(spring:session:Erjuer:sessions:expires:1a61bf7b-5978-438c-a57f-82f9fd9df76f 없음)
조회시 아직 spring:session:Erjuer:sessions:1a61bf7b-5978-438c-a57f-82f9fd9df76f 값이 존재하는 것을 확인할 수 있다.
다음 포스팅은 Redis 명령어를 정리해보려고 한다.
Session을 set하고 get하는 API를 하나 뚫어놓고 redis-cli.exe로 확인하기 위해서는 명령어를 알아야 했고 매번 구글링하고 찾아보는 것이 아닌 자주 사용하는 명령어를 블로그에 정리해보고자 한다.
출처:
https://docs.spring.io/spring-session/docs/current/api/org/springframework/session/data/redis/RedisIndexedSessionRepository.html
'개발 지식 > Spring Framework' 카테고리의 다른 글
[thymeleaf] 기본 기능 정리 - 01 (0) | 2021.12.16 |
---|---|
[JWT] Spring Boot 환경에서 JWT(Json Web Token)생성 하기 (0) | 2021.10.26 |
[Redis Session] Spring Boot에서 Redis Session 활용하기 - 03 (0) | 2021.09.24 |
[Redis Session] Spring Boot에서 Redis Session 활용하기 - 02 (0) | 2021.09.23 |
[Redis Session] Spring Boot에서 Redis Session 활용하기 - 01 (0) | 2021.09.22 |
댓글