在weblogic中,sesion persitence有如下几种方式:
memory
—Disables persistent session storage.
file
—Uses file-based persistence (See also
PersistentStoreDir
, above).
jdbc
—Uses a database to store persistent sessions. (see also
PersistentStorePool
, above).
replicated
—Same as
memory
, but session data is replicated across the clustered servers.
cookie—All session data is stored in a cookie in the user's browser.
replicated_if_clustered—If the Web application is deployed on a clustered server, the in-effect
PersistentStoreType
will be replicated. Otherwise,
memory
is the default.
本文讨论的重点是持久化导致的性能问题,故只讨论JDBC和File两种方式,其余的不做讨论,Session相关的Params,请参考如下链接,
http://e-docs.bea.com/wls/docs81/webapp/weblogic_xml.html#1038173
首先说一下File persistence, 要使http session被写入到指定f目录下的file中,需要在/WEB-INF/weblogic.xml做如下配置:
测试我们使用weblogic自带的mainWebApp, 该web app位于类似如下的位置
D:\beasys\wls816\weblogic81\samples\server\examples\build
测试前,按上面的写法修改weblogic.xml, 然后修改index.jsp, 去掉头部的如下内容:
<%@ page session="false" %>
并修改其内容如下:
1 <%@ page import="java.util.ArrayList" %>
2
3 <%
4 String url = "http://" + request.getServerName() + ":" + request.getServerPort();
5 session.setAttribute("key", "value");
6 ArrayList list = new ArrayList();
7 for(int loop = 0; loop < 100000; loop++)
8 {
9 list.add("test" + loop);
10 }
11 session.setAttribute("list", list);
12 %>
上面的代码中,我往每个session里插入12M左右的数据,结果跟客户说的一样,这种性能会死人的,如果做4个并发的话,差不多需要5分钟以上。就这性能,我反正是快崩溃了,做了一下thread dump
看了Thread dump, 发现居然很多线程在等同一lock,如上面的0x159a82a8,而这个lock的holder居然是FileSessionContext.java。看了一下代码,感觉这代码太太那啥了,
FileSessionContext.sync(HttpSession sess)
1 saveTo = getSessionPath(id);
2 synchronized (dirTreeLock) {
3 makeStorageDir(id);
4 os = new DataOutputStream(new FileOutputStream(saveTo));
5 WLObjectOutputStream oos = new WLObjectOutputStream(os);
6 oos.setReplacer(RemoteObjectReplacer.getReplacer());
7 oos.writeObject(data);
8 oos.flush();
9 os.writeLong(data.getLastAccessedTime());
10 oos.close();
11 os.close();
12 }
有了这样的代码,这么差的性能就不足为奇了。同样的代码还出现在loadSession()中。这些原本应该由FileSessionData(对应于每一个具体的Session)完成的工作,都交给了FileSessionContext去做。SessionContext是什么,顾名思义,Session的上下文,Session的管理者,同一个WebApp的所有Session都由它管理。原本是个管理者,这里却沦落为工兵。打个比方,老板手下50小兵,每个小兵每天要写100行代码,结果小兵都不干活,都交给老板去做了,老板一天要写5000行,而且必须串行完成,不带并行干活的。这样的老板谁干,不累死才怪。
开始别人说file persitence性能差,我不加思索的来了个结论:不差才怪,一个文件,只能串行写入,能有什么好的性能? 后来自己做测试的时候才发现,压根不是我想的那样。设计者的初衷应该是并行的,因为每个Session有个对应的file,而不是公用一个文件。就因为上面的代码段,一个并行的初衷被扼杀了,不知道R&D的同事怎么考虑的。
我自己试着改了该代码,将所有文件读写的工作交给了FileSessionData.java,
FileSessionData.java
1 /*package*/ void syncSession(FileSessionData data, File saveTo) {
2 if (!isValid()) return;
3
4 DataOutputStream os = null;
5 String id = data.id;
6 synchronized(this)
7 {
8 try {
9 os = new DataOutputStream(new FileOutputStream(saveTo));
10 WLObjectOutputStream oos = new WLObjectOutputStream(os);
11 oos.setReplacer(RemoteObjectReplacer.getReplacer());
12 oos.writeObject(data);
13 oos.flush();
14 os.writeLong(data.getLastAccessedTime());
15 oos.close();
16 os.close();
17 os = null;
18 if (verbose) HTTPSessionLogger.logPickledSession(id, saveTo.getAbsolutePath());
19 } catch (ThreadDeath td) {
20 throw td;
21 } catch (Throwable e) {
22 HTTPSessionLogger.logErrorSavingSessionData(e);
23 if (saveTo != null) saveTo.delete();
24 } finally {
25 if (os != null) {
26 try { os.close(); } catch (Exception ignore) {}
27 }
28 }
29 }
30 }
同样loadSession()也被挪到了FileSeesionData, FileSessionContext只调用FileSessionData的接口就可以了。虽让这样可以做到并行写入,但整体性能还是不如JDBC。同样是文件写入, DB毕竟是异步写入的。提交到内存,然后由DBWn和LGWn完成具体的写入工作,所以性能上要好很多。
这样的实现在JDBCSessionData中可以看到,JDBC相关的工作并没有交给JDBCSessionContext去完成。所以JDBC性能要比File要好很多,要使用JDBC store, 配置如下:
要使用JDBC persitence, 需要在SessionPool(jdbc connection pool)下创建wl_servlet_sessions,参考如下链接:
http://e-docs.bea.com/wls/docs81/webapp/sessions.html
好了,这里在提一下cache size的作用。CacheSize用于设定在使用jdbc或file persitence时,内存中cached的session数目。如果cache size为0,ServletRequest结束的时候,该session会被SessionContext从session reference pool中remove掉,这样该Session就成了内存垃圾, GC的时候会被回收掉。 下次请求进来的时候,Session会从persistence store中load出来。这样的话,应用性能会有问题。所以生产系统上建议设定一个cache size, 这样内存中可以cache一些session, 避免反复load seesion导致的新能问题。ServletRequest结束的时候,如果cache中还有空余空间(ArrayList),将该session置入,如果空间以满,则将最早的那个session给remove掉,而置入新进的session。在设定cache size的应用中,内存中包括两部分session,cache的session和当前open的session(正被引用的session,一般是ServletRequest还没有结束的session).。 注意:在控制台上看到的session数,不是表示当前内存中的session个数,而是persistence store(JDBC, File)中的session数, 即所有当前没有timeout的session。
posted on 2008-09-27 17:18
走走停停又三年 阅读(3650)
评论(2) 编辑 收藏 所属分类:
Weblogic