独立实现一个分布式session

gf67 9年前

对于一个独立应用来说,单机部署不需要考虑分布式问题,默认的session实现就行了,一旦多机部署,首先我们需要修改session方案,分布式session解决的是多机session状态同步的问题,一般情况下,会有2种常见的方案

      

1,简单点,机器间相互同步,当一台机器上的session状态改变后,自动发送请求到其他所有机器上,同步状态,这样做当然是可行的,但缺点也很明显,机器之间的网络通讯比较频繁,而且网络问题会引起某些机器的session状态未及时同步,导致用户端访问出现异常

      

2,对于多机部署的应用来说,用一台机器做session服务器,应用集群全部请求这台session服务器获取session信息,这样做避免了状态同步这种繁琐的事情,但仍有缺点,当qps很高的情况下,session服务器的网络压力会非常大,因为所有请求都会落到这一台机器上来,一般存储session信息可以使用redis或者其他分布式cache数据库来做,如何解决上述问题呢,我的做法是,充分利用每台应用服务器的内存做一个二级缓存,来缓解session服务器的压力,只有session信息改变后 application才会去请求session 服务器拉去最新的session信息同步到本机,否则直接读取本机session返回给客户端,那如何做呢,大家都知道,浏览器是根据sessionid 这个标识传给服务器读取session的,我们提出一个跟sessionid同等地位概念,叫版本:session_version,我们将 session_version存储到cookie中,且在服务端也存储起来,可以跟sessionid做一个一对一的关联;ok,当用户发起请求到服务器改变了session信息后,该服务器读取cookie中的session_version,对其加一后更新cookie;这时候用户cookie里的 session_version已经改变,用户再起请求服务器,可能请求落到其他机器上,那这台机器先检查本服务器上的sessionid对应的 session_version版本是否比用户cookie中的低,如果低,则请求session服务器获取最新的session,同时更新服务器内存中的session_version到最新版本,如果session_version比对一致,则直接返回服务器本地的session给用户;

这样做可以充分环节session服务器的压力,但对应用server的内存要求就会有些高了,因为要缓存session信息,我推荐应用使用本地缓存存储session信息,例如ehcache这种的,信息可以同步到硬盘上持久化一下;这个方案适合一些中型业务规模的应用,并不适合超大规模业务场景;


       3,其实我们还有别的方案,就是session服务器可以做成集群,这样就不会出现所有请求都落到一台session服务器上去,那这时候就会有新的问题了,既然是集群,那么对于session集群来说,server的数量会有增有减,我们应用获取session信息往往是通过:sessionService.getSession(sessionid);这样的方式去获取的,这很像hash 的做法,效率高,键值对;那既然是session集群,必然存在当我根据sessionid求hash时,怎么确定落在哪台具体的session服务器上呢,如果求hash的过程是在client端进行,那就太不灵活了,一旦机器有增减,就会导致你get不到数据,所以这个集群需要做个代理服务,由这个服务统一想client提供服务,然后代理服务里面做这个hash映射的事情;ok,这时候,我要增加一台机器,那之前hash的那些映射关系必然会被打乱,撤掉一台机器,也一样会出问题,我们怎么解决这样的问题呢,答案是一致性hash,组成一个环状结构,每个hash落点存储到离他最近的那台机器上去,增删数据时,当我们下掉机器后,要把本机器上的数据,重新hash迁移一下,增加机器时,将落到本机上的数据从其他机器上迁移过来,这种叫集群内部的自动化调整,这样就保证了数据的一致性,我们也方便进行扩容和下线;
另外还有一个问题,对于一些应用来说,可能某一部分用户的活跃度很高,导致在这个环形的 hash分布中,hash落点出现聚集效应,结果就是个别机器的存储量明显高于其他机器,这样资源利用和负载明显不均衡,如何解决这个问题呢,答案是,我们可以再做一次虚拟映射,将每天机器上映射成多个节点,平均地分布到环形区域中,这样hash落点只是落到虚拟节点上,从而完美滴解决了hash分布不均衡的问题,当然由于再次封装了一层,这会导致性能上的损失,但这种损失是微乎其微的,可以接受。

来自:http://my.oschina.net/glarystar/blog/465992