1. Session 机制详解

1.1 为什么要产生 Session

http 协议本身是无状态的,客户端只需要向服务器请求下载内容,客户端和服务器都不记录彼此的历史信息,每一次请求都是独立的。

为什么是无状态的呢?因为浏览器与服务器是使用 socke 套接字进行通信,服务器将请求结果返回给浏览器之后,会关闭当前的 socket 链接,而且服务器也会在处理页面完毕之后销毁页面对象。

然而在 Web 应用的很多场景下需要维护用户状态才能正常工作 (是否登录等),或者说提供便捷(记住密码,浏览历史等),状态的保持就是一个很重要的功能。因此在 web 应用开发里就出现了保持 http 链接状态的技术:一个是 cookie 技术,另一种是 session 技术。
分布式 Session 常见的几种解决方案 - 图1

1.2 Session 有什么作用,如何产生并发挥作用

要明白 Session 就必须要弄明白什么是 Cookie,以及 Cookie 和 Session 的关系。

(1) 什么是 Cookie

Cookie 技术是 http 状态保持在客户端的解决方案,Cookie 就是由服务器发给客户端的特殊信息,而这些信息以文本文件的方式存放在客户端,然后客户端每次向服务器发送请求的时候都会带上这些特殊的信息。

(2) Cookie 的产生

当用户首次使用浏览器访问一个支持 Cookie 的网站的时候,用户会提供包括用户名在内的个人信息并且提交至服务器;接着,服务器在向客户端回传相应的超文本的同时也会发回这些个人信息,当然这些信息并不是存放在 HTTP 响应体(Response Body)中的,而是存放于HTTP 响应头(Response Header);当客户端浏览器接收到来自服务器的响应之后,浏览器会将这些信息存放在一个统一的位置。

不同的浏览器间不能共享存储在硬盘上的 cookie ,可以在同一浏览器的不同进程间共享,比如两个 IE 窗口。这是因为每中浏览器存储 cookie 的位置不一样,比如:

  • Chrome 下的 cookie 放在:C:\Users\sharexie\AppData\Local\Google\Chrome\User Data\Default\Cache
  • Firefox 下的 cookie 放在:C:\Users\sharexie\AppData\Roaming\Mozilla\Firefox\Profiles\tq2hit6m.default\cookies.sqlite (倒数第二个文件名是随机的文件名字)
  • IE 下的 cookie 放在:C:\Users\Administrator\AppData\Roaming\Microsoft\Windows\Cookies

(3) Cookie 的内容、作用域、有效期

cookie的内容主要包括:名字,值,过期时间,路径和域。路径与域合在一起就构成了 cookie 的作用范围。

  • 如果不设置过期时间,则表示这个 cookie 的生命期为浏览器会话期间,只要关闭浏览器窗口,cookie 就消失了,这种生命期为浏览器会话期的 cookie 被称为会话 cookie。会话 cookie 一般不存储在硬盘上而是保存在内存里。
  • 如果设置了过期时间,浏览器就会把 cookie 保存到硬盘上,关闭后再次打开浏览器,这些 cookie 仍然有效直到超过设定的过期时间。

(4) Cookie 如何使用

cookie 的使用是由浏览器按照一定的原则在后台自动发送给服务器的。

当客户端二次向服务器发送请求的时候,浏览器检查所有存储的 cookie,如果某个 cookie 所声明的作用范围大于等于将要请求的资源所在的位置,则把该 cookie 附在请求资源的 HTTP 请求头上发送给服务器。有了 Cookie 这样的技术实现,服务器在接收到来自客户端浏览器的请求之后,就能够通过分析存放于请求头的 Cookie 得到客户端特有的信息,从而动态生成与该客户端相对应的内容。通常,我们可以从很多网站的登录界面中看到“请记住我”这样的选项,如果你勾选了它之后再登录,那么在下一次访问该网站的时候就不需要进行重复而繁琐的登录动作了,而这个功能就是通过 Cookie 实现的。

(5) 什么是 Session

Session 一般叫做会话,Session 技术是 http 状态保持在服务端的解决方案,它是通过服务器来保持状态的。我们可以把客户端浏览器与服务器之间一系列交互的动作称为一个 Session。是服务器端为客户端所开辟的存储空间,在其中保存的信息就是用于保持状态。因此,session 是解决 http 协议无状态问题的服务端解决方案,它能让客户端和服务端一系列交互动作变成一个完整的事务。

