先来复习三个基础问题 :
一个常见的错误是在客户端请求到达的时候就被创建 , 然而实际上是直到某服务端程序(如servlet)调用HttpServletRequest.getSession(true)这样的语句时才会被创建 .
如果在该语句之前有个拦截器拦截了该请求 , 则此时就不会创建session .
答案是sessionId一致 , session对象不一致
原因如下 :
解决分布式session中的问题 , 主流有6种解决方案 :
简介 : 其中一台服务器的session有变动之后 , 将最新的session数据广播复制到其他服务器上
场景 : 机器较少 , 网络流量较少
优点 : 实现简单 , 配置较少 , 单机挂掉时不影响用户访问(其他服务器上仍保存最新的用户session)
缺点 : 广播式复制到其他机器有一定延时 , 影响网络开销 , 仅能在相同的web服务器中复制 , 所有服务器都存储同样的数据 , 增加内存消耗
简介 : 方式1的优化版 , 当其中一台服务器的session有变动之后 , 仅将变动的部分广播的其他服务器上
场景 : 机器数量适中 , 网络流量较少
优点 : 网络开销较少 , 单机当机不影响其他访问
缺点 : 所有服务器仍然存储数据 , 内存消耗仍然存在
简介 : 将session信息存储到客户端的cookie中 , 每次请求都携带客户端的session信息
场景 : session数据量不大 , 服务对安全要求不高
优点 : 不占用服务器存储 , 节省空间
缺点 : 每次请求都携带session , 占用外网带宽 ; 数据存储在端上 , 并在网络中传输 , 容易泄露/被篡改;session数据的大小受cookie限制
简介 : 用户初始访问集群中的某台机器后 , 指定其后的所有请求都分发到这台机器上 , 如利用nginx的ip_hash算法 , 使得同一ip的请求都分发到同一台服务器上
场景 : 机器数量适中 , 对稳定性要求不是非常苛刻 , 机器故障率低
优点 : 实现简单 , 配置较少 , 没有额外的网络开销
缺点 : 当前机器挂掉后 , 用户session丢失 , 造成单点故障 , 缺乏容错性
简介 : 将用户的session存到数据库中 , 每次访问从数据库中获取session
场景 : 机器数量适中 , 网络流量较少
优点 : 实现简单 , 配置较少
缺点 : 增加了数据库的IO开销
简介 : 将session存到redis缓存中 , 每次访问从缓存中获取session
场景 : 机器数量较多 , 网络环境复杂
优点 : 可靠性好 , 扩展性好
缺点 : 实现复杂 , 稳定性依赖于缓存 , 需要增加额外的缓存服务器