一、spring-session在redis在session中的存储结构

1.Http Session数据在Redis中是以Hash结构存储的

session标识为:33fdd1b6-b496-4b33-9f7d-df96679d32fe。

creationTime session的创建时间点是1404360000000(距离1/1/1970的毫秒时间)。

maxInactiveInterval: session的存在期限是1800秒(30分钟)。

lastAccessedTime: session的最近访问时间点是1404360000000(距离1/1/1970的毫秒时间)。

2.expires存储了session的id,并用于设置session的过期时间

3.key="spring:session:expirations:1431577740000"的数据,是以Set结构保存的。

这个值记录了所有session数据应该被删除的时间(即最新的一个session数据过期的时间)。

二、session在创建保持到redis中的存储过程

session在创建保持到redis中,有如下动作:

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

1. 首先保存session,作为Hash保持到redis中的,使用HMSET 命令:

HMSET spring:session:sessions:33fdd1b6-b496-4b33-9f7d-df96679d32fe creationTime 1404360000000 \ 
maxInactiveInterval 1800 \ 
lastAccessedTime 1404360000000 \ 
sessionAttr:attrName someAttrValue \ 
sessionAttr2:attrName2 someAttrValue2 


可以看出这些信息点:

  • session标识为:33fdd1b6-b496-4b33-9f7d-df96679d32fe。
  • session的创建时间点是1404360000000(距离1/1/1970的毫秒时间)。
  • session的存在期限是1800秒(30分钟)。
  • session的最近访问时间点是1404360000000(距离1/1/1970的毫秒时间)。
  • session有两个键值对属性:attrName-someAttrValue和attrName2-someAttrValue2。

2.当属性变更时:

HMSET spring:session:sessions:33fdd1b6-b496-4b33-9f7d-df96679d32fe sessionAttr:attrName2 newValue

session的过期通过EXPIRE 命令控制:

XPIRE spring:session:sessions:33fdd1b6-b496-4b33-9f7d-df96679d32fe 2100

注意到这里是2100而不是1800,说明设置的真实过期是在过期5分钟后。

为了保证在session销毁时,把session关联的资源都清理掉,需要redis在session过期时,通过“keyspace notifications ”触发SessionDeletedEvent/SessionExpiredEvent 事件。

因为session事件中涉及session信息,所以要保证这个时候,session的相关信息还是要存在。所以要把session的真实过期事件设置比需要的还有长5分钟,这样才能保证逻辑过期后,依然能获取到sssion信息。

3.因为要触发事件,所以session得过期时间设置的比逻辑上的晚5分钟,但是这样会造成不符合我们的逻辑设定,为此,过期的设置添加一些额外处理:

PPEND spring:session:sessions:expires:33fdd1b6-b496-4b33-9f7d-df96679d32fe "" 
EXPIRE spring:session:sessions:expires:33fdd1b6-b496-4b33-9f7d-df96679d32fe 1800


这样,当spring:session:sessions:expires:33fdd1b6-b496-4b33-9f7d-df96679d32fe在我们逻辑设定的时间点过期时,就会触发session销毁事件,

但是因为session的信息延后5分钟过期,又保证了在session事件中能正常获取到session信息。

4. 但是有个问题出现,这是redis独有的问题:redis的过期处理,实质上就是先看下这个key的过期时间,如果过期了,才删除。

所以,当key没有被访问到时,我们就不能保证这个实际上已经过期的session在何时会触发session过期事件。尤其redis后台清理过期的任务的优先级比较低,很可能不会触发的。

为了规避这个问题。我们可以确保:当每个key预期到期时,key可以被访问到。这个就意味着:当key的生命周期到期时,我们试图通过先访问到它,然后来让redis删除key,同时触发过期事件。

为此,要让每个session在过期时间点附近就可以被访问追踪到,这样就可以让后台任务访问到可能过期的session,以更确定性的方式确保redis可以触发过期事件:

SADD spring:session:expirations:1439245080000 expires:33fdd1b6-b496-4b33-9f7d-df96679d32fe 
EXPIRE spring:session:expirations1439245080000 2100


后台任务通过映射(eg:expires:33fdd1b6-b496-4b33-9f7d-df96679d32fe)关联到准确的请求key。通过访问key,而不是删除它,我们可以确保只有当生命周期过期时,redis才会删除这个key。

我们并不能很确切地删除这些key,因为在一些情况下,可能会错误地认定key过期了,除了使用分布式锁外,没有任何一种方法能保证过期映射的一致性。

但是通过简单的访问方式,我们却可以保证只有过期能才会被删除。

====================================================================================================================

相关文章

1. http://blog.csdn.net/zcl111/article/details/51700925

2. http://blog.csdn.net/noaman_wgs/article/details/71170083

3. http://blog.csdn.net/sunshinwong/article/details/72356734?locationNum=5&fps=1