首页 > 编程知识 正文

javaredissession,redis跨机房多活

时间:2023-05-04 12:52:36 阅读:32000 作者:4775

专注于JavaWeb开发的2017-10-04123360393358 www.Sina.com /

用户要使用网站上的服务,基本上需要浏览器和Web服务之间的多次交互。 HTTP协议本身是无状态的,在用户的第一个访问请求结束后,后端服务器将无法知道是下一个访问还是不是上次访问的用户。 需要一种基于HTTP协议支持会话状态的机制。 该机制使Web服务器能够从多个单独的HTTP请求中了解哪些请求来自哪个会话。

Session和Cookie的作用是保持访问用户与后端服务器的交互状态。

理解饼干

Cookie角色通常是在用户通过HTTP协议访问服务器时,服务器向客户端浏览器返回几个Key/Value键值对,并对这些数据添加一些限制,从而满足条件

理解会话

cookie允许服务端程序跟踪每个客户端的访问,但每次客户端访问时都必须返回。 如果cookie很多,它会无形地增加客户端和服务端的数据传输量。 Session的出现是为了解决这个问题。

每次同一客户端与服务端交互时,并不每次都返回所有Cookie值,而是只返回客户端首次访问服务时生成的会话id(sessionid ),每个客户端都是唯一的。 因此,每个客户端都有唯一的ID。 客户端只要返回这个ID就可以了。 此ID通常是名称为JSESIONID的Cookie。 Web服务为每个会话分别存储不同会话的信息。 如果禁用了Cookie,则此会话id通常包含在URL的参数中。

总结

这是因为Cookie和Session都保持用户访问的连续状态。 保持这种状态是为了方便业务实现,同时简化服务端编程,提高访问性能。 但是,也存在安全问题、集群环境下的Session同步问题等问题

集群中发生的问题

当我们有多台APP应用程序服务器时,会出现会话共享问题。 当我们第一次访问网站时,负载平衡会将本地请求分配给Web服务器1。 Session是在Web服务器1上创建的,如果第二次访问时我们不处理,也不能保证会落到Web服务器1上。

解决群集会话共享问题

1 .会话sticky

确保负载平衡器能够根据每次请求的会话id传输请求,从而每次都落入同一服务器的方法称为Session Sticky方法。 下图:

有问题:

1 .这一台Web服务器停机或重新启动时,服务器上的会话数据将丢失,用户需要重新登录等。

2 .会话id是APP应用层的信息,负载平衡器要在同一Web服务器上存储同一会话的所有请求,需要解析APP应用层,该开销属于第4层交换机(LVS负载平衡器属于第4层)

3 .负载平衡器成为有状态节点,并将会话保存到特定Web服务的映射中。 与无状态节点相比,内存消耗更大,在灾难恢复方面更麻烦。

例如,Web服务器是酒店,对话数据是餐具。 如果保证每次吃饭都用自己的餐具,我就把餐具寄存在一家酒店,每次都去这家店吃饭。

2 .会话复制

还是吃饭的例子,在每个酒店放一套自己的餐具,就可以自己选择去哪个店吃饭。 这就是会话复制。 下图:

在此方案中,负载平衡器不再需要为同一Web服务确保同一会话的多次请求。 在Web服务器之间添加了会话数据同步,通过同步保证了不同Web服务器之间的Session数据的一致性。 典型的APP应用容器支持会话复制方法,与会话堆栈方法相比,会话复制方法对负载平衡器没有那么多要求。

有问题:

同步会话数据会导致网络带宽开销。 只要Session数据发生更改,就必须将数据同步到所有其他计算机。 机器越多,同步带来的网络带宽开销就越大。

2 .必须为每个web服务器保存所有会话数据。 如果整个群集的Session数据很多(很多人同时访问站点),则每台计算机存储Session数据的内容占用将变得严重。

该方案是在APP应用程序容器中完成Session复制以解决Session问题,而APP应用程序本身对此不感兴趣。 这个方案不适合集群设备数量多的场景。 如果只有几台机器的话,这个方案就可以了。

3 .会话数据集存储

集中存储会话数据,不同的Web服务从同一位置检索会话,如下图所示。

Session数据不会本地存储,而是存储在集中存储的位置,并更改Sessi

on也是发生在集中存储的地方。Web服务器使用Session从集中存储的地方读取。这样保证了不同Web服务器读取到的Session数据都是一样的。存储Session的具体方式可以是数据库、分布式存储系统等。这个方案解决了Session Replication方案中内存的问题,对于网络带宽也比Session Replication要好。

存在问题:

1. 读写Session数据引入了网络操作,这相对于本机的数据读取来说,问题就在于存在时延和不稳定性,不过我们的通讯基本都是发生在内网,问题不大。

2. 如果集中存储Session的机器或者集群有问题,就会影响到我们的应用。

