Spring Session 把会话存成了什么?Redis 里的值能直接读吗?超时到底在哪配?属性不可序列化会怎样?每个请求给 Redis 增加多少压力?这篇在 Spring Session 4.0.5 和真实的 Redis 上用两个实例实测。
[默认] Redis 里的 key:['spring:session:sessions:<id>']
会话 hash 的字段:['creationTime', 'lastAccessedTime', 'maxInactiveInterval', 'sessionAttr:k'];各 key 的 TTL(秒):[('spring:session:sessions:<id>', 1800)]
属性 k 的原始字节前 4 个 = [172, 237, 0, 5](Java 序列化头是 172, 237 即 0xACED);Set-Cookie:名字 SESSION,属性 Path=/; HttpOnly; SameSite=Lax;cookie 值 base64 解码后 = 343a5ad9… 与会话 id 前 8 位 343a5ad9 相同
[旧属性名 spring.session.redis.repository-type=indexed] Redis 里的 key:['spring:session:sessions:<id>']
会话 hash 的字段:['creationTime', 'lastAccessedTime', 'maxInactiveInterval', 'sessionAttr:k'];各 key 的 TTL(秒):[('spring:session:sessions:<id>', 1800)]
属性 k 的原始字节前 4 个 = [172, 237, 0, 5](Java 序列化头是 172, 237 即 0xACED);Set-Cookie:名字 SESSION,属性 Path=/; HttpOnly; SameSite=Lax;cookie 值 base64 解码后 = 19b15dd9… 与会话 id 前 8 位 19b15dd9 相同
[spring.session.data.redis.repository-type=indexed] Redis 里的 key:['spring:session:expirations:<ts>', 'spring:session:sessions:<id>', 'spring:session:sessions:expires:<id>']
会话 hash 的字段:['creationTime', 'lastAccessedTime', 'maxInactiveInterval', 'sessionAttr:k'];各 key 的 TTL(秒):[('spring:session:expirations:<ts>', -1), ('spring:session:sessions:<id>', 2100), ('spring:session:sessions:expires:<id>', 1800)]
属性 k 的原始字节前 4 个 = [172, 237, 0, 5](Java 序列化头是 172, 237 即 0xACED);Set-Cookie:名字 SESSION,属性 Path=/; HttpOnly; SameSite=Lax;cookie 值 base64 解码后 = 00a780a4… 与会话 id 前 8 位 00a780a4 相同默认一个 hash,indexed 仓库三类 key;值是 Java 序列化。
在实例 A 上 /set 之后,用同一个 cookie 请求实例 B 的 /get:k=from-A id=65598519 对照:没有 Spring Session,同样请求实例 B:没有会话(cookie 名 JSESSIONID)
多个实例共享同一个会话。
存一个可序列化对象:ok;存一个没有实现 Serializable 的对象:HTTP 500(请求结束写 Redis 时失败) 之后 GET /get:k=x id=a23ee6d3
不可序列化的属性在请求结束时才失败。
[默认] 会话 hash 的 TTL = 1800 秒 [server.servlet.session.timeout=100s] 会话 hash 的 TTL = 100 秒 [spring.session.timeout=60s] 会话 hash 的 TTL = 60 秒 [两个都配(server 100s,spring.session 60s)] 会话 hash 的 TTL = 60 秒
spring.session.timeout 优先。
立刻 GET /get:k=x id=db51536f 4.5 秒后 Redis 里还有会话 hash:False;用同一个 cookie GET /get:没有会话
默认仓库靠 Redis TTL。
带 cookie 但不碰会话的 /noop:{'hmset': 1, 'pexpireat': 1, 'exists': 2, 'hgetall': 2}(共 6 条)
读会话属性 /read:{'hmset': 1, 'pexpireat': 1, 'exists': 2, 'hgetall': 2}(共 6 条)
写会话属性 /set:{'hmset': 1, 'pexpireat': 1, 'exists': 2, 'hgetall': 2}(共 6 条)每个带 cookie 的请求 6 条命令并续期。