(6) Session 的创建

那么 Session 在何时创建呢?当然还是在服务器端程序运行的过程中创建的,不同语言实现的应用程序有不同创建 Session 的方法。

当客户端第一次请求服务端,当 server 端程序调用 HttpServletRequest.getSession(true) 这样的语句的时候,服务器会为客户端创建一个 session,并将通过特殊算法算出一个 session 的 ID,用来标识该 session 对象。

Session 存储在服务器的内存中 (tomcat 服务器通过 StandardManager 类将 session 存储在内存中),也可以持久化到 file,数据库,memcache,redis 等。客户端只保存 sessionid 到 cookie 中,而不会保存 session。

浏览器的关闭并不会导致 Session 的删除,只有当超时、程序调用 HttpSession.invalidate() 以及服务端程序关闭才会删除。

(7) Tomcat 中的 Session 创建

**ManagerBase** 是所有 session 管理工具类的基类,它是一个抽象类,所有具体实现 session 管理功能的类都要继承这个类,该类有一个受保护的方法,该方法就是创建 sessionId 值的方法:tomcat 的 session 的 id 值生成的机制是一个随机数加时间加上 jvm 的 id 值,jvm 的 id 值会根据服务器的硬件信息计算得来,因此不同 jvm 的 id 值都是唯一的。

**StandardManager** 类是 tomcat 容器里默认的 session 管理实现类,它会将 session 的信息存储到 web 容器所在服务器的内存里。

PersistentManagerBase 也是继承 ManagerBase 类,它是所有持久化存储 session 信息的基类,PersistentManager 继承了 PersistentManagerBase,但是这个类只是多了一个静态变量和一个 getName 方法,目前看来意义不大,对于持久化存储 session,tomcat 还提供了 StoreBase 的抽象类,它是所有持久化存储 session 的基类,另外 tomcat 还给出了文件存储 FileStore 和数据存储 JDBCStore 两个实现。

(8) Cookie 与 Session 的关系

cookie 和 session 的方案虽然分别属于客户端和服务端,但是服务端的 session 的实现对客户端的 cookie 有依赖关系的,服务端执行 session 机制时候会生成 session 的 id 值,这个 id 值会发送给客户端,客户端每次请求都会把这个 id 值放到 http 请求的头部发送给服务端,而这个 id 值在客户端会保存下来,保存的容器就是 cookie,因此当我们完全禁掉浏览器的 cookie 的时候,服务端的 session 也会不能正常使用。

2. 分布式架构中 Session 的问题

单体架构:
在单体服务器的年代,Session 直接保存在服务器中,是没有问题的,而且实现起来很容易。

分布式架构:
但是随着分布式架构的流行,单个服务器已经不能满足系统的需要了,通常都会把系统部署在多台服务器上,通过负载均衡把请求分发到其中的一台服务器上;

那么很有可能第一次请求访问的 A 服务器,创建了 Session ,但是第二次访问到了 B 服务器,这时就会出现取不到 Session 的情况;

于是,分布式架构中,Session 共享就成了一个很大的问题。
分布式 Session 常见的几种解决方案 - 图2

3. 分布式 Session 解决方案

3.1 不使用 Session

在很多接口类系统当中,都是提倡”无状态服务”的,也就是每一次的接口访问,都不依赖 Session,不依赖于前一次的接口访问;

对于身份认证的场景,也可以不使用 Session 进行认证,而使用 JWT Token 存储用户身份,然后再从数据库或 Cache 中获取其他的信息。这样无论请求分配到哪个服务器都无所谓。

3.2 Session 复制

session 复制是早期的企业级的使用比较多的一种服务器集群 session 管理机制。
应用服务器开启 web 容器的 session 复制功能,在集群中的几台服务器之间同步 session 对象,使得每台服务器上都保存所有的 session 信息,这样任何一台宕机都不会导致 session 的数据丢失,服务器使用 session 时,直接从本地获取。
分布式 Session 常见的几种解决方案 - 图3

  • session 复制使用场景:机器较少,网络流量较小;
  • 优点:实现简单、配置较少、当网络中有机器 Down 掉时不影响用户访问;
  • 缺点:广播式复制到其余机器有一定延时,带来一定网络开销;