相对于Session Replication,当Web服务器数量比较大、Session数比较多的时候,这个集中存储方案的优势是非常明显的。

4. Cookie Based

这个方案对于同一个会话的不同请求也是不限制具体处理机器的。它是通过Cookie来传递Session数据的,如下图:

从上图可以看出,我们的Session数据放到Cookie中,然后在Web服务器上从Cookie中生成对应的Session数据。这就好比我们每次都把自己的碗筷带在身上,这样去那家饭店就可以随意选择了。相对前面的集中存储方案,不会依赖外部的存储系统,也就不存在从外部系统获取、写入Session数据的网络时延、不稳定性了。

存在问题:

1. Cookie长度的限制。我们知道Cookie是有长度限制的,而这也会限制Session数据的长度。

2. 安全性。Session数据本来都是服务端数据,而这个方案是让这些服务端数据到了外部网络及客户端,因此存在安全性上的问题。我们可以对写入的Cookie的Session数据做加密,不过对于安全来说,物理上不能接触才是安全的。

3. 带宽消耗。指的是我们数据中心的整体外部带宽的消耗。

4. 性能影响。每次HTTP请求和响应都带有Session数据,对Web服务器来说,在同样的处理情况下,响应的结果输出越少,支持的并发请求就越多。生成Session数据也会影响处理速度。

这4个方案都是可用的方案,但是对于大型网站来说,Session Stick和Session数据集中存储是比较好的方案,这两个方案各有优劣,需要在具体的场景中做出选择和权衡。

以下我们对第三种方案Session数据集中存储进行简单的例子介绍

简单tomcat8+redis的session共享实现

1. 下载开源项目

https://github.com/jcoleman/tomcat-redis-session-manager

2. 创建maven项目

创建项目并把src/main/java/com/orangefunction/tomcat/redissessions/复制到项目

3. 支持tomcat8需修改代码

RedisSessionManager.java

 @@ -713,9 +713,9 @@ private void initializeSerializer() throws ClassNotFoundException, IllegalAccess   serializer = (Serializer) Class.forName(serializationStrategyClass).newInstance(); serializer = (Serializer) Class.forName(serializationStrategyClass).newInstance();     Loader loader =null; Loader loader =null; - +Context context =this.getContext(); - if (getContainer()!=null) { + if (context!=null) { - loader =getContainer().getLoader(); + loader =context.getLoader(); } }     ClassLoader classLoader =null; ClassLoader classLoader =null;

4. 打包部署

将实现包和依赖包commons-pool2-2.3.jar、jedis-2.7.2.jar、tomcat8_redis_session-0.0.1-SNAPSHOT.jar拷贝到tomcat的lib下

新增tomcat context.xml配置

<Valve className="com.demo.redis_session.RedisSessionHandlerValve" />

<Manager className="com.demo.redis_session.RedisSessionManager"

host="127.0.0.1"

port="6379"

database="0"

maxInactiveInterval="60" />

资料在项目的data目录下

5. 测试

在web项目启动tomcat并使用如下代码进行测试

publicvoiddoGet(HttpServletRequestrequest,HttpServletResponseresponse)throwsServletException,IOException{HttpSessionsession=request.getSession();/*//1.设置Sessionfor(inti=0;i<10;i++){session.setAttribute("name"+i,"session_data_"+i);}*///2.注释第一步,重启tomcat后看是否还可以读取到SessionStringstr="";for(inti=0;i<10;i++){str=str+session.getAttribute("name"+i)+"<br>";}response.setContentType("text/html");PrintWriterout=response.getWriter();out.println(str);out.flush();out.close();//访问:http://localhost:8080/tomcat8_redis_session_web/servlet/TestRedisSessionServlet}

参考网址:

redis + Tomcat 8 的session共享解决 【http://www.cnblogs.com/interdrp/p/4868740.html 】

Tomcat7+Redis存储Session【http://blog.csdn.net/caiwenfeng_for_23/article/details/45666831】

用Redis存储Tomcat集群的Session【http://blog.csdn.net/chszs/article/details/42610365 】

分布式集群系统下的高可用session解决方案【http://tendyming.iteye.com/blog/1815136 】

《大型网站系统与Java中间件实践》

《深入分析Java Web技术内幕》

code:

https://github.com/JeromeSuz/tomcat8_redis_session

https://github.com/JeromeSuz/tomcat8_redis_session_web

好了,今天的技术内容就分享给大家,码农不容易,小编给大家分享写博客也不容易,请多多支持,喜欢请关注头条号,每天都有功能和bug分享给大家一起学习进步,我们的目标是 ----软件攻城狮

码农不容易,码文章更不容易啊,喜欢小编多多支持请点击关注哦,小编会更加努力每天给大家分享技术文章。

版权声明:该文观点仅代表作者本人。处理文章:请发送邮件至 三1五14八八95#扣扣.com 举报,一经查实,本站将立刻删除。