在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
走走停停又三年 閱讀(3663)
評論(2) 編輯 收藏 所屬分類:
Weblogic