session 机制是一种服务器端的机制,服务器使用一种散列表或者类似的结构来保存信息。在使用分布式 session 前会有这样两个疑问:

1)为什么采用分布式 session :

当我们的系统当中有多台服务器的时候,我们无法保证 session 在多台机器都存在,这是因为我们用户的请求不一定会被路由到同一台机器上。也就是说对应一个用户的 session 信息在服务器 A 上存在,但是在服务器 B 上不存在,因为请求被路由到了服务器 A 上,所以我们需要让集群中的多台机器共享 session 信息。

2)为什么重写 session:

session 只能存储在本地 web 服务器的内存当中,但无法满足 session 在多台服务器的分布式环境下,多台机器共享 session 数据的问题,所以我们需要重写,让它在分布式环境下,拥有 session 数据共享功能。

分布式session_分布式session解决方案_分布式session问题

session配置方法

当程序需要为某个客户端的请求创建一个 session 的时候,服务器首先检查这个客户端的请求里是否包含了一个 session 标识,称为 session-id。

如果已经包含一个 session-id 则说明以前已经为此客户创建过 session,服务器就按照session-id 把这个 session 检索出来使用(如果检索不到,可能会新建一个,这种情况可能出现在服务端已经删除了该用户对应的 session 对象,但用户人为地在请求的 URL 后面附加上一个 JSESSION 的参数)。

如果客户请求不包含 session-id,则为此客户创建一个 session 并且生成一个与此 session 相关联的 session-id,这个session-id将在本次响应中返回给客户端保存。

其实分布式 session 并不是一个特别难的课题,实现的思路也有很多种。今天我将介绍一种使用起来非常简单的方法,只要做如下配置即可使用:

1 )导入一个jar在pom文件中

分布式session问题_分布式session解决方案_分布式session

2)在 web.xml 文件中配置一个 filter

分布式session问题_分布式session解决方案_分布式session

session 使用方法

分布式 session 的使用:从使用者的角度不需要知道是否为分布式 session,一句即可搞定,而且和容器无关。

为了保证读者可以理解这种方法,下面我将以最简洁的方法来实现。

1拦截器的实现

这个拦截器拦截了所有路径的客户端请求,并且在请求进去 Controller 之前把HttpServletRequest 替换成我自己实现的一个 HttpServletRequest,叫做DistributionSessionRequestWrapper

分布式session_分布式session解决方案_分布式session问题

2DistributionSessionRequestWrapper 的实现

分布式session解决方案_分布式session问题_分布式session

HttpServletRequestWrapper 是 HttpServletRequest 的装饰类,通过继承它,覆盖你希望改变的方法,你可以改变当前 HttpServletRequest 对象的状态。

从 session 的使用角度上来说,你只会用 getSession() 这个方法,那么我覆盖这个方法就ok了,在 getSession() 中我做了两件事:

3DistributionSessionImpl 的实现

分布式session解决方案_分布式session_分布式session问题

在 DistributionSessionImpl 中有两个属性比较重要

sessionMap:用来存储一次请求中的 session 数据

sessionStore:把用户的 session 数据存储到分布式缓存的类

getId() 方法:通过这个方法可以获取用户的 cookie 中 key=“pcxSessionId”的value 值

分布式session解决方案_分布式session问题_分布式session

getAttribute():通过 key中 pcxSessionId从缓存中获取用户的 session 数据

分布式session_分布式session问题_分布式session解决方案

setAttribute():如果为空的话,那么从分布式缓存中获取用户的 session 数据,当然如果这个用户是第一次访问的话,这个 sessionMap 可能还是为空,这个逻辑的话在sessionStore 有判断;把key-value数据存储到本地的sessionMap中,然后把数据推送到分布式缓存中

分布式session解决方案_分布式session_分布式session问题

removeAttribute():清除本地 map 中的 Attribute 然后再把分布式缓存中的getID() 给删掉

分布式session问题_分布式session_分布式session解决方案

Invalidate():先清除本地的 sessionmap 然后删除分布式缓存中的 session 数据,最后清除 cookie

4SessionStore 的实现

session 存储的时候使用 hession 的序列化,然后通过调用 jedis的 api 存放session 数据。这个类应该是很容易理解的,当然具体你用 redis 还是 memcached 这个随意了。

分布式session解决方案_分布式session问题_分布式session

至此,一个基本的分布式 session 就实现了。它的本质是加一个拦截器然后把 HttpServletRequest 替换成自己定义了,然后覆盖掉 getSession 方法,最后用一个我自己定义的 HttpSession 实现来完成各种操作。

总结

上述代码只是保留了最基本的实现,我们也可以继续优化封装,添加更多的功能。下面笔者以减少用户与分布式缓存机器的通信次数的优化为例,供大家参考。

从 DistributionSessionImpl 中我们可以看出,每次 setAttribute 和removeAttribute 数据都会同步到分布式缓存,这个实际上是没有必要的,虽说分布式缓存和我们的 server 虽然是在内网中通信,但是来回的次数会增加其时间损耗。

我们不能保证把一个用户的请求一直路由到同一台机器上,但是能够保证一次 request 在一台机器上,我们可以在用户的一次请求结束后把这个用户的 Session 数据同步到分布式缓存当中,以减少了与分布式缓存机器的通信次数。

分布式session问题_分布式session解决方案_分布式session

本文作者:彭晨雪(点融黑帮),现就职于点融网工程部 LB 团队,java 开发工程师一枚。

随着点融网新一轮融资,点融网即将开始大规模的扩张,需要各种优秀人才的加入,如果你觉得自己够优秀,欢迎加入我们!获取更多职位信息,请关注点融黑帮。

分布式session问题_分布式session解决方案_分布式session

限 时 特 惠: 本站每日持续更新海量各大内部创业教程,一年会员只需98元,全站资源免费下载 点击查看详情
站 长 微 信: lzxmw777

发表回复

您的电子邮箱地址不会被公开。 必填项已用*标注