简析分布式集群中的session一致性

来源:互联网 发布:香水时代的淘宝店怎么 编辑:程序博客网 时间:2024/06/04 01:28

前言

随着互联网用户的逐渐增多,系统设计的业务量的几何式扩大,单系统的项目在应对大量的请求时,越来越显得力不从心。于是集群分布式项目被提出来了,这样将单系统的压力分摊到分布式系统的多个子系统中。这样确实很好的提高了效率,但是从单系统向分布式集群系统转换的过程并不是那么顺利。这其中遇到了一系列的问题,分布式集群系统中的session一致性就是一个不可回避的问题。这里和大家一起简单学习一下解决session一致性的问题的几种方式。

何为分布式集群中的session一致性

对于分布式中的session一致性,有些刚刚接触web开发的萌新可能不太清楚这个概念,这里简单结合单系统的session和分布式系统中session来解释一下。对于Session的概念想必大家应该都很熟悉,他是指浏览器和服务器之间维持的一个session会话,由于http协议本身是无状态的,所以为了保持一个用户的状态,例如登录状态。我们通常会将用户的信息以及登录信息在用户登录成功之后存储在session会话之中,用户在不关闭浏览器,并且session没有实现实效的请求下,用户的请求都是属于同一个session。单系统的session维持如下图
这里写图片描述
这种通过cookie来维持单系统的session是可以的,但是如果在分布式集群系统,来自浏览器的请求可能被nginx分发到的集群系统中任一一个,如下图,如果一个用户通过浏览器在进行登录,登录请求被转发到A服务器,服务器核实用户名,密码之后登录成功,那么浏览器就会和A服务器建立session,用户登录成功之后,执行其他操作,但是其他操作的请求有可能被ngnix转发到服务器B上,但是服务器B上没有用户的session啊,所以服务器直接跳到登录界面了,这时候的用户肯定是一脸懵逼啊。。。。搞啥!
这里写图片描述
上面就是session不一致导致的,如果一个系统莫名其妙的出现的这种情况,用户的流失是迟早的事,那么这个session不一致问题我们该如何解决呢?

将session存储在客户端

首先要讲的是,这是解决上面session不一致的一种方式,可行并不代表在实际开发中使用,但是这种方式我们还是可以了解一下,所谓的将session存储在客户端就是指将用户的会话存储在用户使用的客户端上,一般是指浏览器。用户每次请求的时候都会带上自己的session,这样就不用担心session不一致的问题。同时由于session存储在客户端,所以服务器上没有了存储很多session的压力。但是由于每次请求的时候都需要带上session,比较占用外网带宽,同时由于session存储在客户端,安全性也是问题,会话攻击和会话劫持也是比较头疼的问题。

在各个服务器上复制

既然放在客户端上,安全性,又占用外网带宽,那么我们将session还是放在服务器端吧,这样至少比在客户端上安全。所谓session不一致,说白了就是有的服务器上没有session,那么我们自己将一个服务器上的session复制到其他session上不就搞定了嘛。显然这是一种可行的方式,只要有session变化,或者失效,我们就将session状态复制到其他服务器上。这样用户的请求不管被nginx转发到哪个服务器上都不用怕了,但是这种方式是不是说就是绝对完美呢,显然不是,首先由于session在各个服务器上复制传递本身就是占用了内网带宽,同时由于一个服务器上会存储本身的session还有其他服务器复制过来的session,这样单台服务器上存储的session数目将会很大,这对服务器的存储压力就会很大,所以服务器的横向拓展性很差。同时session在各个服务器间的复制还具有一定的延迟性。

通过nginx粘性转发

上面的将session存储在客户端不安全,在每个服务器上都存储所有的session这样又给服务器带来很大的压力,那有没有办法将特定的用户的请求转发的特定的服务器上。办法总是有的,其中nginx根据是用户的ip地址hash值来实现负载均衡,这种四层四层负载均衡就可以将特定ip上的用户请求转发到特定的服务器上,如果ip地址hash很均匀,那么这种方式就可以解决分布式系统中的session一致性问题。而且服务器的横向拓展也很好实现,但是这种方式也还是有缺陷的,就比方说,如果某个服务器挂掉了,就会导致部分session丢失。对于上面的ip地址hash的具体原理可以参见这篇小记扫盲系列之负载均衡算法,上面是根据ip地址来进行hash,当然我们还可以根据用户的一些专门标志来进行hash,如userid。

通过专门的存储来存放session

上面讲的几种方式都各有千秋,各自的使用情况结合具体的情况来决定,一般在开发中,如果对高并发,高可用的要求比较高,我们一般将session放在一个专门的容器中来存储,这个容器可以是实际的数据库,也可以是缓存数据库,像redis。具体就像下图
这里写图片描述
session放在专门的存储中,安全性是比较好,就是某台集群服务器挂掉了,也不会造成session的丢失。但是由于要访问存储容器,无形中增加了一次访问,所以对效率会有一定的影响。同时由于所有的session如果都存在数据库中,那么对于数据库的压力也是不可忽视的,所以相比较而言,存在缓存容器中更加合适,由于缓存要设置一定的缓存时间,同时session也会有失效时间,所以这样就不谋而合了。

总结

上面简单介绍了几种解决方案,具体的那个比较好,我们应该根据项目的实际情况来选择,没有最好,只有在实际环境中的最合适。以上都是基础概念的理解,实际效果需要我们自己动手实践咯!