看到有留言,對(duì)我如此“執(zhí)著”的關(guān)注session創(chuàng)建很好奇,解釋一下吧。
首先是關(guān)注性能,前面提到過session的使用是有代價(jià)的,需要在保存在服務(wù)器端內(nèi)容中,每次request.getSeesion()方法獲取session時(shí),實(shí)際是在服務(wù)器段的一個(gè)大的hasp結(jié)構(gòu)中以當(dāng)前的jsessionid為key,獲取對(duì)應(yīng)的value HttpSession對(duì)象,這個(gè)過程是需要消耗cpu的,當(dāng)然目前hash算法比較好,這里消耗不那么明顯。而一般的應(yīng)用,消耗的cpu遠(yuǎn)比這個(gè)小開銷大出2-3個(gè)數(shù)量級(jí),因此通常情況不敏感。如果這個(gè)session是我們需要使用的,那么付出這些內(nèi)存和cpu的代碼是完全值得的。但是,如果產(chǎn)生大量的沒有任何用處的"垃圾session",對(duì)大容量,大并發(fā),需要長期穩(wěn)定運(yùn)行的系統(tǒng)會(huì)帶來很無謂的負(fù)載。
注意,我們要討論是"垃圾session",即是在我們計(jì)劃外因?yàn)槟硞€(gè)原因創(chuàng)建,從不使用,完全浪費(fèi)的session。正常使用的session不在討論范圍內(nèi),雖然也有些比較極端的系統(tǒng)號(hào)稱不使用session來提高服務(wù)器性能,有些對(duì)性能比較關(guān)注的系統(tǒng)/框架則采用其他的方式來避免使用session,有興趣的可以google找資料看。
下面我們來進(jìn)行一個(gè)簡單的性能測試,模擬一下比較極端的情況,我在linux下啟動(dòng)resin,只跑兩個(gè)最簡單的jsp文件:
a.jsp不會(huì)自動(dòng)生成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基本相同,但是設(shè)置為<%@ page session="true" %>,這個(gè)將自動(dòng)增加
HttpSession session = request.getSesson(true)
語句,我們進(jìn)行最惡劣的假設(shè),每次請(qǐng)求都生成新的session,看看會(huì)是什么情況:
測試工具采用loadrunner,部署在我的筆記本上(dell d620機(jī)器,intel 雙核 2g內(nèi)存)。測試比較簡單,測試方法和過程忽略(loadrunner的使用也不復(fù)雜),只給出結(jié)果:
測試中兩個(gè)場景的運(yùn)行情況相同:100個(gè)線程并發(fā),每次只訪問一下a.jsp/b.jsp,運(yùn)行時(shí)間2分鐘。使用top命令在服務(wù)器段看resin的內(nèi)存消耗和cpu使用情況,這個(gè)只能大概估計(jì),不好準(zhǔn)確衡量。
補(bǔ)充:第一次測試時(shí)忘了設(shè)置resin的<session-max>參數(shù)了,后來寫了一個(gè)sessionLinstener做計(jì)數(shù)器,resin的默認(rèn)沒有配置session-max,這個(gè)時(shí)候resin取的值是默認(rèn)4096,計(jì)數(shù)器打印日志發(fā)現(xiàn)session總數(shù)達(dá)到4096后,就會(huì)remove掉已經(jīng)存在的session以保證不超過4096.下面的測試數(shù)據(jù)時(shí)將session-max設(shè)置為4096000后測試的結(jié)果
測試1:
a.jsp 不生成session
resin內(nèi)存消耗始終是在175-177之間,基本沒有變化。cpu基本穩(wěn)定在19%-22%。
測試2:
b.jsp 每次生成session
resin內(nèi)存消耗從181m逐步增加,到2分鐘測試結(jié)束時(shí)達(dá)到283m,大概增加了102M。cpu大體在25%-30%間。
下面可以總結(jié)了:
1. 垃圾session會(huì)占用內(nèi)存
上面只測試了2分鐘,考慮通常session的超時(shí)時(shí)間會(huì)是30分鐘,這意味著這些占據(jù)的內(nèi)存至少要到30分鐘之后resin才能判定超時(shí)從resin的session hash結(jié)構(gòu)出移除,之后再被jvm回收。
創(chuàng)建的session總數(shù)為202941,102M內(nèi)存/202941次請(qǐng)求=
527字節(jié)/session,這個(gè)數(shù)據(jù)比較粗糙,但是還是能大體反映問題。一個(gè)垃圾session大概要浪費(fèi)我們0.5k的內(nèi)存,時(shí)間長達(dá)30分鐘。
2. 垃圾session的調(diào)用消耗了cpu資源
HttpSession session = request.getSesson(true),每次都要new出新的HttpSession對(duì)象,然后resin還要給這個(gè)HttpSession算出一個(gè)jsessionid,再將jsessionid/session以key/value保存到hash結(jié)構(gòu)中。以后resin檢查session超時(shí)的線程每次檢查時(shí)都要查看每個(gè)垃圾session,看是否超時(shí)。
3. 垃圾session增加正常獲取session的開銷
前面提到垃圾session也是要保存hash結(jié)構(gòu)中,request.getSesson()每次都要用jsessionid在這個(gè)hash結(jié)構(gòu)中取一次數(shù)據(jù)。當(dāng)垃圾session大量充斥時(shí),獲取當(dāng)正常有用的session的時(shí)間也會(huì)增加,具體就要看這個(gè)hash結(jié)構(gòu)的算法如何了。
當(dāng)前上述的測試都是建立在最苛刻最惡劣的情況下,大多數(shù)情況我們的系統(tǒng)不會(huì)這么糟糕,也不是每個(gè)系統(tǒng)都對(duì)訪問量/性能有高要求。如果覺得可以浪費(fèi)的起,那浪費(fèi)好了,只是我這邊系統(tǒng)的情況不同,我們的產(chǎn)品對(duì)性能很敏感,能省就省點(diǎn)。
除考慮性能外, session的創(chuàng)建在我們新設(shè)計(jì)的系統(tǒng)中,是必須非常嚴(yán)格控制的.這個(gè)和我們目前的系統(tǒng)結(jié)構(gòu),包括部署/用戶身份認(rèn)證有關(guān).簡單的說我們的系統(tǒng)是基于apache + resin的多機(jī)分布, 各個(gè)功能模塊是作為不同的webapp發(fā)布的,session的生成和jsessionid的傳遞必須可控,因此我必須嚴(yán)格掌控系統(tǒng)中session的生成情況。
另外說一點(diǎn)個(gè)人意見,知不知道有這些session自動(dòng)創(chuàng)建的情況,和決定是否要在自己的代碼中嚴(yán)格控制session創(chuàng)建,不是同一個(gè)概念。完全可以在了解情況后,根據(jù)自己的實(shí)際需要和個(gè)人習(xí)慣去做決定,比如選擇無視。但是如果不知道呢?呵呵,很慚愧,在這次探索之前,我對(duì)jsp/webwork標(biāo)簽自動(dòng)生成session是沒有概念的,我們的原有系統(tǒng)是不使用HttpSession的(和當(dāng)時(shí)的分布式方案有關(guān)),但是現(xiàn)在看來,由于jsp/webwork標(biāo)簽的存在,其實(shí)每次都有session被創(chuàng)建,這些session也就成了我上面說的垃圾session: 在不需要?jiǎng)?chuàng)建時(shí)意外創(chuàng)建,從來不使用,除了浪費(fèi)資源外沒有其他存在價(jià)值。
整理一下留言中的內(nèi)容,感謝大家的關(guān)注:
疑問:
我覺得系統(tǒng)的瓶頸不會(huì)出在session生成上
,花時(shí)間在后臺(tái)緩存和sql優(yōu)化、架構(gòu)調(diào)整這些事情上來的實(shí)惠.
回答:
滴水的水龍頭要不要擰緊的問題?
沒有哪個(gè)家庭的財(cái)政會(huì)因?yàn)槟莻€(gè)滴水的水龍頭造成收支失衡以致破產(chǎn),那是否就意味著可以無視它的存在,只管專心掙錢,再每個(gè)月少吃一次大餐?后臺(tái)緩存和sql優(yōu)化、架構(gòu)調(diào)整,這些當(dāng)然是更重要的,但不意味著其他東西就可以完全忽略。我無意強(qiáng)調(diào)session的這些細(xì)節(jié)的高度,只是希望告訴大家,在某些角落里,有些我們沒有意識(shí)到的小水龍頭,在一滴一滴的浪費(fèi)資源。
后臺(tái)緩存和sql優(yōu)化、架構(gòu)調(diào)整,到處可以找到資料。可是我google了一圈,上述session的幾個(gè)問題根本沒有成文的全面一點(diǎn)的資料可以參考,我相信jsp世界中肯定還有很多很多類似的小水龍頭在悄悄地滴水,而主人們根本沒有看見。