目录
最靠谱的分布式Session解决方案(基于令牌(Token))
什么是Session
session 是一种服务端的会话机制。(被称为域对象)作为范围是一次会话的范围。
服务器为每个用户创建一个会话,存储用户的相关信息,以便多次请求能够定位到同一个上下文。这样,当用户在应用程序的 Web 页之间跳转时,存储在 Session 对象中的变量将不会丢失,而是在整个用户会话中一直存在下去。当用户请求来自应用程序的 Web 页时,如果该用户还没有会话,则 Web 服务器将自动创建一个 Session 对象。当会话过期或被放弃后,服务器将终止该会话。
Web开发中,web-server可以自动为同一个浏览器的访问用户自动创建session,提供数据存储功能。最常见的,会把用户的登录信息、用户信息存储在session中,以保持登录状态。
那么Session为什么会不一致呢?
在基于请求与响应的HTTP
通讯中,当第一次请求来时,服务器端会接受到客户端请求,会创建一个session
,使用响应头返回sessionid
给客户端。浏览器获取到sessionid
后会保存到本地cookie
中。
当第二次请求来时,客户端会读取本地的sessionid
,存放在请求头中,服务端在请求头中获取对象的sessionid
在本地session
内存中查询。
但是session
属于会话机制,当当先会话结束时,session
就会被销毁,并且web
程序会为每一次不同的会话创建不同的session
,所以在分布式场景下,即使是调用同一个方法执行同样的代码,但是他们的服务器不同,自然web
程序不同,整个上下文对象也不同,理所当然session
也是不同的。
Session一致性解决方案
方案一:客户端存储
直接将信息存储在cookie中
cookie是存储在客户端上的一小段数据,客户端通过http协议和服务器进行cookie交互,通常用来存储一些不敏感信息
优点:
- 不需要服务器存储session,节省服务端资源。
缺点:
- 都是缺点,这只是一种解决问题的思路。
- 数据存储在客户端,存在安全隐患,容易泄露。
- cookie存储大小为4K,不能存储大量信息、类型存在限制
- 数据存储在cookie中,如果一次请求cookie过大,会给网络增加更大的开销
方案二:session复制(Tomcat自带该功能)
session复制是小型企业应用使用较多的一种服务器集群session管理机制,在真正的开发使用的并不是很多,通过对web服务器(例如Tomcat)进行搭建集群。
优点:
- 服务器之间的session信息都是同步的,任何一台服务器宕机的时候不会影响另外服务器中session的状态,配置相对简单
- Tomcat内部已经支持分布式架构开发管理机制,可以对tomcat修改配置来支持session复制,在集群中的几台服务器之间同步session对象,使每台服务器上都保存了所有用户的session信息,这样任何一台本机宕机都不会导致session数据的丢失,而服务器使用session时,也只需要在本机获取即可
缺点:
- session同步的原理是在同一个局域网里面通过发送广播来异步同步session的,一旦服务器多了,并发上来了,session需要同步的数据量就大了,需要将其他服务器上的session全部同步到本服务器上,会带来一定的网路开销,在用户量特别大的时候,会出现内存不足的情况
步骤:
1.tomcat中server.xml直接配置
<!-- 第1步:修改server.xml,在Host节点下添加如下Cluster节点 -->
<!-- 用于Session复制 -->
<Cluster className="org.apache.catalina.ha.tcp.SimpleTcpCluster" channelSendOptions="8">
<Manager className="org.apache.catalina.ha.session.DeltaManager" expireSessionsOnShutdown="false" notifyListenersOnReplication="true" />
<Channel className="org.apache.catalina.tribes.group.GroupChannel">
<Membership className="org.apache.catalina.tribes.membership.McastService" address="228.0.0.4"
port="45564" frequency="500" dropTime="3000" />
<!-- 这里如果启动出现异常,则可以尝试把address中的"auto"改为"localhost" -->
<Receiver className="org.apache.catalina.tribes.transport.nio.NioReceiver" address="auto" port="4000"
autoBind="100" selectorTimeout="5000" maxThreads="6" />
<Sender className="org.apache.catalina.tribes.transport.ReplicationTransmitter">
<Transport className="org.apache.catalina.tribes.transport.nio.PooledParallelSender" />
</Sender>
<Interceptor className="org.apache.catalina.tribes.group.interceptors.TcpFailureDetector" />
<Interceptor className="org.apache.catalina.tribes.group.interceptors.MessageDispatchInterceptor" />
</Channel>
<Valve className="org.apache.catalina.ha.tcp.ReplicationValve" filter="" />
<Valve className="org.apache.catalina.ha.session.JvmRouteBinderValve" />
<Deployer className="org.apache.catalina.ha.deploy.FarmWarDeployer" tempDir="/tmp/war-temp/"
deployDir="/tmp/war-deploy/" watchDir="/tmp/war-listen/" watchEnabled="false" />
<ClusterListener className="org.apache.catalina.ha.session.ClusterSessionListener" />
</Cluster>
2 修改web.xml
web.xml中需加入<distributable/> 以支持集群。
方案三:session绑定:
Nginx介绍:
Nginx是一款自由的、开源的、高性能的http服务器和反向代理服务器
Nginx能做什么:
反向代理、负载均衡、http服务器(动静代理)、正向代理
如何使用nginx进行session绑定
我们利用nginx的反向代理和负载均衡,之前是客户端会被分配到其中一台服务器进行处理,具体分配到哪台服务器进行处理还得看服务器的负载均衡算法(轮询、随机、ip-hash、权重等),但是我们可以基于nginx的ip-hash策略,可以对客户端和服务器进行绑定,同一个客户端就只能访问该服务器,无论客户端发送多少次请求都被同一个服务器处理
在nginx安装目录下的conf目录中的nginx.conf文件
upstream aaa {
Ip_hash;
server 39.105.59.4:8080;
Server 39.105.59.4:8081;
}
server {
listen 80;
server_name www.wanyingjing.cn;
#root /usr/local/nginx/html;
#index index.html index.htm;
location / {
proxy_pass http:39.105.59.4;
index index.html index.htm;
}
}
缺点:
- 容易造成单点故障,如果有一台服务器宕机,那么该台服务器上的session信息将会丢失
- 前端不能有负载均衡,如果有,session绑定将会出问题
- 失去了
Nginx
负载均衡的初心
优点:
- 配置简单
方案四:后端统一集中存储
思路:将session存储在web-server后端的存储层,数据库或者缓存
优点:
- 没有安全隐患
- 可以水平扩展,数据库/缓存水平切分即可
- web-server重启或者扩容都不会有session丢失
不足:增加了一次网络调用,并且需要修改应用代码
对于db存储还是cache,个人推荐后者:session读取的频率会很高,数据库压力会比较大。如果有session高可用需求,cache可以做高可用,但大部分情况下session可以丢失,一般也不需要考虑高可用。
方案五:基于redis存储session方案(推荐)
优点:
- 这是企业中使用的最多的一种方式
- spring为我们封装好了spring-session,直接引入依赖即可
- 数据保存在redis中,无缝接入,不存在任何安全隐患
- redis自身可做集群,搭建主从,同时方便管理
缺点:
- 多了一次网络调用,web容器需要向redis访问
最靠谱的分布式Session解决方案(基于令牌(Token))
基于令牌(Token)方式实现Session解决方案,因为Session本身就是分布式共享连接。
将生成的Token 存入到Redis中。