看到有留言,对我如此“执着”的关注session创建很好奇,解释一下吧。
首先是关注性能,前面提到过session的使用是有代价的,需要在保存在服务器端内容中,每次request.getSeesion()方法获取 session时,实际是在服务器段的一个大的hasp结构中以当前的jsessionid为key,获取对应的value HttpSession对象,这个过程是需要消耗cpu的,当然目前hash算法比较好,这里消耗不那么明显。而一般的应用,消耗的cpu远比这个小开销大出2-3个数量级,因此通常情况不敏感。如果这个session是我们需要使用的,那么付出这些内存和cpu的代码是完全值得的。但是,如果产生大量的没有任何用处的"垃圾session",对大容量,大并发,需要长期稳定运行的系统会带来很无谓的负载。
注意,我们要讨论是"垃圾session",即是在我们计划外因为某个原因创建,从不使用,完全浪费的session。正常使用的session不在讨论范围内,虽然也有些比较极端的系统号称不使用session来提高服务器性能,有些对性能比较关注的系统/框架则采用其他的方式来避免使用 session,有兴趣的可以google找资料看。
下面我们来进行一个简单的性能测试,模拟一下比较极端的情况,我在linux下启动resin,只跑两个最简单的jsp文件:
a.jsp不会自动生成session:
<%@ page contentType="text/html; charset=UTF-8" %>
<%@ page session="false" %>
<!DOCTYPE html PUBLIC "-//W3C/m/DTD XHTML 1.0 Strict//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title></title>
</head>
<body>
<%=1%>
</body>
</html>
b.jsp基本相同,但是设置为<%@ page session="true" %>,这个将自动增加
HttpSession session = request.getSesson(true)
语句,我们进行最恶劣的假设,每次请求都生成新的session,看看会是什么情况:
测试工具采用loadrunner,部署在我的笔记本上(dell d620机器,intel 双核 2g内存)。测试比较简单,测试方法和过程忽略(loadrunner的使用也不复杂),只给出结果:
测试中两个场景的运行情况相同:100个线程并发,每次只访问一下a.jsp/b.jsp,运行时间2分钟。使用top命令在服务器段看resin的内存消耗和cpu使用情况,这个只能大概估计,不好准确衡量。
补充:第一次测试时忘了设置resin的<session-max>参数了,后来写了一个sessionLinstener做计数器, resin的默认没有配置session-max,这个时候resin取的值是默认4096,计数器打印日志发现session总数达到4096后,就会 remove掉已经存在的session以保证不超过4096.下面的测试数据时将session-max设置为4096000后测试的结果
测试1:
a.jsp 不生成session
resin内存消耗始终是在175-177之间,基本没有变化。cpu基本稳定在19%-22%。
测试2:
b.jsp 每次生成session
resin内存消耗从181m逐步增加,到2分钟测试结束时达到283m,大概增加了102M。cpu大体在25%-30%间。
下面可以总结了:
1. 垃圾session会占用内存
上面只测试了2分钟,考虑通常session的超时时间会是30分钟,这意味着这些占据的内存至少要到30分钟之后resin才能判定超时从resin的session hash结构出移除,之后再被jvm回收。
创建的session总数为202941,102M内存/202941次请求= 527字节/session,这个数据比较粗糙,但是还是能大体反映问题。一个垃圾session大概要浪费我们0.5k的内存,时间长达30分钟。
2. 垃圾session的调用消耗了cpu资源
HttpSession session = request.getSesson(true),每次都要new出新的HttpSession对象,然后resin还要给这个HttpSession算出一个jsessionid,再将jsessionid/session以key/value保存到hash结构中。以后resin检查session超时的线程每次检查时都要查看每个垃圾session,看是否超时。
3. 垃圾session增加正常获取session的开销
前面提到垃圾session也是要保存hash结构中,request.getSesson()每次都要用jsessionid在这个hash结构中取一次数据。当垃圾session大量充斥时,获取当正常有用的session的时间也会增加,具体就要看这个hash结构的算法如何了。
当前上述的测试都是建立在最苛刻最恶劣的情况下,大多数情况我们的系统不会这么糟糕,也不是每个系统都对访问量/性能有高要求。如果觉得可以浪费的起,那浪费好了,只是我这边系统的情况不同,我们的产品对性能很敏感,能省就省点。
除考虑性能外, session的创建在我们新设计的系统中,是必须非常严格控制的.这个和我们目前的系统结构,包括部署/用户身份认证有关.简单的说我们的系统是基于 apache + resin的多机分布, 各个功能模块是作为不同的webapp发布的,session的生成和jsessionid的传递必须可控,因此我必须严格掌控系统中session的生成情况。
另外说一点个人意见,知不知道有这些session自动创建的情况,和决定是否要在自己的代码中严格控制session创建,不是同一个概念。完全可以在了解情况后,根据自己的实际需要和个人习惯去做决定,比如选择无视。但是如果不知道呢?呵呵,很惭愧,在这次探索之前,我对jsp/webwork标签自动生成session是没有概念的,我们的原有系统是不使用HttpSession的(和当时的分布式方案有关),但是现在看来,由于 jsp/webwork标签的存在,其实每次都有session被创建,这些session也就成了我上面说的垃圾session: 在不需要创建时意外创建,从来不使用,除了浪费资源外没有其他存在价值。
整理一下留言中的内容,感谢大家的关注:
疑问:
我觉得系统的瓶颈不会出在session生成上 ,花时间在后台缓存和sql优化、架构调整这些事情上来的实惠.
回答:
滴水的水龙头要不要拧紧的问题?
没有哪个家庭的财政会因为那个滴水的水龙头造成收支失衡以致破产,那是否就意味着可以无视它的存在,只管专心挣钱,再每个月少吃一次大餐?后台缓存和 sql优化、架构调整,这些当然是更重要的,但不意味着其他东西就可以完全忽略。我无意强调session的这些细节的高度,只是希望告诉大家,在某些角落里,有些我们没有意识到的小水龙头,在一滴一滴的浪费资源。
后台缓存和sql优化、架构调整,到处可以找到资料。可是我google了一圈,上述session的几个问题根本没有成文的全面一点的资料可以参考,我相信jsp世界中肯定还有很多很多类似的小水龙头在悄悄地滴水,而主人们根本没有看见。
ps: 这个系列的文章最初发在blogjava,现在复制到javaeye(担心哪天某家blog不在了丢失文章),感觉这个话题很少看到有人谈起,我斗胆发到论坛上来看看,是否有人和我持有相同的看法。
分享到:
相关推荐
如果没有sessionId就新创建session,如果有sessionId,就去redis中查看是否有此id的记录,如果没有就新建session,如果有,还是新建session,并把redis中此session的相关数据赋值给新建的session,最后保存sessionId...
主要介绍了解决Spring session(redis存储方式)监听导致创建大量redisMessageListenerContailner-X线程问题,需要的朋友可以参考下
// 开始一个会话,如果要使用session程序最前面一定要加上这句 $_SESSION['user_id'] = ‘123′;//给一个session 变量赋值,如果该变量不存在即创建 echo $_SESSION['user_id'];//访问 session变量 $_SESSION = ...
jsp课程中内置对象session,jsp教程中的上课源代码
重写session机制,默认session是以临时文件形式存储在服务器,将session写入数据库,建表和注释写的都很清晰,已测试
这是一个用springMVC的项目 是一个监听器 用于监听session的创建、销毁、移除。会触发相应的事件处理
session.socket.io, 在 socket.io 中,表示/连接会话 session.socket.io ( SessionSockets ) 这个小模块简化了 socket.io 使用express或者连接中间件的http会话的使用。 它没有依赖项,可以使用任何与表示或者连接...
会话查找器 会话相关任务的命令。 安装 mkdir -p ~/.tmux/ git clone https://github.com/siadat/session-finder ~/.tmux/session-finder ~/.tmux/session-finder/install.bash ...启动并找到或创建一个
3、提前需要准备一个xshell的session模板文件,一般是自己在xshell中创建好的一个session ;还需要准备一个ip列表: IP列表的格式为 [aa] ip1 ip2 [bb] ip3 4、以上面的ip列表为例,生成的文件名为: ip1-aa.xsh ip...
session-tracking-jimmy199791020:session-tracking-jimmy199791020由GitHub Classroom创建
安装对于Rack应用程序,您可以使用以下方法在Ruby文件中创建Amazon DynamoDB表: require 'aws-sessionstore-dynamodb'Aws::SessionStore::DynamoDB::Table.create_table通过以下方式将会话存储作为Rack中间件运行:...
fastify-secure-session 基于 libsodium 的和 ,为 Fastify 创建一个安全的无状态 cookie 会话。使用预先生成的密钥首先生成一个密钥: ./node_modules/.bin/secure-session-gen-key > secret-key然后,注册插件如下...
WEB16_session&cookie。 案例一、记录用户的上次访问时间---cookie 案例二、实现验证码的校验----session。 1.服务器端向客户端发送一个Cookie 1)创建Cookie: Cookie cookie = new Cookie(String cookieName,...
一个Demo告诉你struts2如何创建 request response session application
会话在创建后立即存储到 Redis 中以供其他服务器使用。 会话直接从 Redis 请求加载(但在同一请求上下文期间对会话的后续请求将返回 ThreadLocal 缓存而不是多次命中 Redis。)为了尽可能防止冲突(和丢失的写入)...
旧版本对于仍在使用express-mysql-session 0.x 。 已对构造函数进行了向后兼容的更改,但如果将此模块的旧版本与最新文档一起使用,则可能会遇到麻烦。 您可以在找到旧版本的文档。会话表整理该模块创建一个数据库表...
创建菜单,菜单项和对话框-创建名为“ ADD”的菜单项,并在菜单项上单击事件后,将出现一个弹出窗口,要求用户输入姓名,电话号码和DOB。 弹出窗口必须包含一个Button,以将值添加到ListView中,并在添加弹出窗口后...
Session Lens通过Telescope.nvim扩展了,从而创建了一个具有模糊查找功能的简单会话切换器。 用法 您可以从望远镜呼叫切换台 :Telescope session - lens search_session 或者直接通过lua从插件的路径开始 : lua ...
创建索引的时候也会产生3,4级别的锁。 locked_mode为2,3,4不影响DML(insert,delete,update,select)操作, 但DDL(alter,drop等)操作会提示ora-00054错误。 有主外键约束时 update / delete ... ; 可能会产生...