这种方式在应用集群达到数千台的时候,就会出现瓶颈,每台都需要备份 session,会出现内存不够用的情况,所以不推荐使用这种方案!!!

3.3 Session 客户端存储

session 记录在客户端,每次请求服务器的时候,将 session 放在请求中发送给服务器,服务器处理完请求后再将修改后的 session 响应给客户端,这里的客户端就是 cookie。
分布式 Session 常见的几种解决方案 - 图4

  • 缺点:
    • 比如受 cookie 大小的限制,能记录的信息有限;
    • 每次请求响应都需要传递 cookie,增大网络的开销,如果用户关闭 cookie,访问就不正常;
    • Cookie 存储用户的敏感数据,安全性存在问题,要做加密方案,避免敏感信息被窃取或篡改;
  • 优点:
    • cookie 的简单易用,可用性高,支持应用服务器的线性伸缩,而大部分要记录的 session 信息比较小,因此事实上,许多网站或多或少的在使用 cookie 记录 session。

存在一定的安全隐患,所以一般也是不推荐使用这种方案!!!

3.4 Session 绑定

利用 Nginx 服务器的反向代理,将服务器 A 和服务器 B 进行代理,然后采用 ip_hash 的负载策略,将客户端和服务器进行绑定,也就是说客户端 A 第一次访问的是服务器 B,那么第二次访问也必然是服务器 B,这样就不存在session 不一致的问题了。
分布式 Session 常见的几种解决方案 - 图5

  • session 绑定使用场景:机器数适中、对稳定性要求不是非常苛刻
  • 优点:实现简单、配置方便、没有额外网络开销
  • 缺点:网络中有机器 Down 掉时、用户 Session 会丢失、容易造成单点故障。

这种方式不符合对系统的高可用要求,因为一旦某台服务器宕机,那么该机器上的 session 也就不复存在了,用户请求切换到其他机器后没有 session,无法完成业务处理,所以也不推荐这种方案!!!

3.5 Session 后端集中管理

这种方式就是利用独立部署的 session 服务器(集群)将所有服务器的 session 进行统一管理,服务器每次读写 session 时,都要访问 session 服务器。

这种解决方案事实上是应用服务器的状态分离,分为无状态的应用服务器有状态的 session 服务器,然后针对这两种服务器的不同特性分别设计架构。

对于有状态的 session 服务器,一种比较简单的方法是利用分布式缓存(redis、memcached), 或者存储在数据库(如 MySQL )等。在这些产品的基础上进行包装,使其符合 session 的存储和访问要求。

如果业务场景对 session 管理有比较高的要求,比如利用 session 服务实现单点登录(sso),用户服务器等功能,需要开发专门的 session 服务管理平台。

分布式 Session 常见的几种解决方案 - 图6

  • session 服务器使用场景:集群中机器数多、网络环境复杂。
  • 优点:
    • 可以很容易实现水平扩展;
    • 服务器重启 Session 不会丢失;
    • 不仅可以跨服务器 Session 共享,甚至可以跨平台(例如网页端和 APP 端);
  • 缺点:
    • 引入 Redis 或其他 Session 服务器,会增加代码复杂度,架构变的复杂;
    • 获取 Session 需要多访问一次 Session 服务器,增加一次额外的网络开销;

这也是目前企业开发用到的比较多的一种分布式 session 解决方案,推荐使用!!!

4. 总结

分布式 Session 常见的几种解决方案 - 图7
当我们后端 Web 应用扩展到多台后,我们就会碰到分布式一致性 Session 的问题,主流解决方案有四种:

  • Session 复制:利用 Tomcat 等 Web 容器同步复制
  • Session 前端存储:利用用户浏览器中 Cookie 保存 Session 信息
  • Session 粘滞方案:利用 Nginx 可以做四层 Hash 或七层 Hash 的特性,保证用户的请求都落在同一台机器上
  • Session 后端集中存储方案:利用 Redis 集中存储 Session,Web 应用重启或扩容,Session 也无需丢失。

上面四种方案,优先推荐第四种。

当然第四种方案需要一定的开发工作量,前期还没改造的过程可以选择 第三种方案中间过渡。

参考: https://www.cnblogs.com/jing99/p/11785070.html https://mp.weixin.qq.com/s/QcNGX21Ij7AS9lBKtq9IfA