关于Session timeout,是一个非常有效的节约服务器资源的方法,而且关于timeout的时间限制设定也非常有讲究,跟业务关系强相关。
如果服务器是只有一台,或者服务器集群中没有使用负载均衡器,那么session的管理是非常简单的。但是今天想描述的一个问题是,在服务器集群内使用session,并且有负载均衡器管理流量,这时候出现的奇异session timeout问题。
首先有几点前提知识需要阐述一下:
- 一个浏览器窗口是共享session的,也就是说,打开一个浏览器进程,不管你开多少子标签页,他们都是共享session的。
- 不同的浏览器进程之间是不共享session的,也就是session是跟浏览器进程相关,一个进程获得一个session。
- 不同的服务器之间只管理自己服务的客户端session,session信息存在服务器内存中,他们之间默认是不共享的。
现在问题是:在浏览器A子标签中访问站点首页导航,并点击进入子页面,建立浏览器与服务器的session(关于session的建立时间在本文最后有解释);然后在同一个浏览器中打开第二个、第三个、第四个子标签访问子页面,并进行相关操作,操作时间必须超过第一个子标签在服务器的session timeout时间;接下来继续打开第五个子标签访问站点首页,这时出现一进入站点就出现session timeout。
问题分析:出现这种情况的基本原因是客户端同一个浏览器之间的子标签session共享,而服务器之间默认是不共享session的,并且负载均衡器默认也不会根据session来分发流量,所以就会出现上述情况。
问题解析:当第一个子标签访问网站时,负载均衡器将流量随机导到服务器A上,因此该浏览器与服务器之间的session就建立了,而后该浏览器打开的子标签二,子标签三,子标签四的流量分别被导向其他的服务器,进过一段时间的操作,该浏览器与服务器A的session已经timeout了,而后第五个子标签访问网站时,负载均衡器又将流量转到了服务器A上,这是浏览器和服务器A的session已经timeout了,所以一进网站就会session timeout。
问题解决:核心思路,session共享、session同步,保证服务器集群之间的session一致。如果是非产品环境,可以把服务器的数量减少到1台,而如果是产品环境,就需要在负载均衡器中加session管理服务器,需要负载均衡器从session管理服务器中拿session与服务器的对应关系,然后在将流量导入到相关的服务器中,这样不会出现session不一致的问题。
关于session的一起其他知识:
- session在何时被创建:一个常见的误解是以为session在有客户端访问时就被创建,然而事实是直到某server端程序调用HttpServletRequest.getSession(true)这样的语句时才被创建,注意如果JSP没有显示的使用 <%@page session="false"%>关闭session,则JSP文件在编译成Servlet时将会自动加上这样一条语句HttpSession session = HttpServletRequest.getSession(true);这也是JSP中隐含的session对象的来历。由于session会消耗内存资源,因此,如果不打算使用session,应该在所有的JSP中关闭它。
- session何时被删除:session在下列情况下被删除a.程序调用HttpSession.invalidate();或b.距离上一次收到客户端发送的session id时间间隔超过了session的超时设置;或c.服务器进程被停止(非持久session)。
- 如何做到在浏览器关闭时删除session:严格的讲,做不到这一点。可以做一点努力的办法是在所有的客户端页面里使用javascript代码window.oncolose来监视浏览器的关闭动作,然后向服务器发送一个请求来删除session。但是对于浏览器崩溃或者强行杀死进程这些非常规手段仍然无能为力。
原文地址:https://www.cnblogs.com/petewell/p/11601759.html