誰在創建session(4)-為什么要關注session的創建
看到有留言,對我如此“執著”的關注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世界中肯定還有很多很多類似的小水龍頭在悄悄地滴水,而主人們根本沒有看見。
posted on 2007-12-20 11:06 sky ao 閱讀(3891) 評論(9) 編輯 收藏 所屬分類: web