Spring Cloud学习笔记—分布式下的Session共享
分布式下的Session
在单应用的年代,基于Session来做用户的登录、退出等,总是令人感到轻松而愉快的。然而,在分布式下,情况变得复杂起来,如下:
分布式请求路径
用户的请求可能会被分散在A和B上,这意味着,在A中对Session的操作,如果不作特殊处理的话,B是无感的。这类问题,我们称之为Session共享的问题。通常来说,我们有以下四种解决方案:
Session复制。这是一个很顺畅的思路,既然A和B中的Session不一致,那我做一个同步的复制就好了。没错,这确实是一种解决方案,并且,在一些中小型分布式站点里,也被经常使用。Tomcat等容器也支持以简单的配置来实现Session复制。但是,当分布式的规模变大,服务器数量变多时,这种方式变得不太可靠。这是因为,Session的复制也是需要时间的,为了保证一致性,每个涉及Session更新的请求可能都需要等待Session完全复制一遍后才能算响应完成。而这,在服务器数量多,尤其是用户量又大的情况下,会导致响应时间过长,且可能会导致服务器内存不足(复制消耗内存)。Session绑定。如果说方案一是一个解决问题的定向思路的话,方案二就有点投机取巧。解决不了问题,就解决提问题的人。既然用多台服务器处理同一客户端的请求存在困难,那我就把同一客户端的请求都定位到同一服务器好了。这种方案,可以简单地通过nginx的ip-hash策略来解决。但是,它的问题是当服务器中某节点宕机后,该节点中的Session数据将全部丢失,反映到网站中,可能的表现是:有一波用户突然发现自己登录状态丢失了,需要进行一次重新的登录验证。不用Session。严格来说,这不能成为一个分布式Session的解决方案。因为这种方案,相当于是:Session既然有问题,那我不用就好了。一般来说,可能会用Cookie来代替Session。我们知道,Cookie是完全存在于客户端的。所以,Cookie和服务器无关。但是,Cookie本身可存在的数据大小存在限制,类型也存在限制,Cookie在客户端,服务器对其安全性能做得更少。还有就是,当一些关键信息放在Cookie里时,在必要的时候,可能需要携带这些信息发起请求,当要携带的信息较多时,会造成较大的网络开销,影响用户体验。第三方存储。这种方案是本篇要重点介绍的方案,也是推荐的分布式Session共享解决方案,如下:
从客户端的角度来看,第三方存储的基本思路是,把Session的存储位置,从服务器向后移,放到了一个通用的第三方存储中。这种解决方案,相当于是在每次的Session读写时,引入了一个额外的,和第三方存储进行交互的网络请求,但是,它不需要Session复制,也不需要Session绑定。事实上,对比Session复制和第三方存储,可以这样理解:通常对每次请求引入一个极小的延迟,来避免若干请求可能的极大延迟。有点大事化小,小事化了的感觉,但这种类型的解决思路,在分布式系统下,其实是经常遇到的。
适合用作Session的容器
如果是单纯从功能上来说的话,大部分的容器都可以充当第三方存储,比如说数据库,甚至于说是某台独立的主机。但是,在分布式的前提下,我们必须要考虑高可用,高并发等问题。这样,你会发现,使用Redis等这种内存NoSQL数据库是最好不过了。读写速度快,支持集群。如下:
Redis实现Session共享
第三方存储该如何实现
那么,该如何实现一个针对Session共享的第三方存储的解决方案呢?简单的,我们可以直接引入一个现成的轮子,比如Spring体系中的spring-session。当然了,想要自己搞一个,其实也并不复杂。大方向上有两种:
实现一个外挂缓存类,用这个缓存类替代原来的Session操作。重写请求、响应的相关内容,把原来的Sessio操作和第三方存储关联起来。无论是哪种方案,关键问题都是两个:
关键词: session