分布式session的6种解决方案

先来复习三个基础问题 : 

Q1 . session什么时候创建 ? 

一个常见的错误是在客户端请求到达的时候就被创建 , 然而实际上是直到某服务端程序(如servlet)调用HttpServletRequest.getSession(true)这样的语句时才会被创建 . 

如果在该语句之前有个拦截器拦截了该请求 , 则此时就不会创建session . 

Q2 . 分布式环境下 , 如果未采取session同步策略会怎样

答案是sessionId一致 , session对象不一致

原因如下 : 

  1. 客户端首次请求 , 分配到服务器A , A首先检查客户端请求中是否包含sessionId , 首次则没有 . 然后A创建一个session对象保存会话信息 , 并生成唯一的session标识sessionId返回给客户端
  2. 然后每次客户端请求都会携带该标识sessionId
  3. 客户端第二次请求 , 可能分配到服务器B , B检测到请求中包含sessionId , 则先会根据sessionId检索响应的session对象 , 检索不到 , 会新建一个session对象 , sessionId不变 . 

Q3 . 什么情况下客户端请求会携带sessionId , 但服务器中无对应的session ? 

  1. 服务器分布式部署且未同步session , 第二次或N次的请求被路由到一个从未访问的服务器上
  2. 客户端重写了sessionId , 如修改请求body , 或在请求url上手动添加了sessionId参数

解决分布式session中的问题 , 主流有6种解决方案 : 

  1. session广播
  2. session增量广播
  3. session客户端
  4. 粘性session
  5. session持久化
  6. session集中缓存

1 . session复制/session广播

    简介 : 其中一台服务器的session有变动之后 , 将最新的session数据广播复制到其他服务器上
    场景 : 机器较少 , 网络流量较少
    优点 : 实现简单 , 配置较少 , 单机挂掉时不影响用户访问(其他服务器上仍保存最新的用户session)
    缺点 : 广播式复制到其他机器有一定延时 , 影响网络开销 , 仅能在相同的web服务器中复制 , 所有服务器都存储同样的数据 , 增加内存消耗

2 . session 增量广播

    简介 : 方式1的优化版 , 当其中一台服务器的session有变动之后 , 仅将变动的部分广播的其他服务器上
    场景 : 机器数量适中 , 网络流量较少
    优点 : 网络开销较少 , 单机当机不影响其他访问
    缺点 : 所有服务器仍然存储数据 , 内存消耗仍然存在

3 . session客户端

    简介 : 将session信息存储到客户端的cookie中 , 每次请求都携带客户端的session信息
    场景 : session数据量不大 , 服务对安全要求不高
    优点 : 不占用服务器存储 , 节省空间
    缺点 : 每次请求都携带session , 占用外网带宽 ; 数据存储在端上 , 并在网络中传输 , 容易泄露/被篡改;session数据的大小受cookie限制

4 . 粘性session

    简介 : 用户初始访问集群中的某台机器后 , 指定其后的所有请求都分发到这台机器上 , 如利用nginx的ip_hash算法 , 使得同一ip的请求都分发到同一台服务器上
    场景 : 机器数量适中 , 对稳定性要求不是非常苛刻 , 机器故障率低
    优点 : 实现简单 , 配置较少 , 没有额外的网络开销
    缺点 : 当前机器挂掉后 , 用户session丢失 , 造成单点故障 , 缺乏容错性

5 . session持久化-数据库

    简介 : 将用户的session存到数据库中 , 每次访问从数据库中获取session
    场景 : 机器数量适中 , 网络流量较少
    优点 : 实现简单 , 配置较少
    缺点 : 增加了数据库的IO开销

6 . session持久化-缓存

    简介 : 将session存到redis缓存中 , 每次访问从缓存中获取session
    场景 : 机器数量较多 , 网络环境复杂
    优点 : 可靠性好 , 扩展性好
    缺点 : 实现复杂 , 稳定性依赖于缓存 , 需要增加额外的缓存服务器

你可能感兴趣的:(Java,高级JAVA)