session機制詳解以及session的相關應用

sessionweb開發里一個重要的概念,在大多數web應用里session都是被當做現成的東西,拿來就直接用,但是一些復雜的web應用里能拿來用的session已經滿足不了實際的需求,當碰到這樣的情況時候我們需要更加深入的理解session的機制,本文將梳理下session的相關知識,為設計可替代web容器自帶的session機制打個基礎。

?

1.1?session的概念

?

在計算機專業術語里:session是指一個終端用戶與交互系統進行通信的時間間隔,通常指從注冊入系統到注銷系統之間所經過的時間以及如果需要的話,可能還有一定操作空間。

?

具體到web應用里的session,大家都做過web開發,這里我就先不提出websession的定義,先和大伙講下和session相關的技術背景。

?

早期的web應用或者說早期的網站都是一種處理靜態資源的網站,功能主要是查看文檔,看看圖片,而現在的web應用和早期的差別已經很大,互聯網的網站更準確的定義應該是互聯網軟件即網站就是軟件,網站所代表的軟件和早期軟件的定義是不一樣的,早期的軟件都是在單機環境下運行,而互聯網的普及讓軟件和網絡技術融合在一起,這就要求網站所代表的軟件應該要有一個對事務處理的記憶功能,事務處理的記憶功能就是我們常說的要有狀態。而實現web應用技術的核心http協議是一個無狀態的協議,http這種設計也許是歷史遺留問題,也許無狀態的http是最簡單也是最有效的通訊方式,但是當網站成為軟件后,狀態的保持就是一個很重要的功能。

因此在web應用開發里就出現了保持http鏈接狀態的技術:一個是cookie技術,另一種是session技術。

?

cookie技術是客戶端的解決方案(當然隨著html5的出現,比cookie更為強勁和安全的技術出現了,但是鑒于html5的普及度不夠,就不做本文討論的內容了),Cookie就是由服務器發給客戶端的特殊信息,而這些信息以文本文件的方式存放在客戶端,然后客戶端每次向服務器發送請求的時候都會帶上這些特殊的信息。讓我們說得更具體一些:當用戶使用瀏覽器訪問一個支持Cookie的網站的時候,用戶會提供包括用戶名在內的個人信息并且提交至服務器;接著,服務器在向客戶端回傳相應的超文本的同時也會發回這些個人信息,當然這些信息并不是存放在HTTP響應體(Response?Body)中的,而是存放于HTTP響應頭(Response?Header);當客戶端瀏覽器接收到來自服務器的響應之后,瀏覽器會將這些信息存放在一個統一的位置,對于Windows操作系統而言,我們可以從:?[系統盤]:\Documents?and?Settings\[用戶名]\Cookies目錄中找到存儲的Cookie;自此,客戶端再向服務器發送請求的時候,都會把相應的Cookie再次發回至服務器。而這次,Cookie信息則存放在HTTP請求頭(Request?Header)了。有了Cookie這樣的技術實現,服務器在接收到來自客戶端瀏覽器的請求之后,就能夠通過分析存放于請求頭的Cookie得到客戶端特有的信息,從而動態生成與該客戶端相對應的內容。通常,我們可以從很多網站的登錄界面中看到“請記住我”這樣的選項,如果你勾選了它之后再登錄,那么在下一次訪問該網站的時候就不需要進行重復而繁瑣的登錄動作了,而這個功能就是通過Cookie實現的。

?

session技術則是服務端的解決方案,它是通過服務器來保持狀態的。由于Session這個詞匯包含的語義很多,因此需要在這里明確一下?Session的含義。首先,我們通常都會把Session翻譯成會話,因此我們可以把客戶端瀏覽器與服務器之間一系列交互的動作稱為一個?Session。從這個語義出發,我們會提到Session持續的時間,會提到在Session過程中進行了什么操作等等;其次,Session指的是服務器端為客戶端所開辟的存儲空間,在其中保存的信息就是用于保持狀態。從這個語義出發,我們則會提到往Session中存放什么內容,如何根據鍵值從?Session中獲取匹配的內容等。要使用Session,第一步當然是創建Session了。那么Session在何時創建呢?當然還是在服務器端程序運行的過程中創建的,不同語言實現的應用程序有不同創建Session的方法,而在Java中是通過調用HttpServletRequestgetSession方法(使用true作為參數)創建的。在創建了Session的同時,服務器會為該Session生成唯一的Session?id,而這個Session?id在隨后的請求中會被用來重新獲得已經創建的Session;在Session被創建之后,就可以調用Session相關的方法往Session中增加內容了,而這些內容只會保存在服務器中,發到客戶端的只有Session?id;當客戶端再次發送請求的時候,會將這個Session?id帶上,服務器接受到請求之后就會依據Session?id找到相應的Session,從而再次使用之。正式這樣一個過程,用戶的狀態也就得以保持了。

?

由此我們可以得出,session是解決http協議無狀態問題的服務端解決方案,它能讓客戶端和服務端一系列交互動作變成一個完整的事務,能使網站變成一個真正意義上的軟件。

?

1.2?cookiesession的關系

cookiesession的方案雖然分別屬于客戶端和服務端,但是服務端的session的實現對客戶端的cookie有依賴關系的,上面我講到服務端執行session機制時候會生成sessionid值,這個id值會發送給客戶端,客戶端每次請求都會把這個id值放到http請求的頭部發送給服務端,而這個id值在客戶端會保存下來,保存的容器就是cookie,因此當我們完全禁掉瀏覽器的cookie的時候,服務端的session也會不能正常使用(注意:有些資料說ASP解決這個問題,當瀏覽器的cookie被禁掉,服務端的session任然可以正常使用,ASP我沒試驗過,但是對于網絡上很多用phpjsp編寫的網站,我發現禁掉cookie,網站的session都無法正常的訪問)

?

1.3?session實現的原理

javaweb容器都實現了session機制,實現的邏輯思想都是一致的,但是具體方案可能會存在一定差異,這里我以tomcat容器為例,探討下session實現的機制。

下圖是tomcat源碼里session實現:

?

實現包的路徑是:org.apache.catalina.sessiontomcat對外提供session調用的接口不在這個實現包里,對外接口是在包javax.servlet.http下的HttpSession,而實現包里的StandardSessiontomcat提供的標準實現,當然對外tomcat不希望用戶直接操作StandardSession,而是提供了一個StandardSessionFacade類,tomcat容器里具體操作session的組件是servlet,而servlet操作session是通過StandardSessionFacade進行的,這樣就可以防止程序員直接操作StandardSession所帶來的安全問題。(StandardSessionFacade使用了設計模式里的Fa?ade(外觀)模式,外觀模式能讓不同邏輯層的組件進行解耦)

?

實現類里有Manager的類是用來管理session的工具類,它負責創建和銷毀session對象,其中ManagerBase是所有session管理工具類的基類,它是一個抽象類,所有具體實現session管理功能的類都要繼承這個類,該類有一個受保護的方法,該方法就是創建sessionId值的方法(tomcatsessionid值生成的機制是一個隨機數加時間加上jvmid值,jvmid值會根據服務器的硬件信息計算得來,因此不同jvmid值都是唯一的),StandardManager類是tomcat容器里默認的session管理實現類,它會將session的信息存儲到web容器所在服務器的內存里。PersistentManagerBase也是繼承ManagerBase類,它是所有持久化存儲session信息的基類,PersistentManager繼承了PersistentManagerBase,但是這個類只是多了一個靜態變量和一個getName方法,目前看來意義不大,對于持久化存儲sessiontomcat還提供了StoreBase的抽象類,它是所有持久化存儲session的基類,另外tomcat還給出了文件存儲FileStore和數據存儲JDBCStore兩個實現。

?

1.4?在實際運用中session所帶來的問題

由上面所描述的session實現機制,我們會發現,為了彌補http協議的無狀態的特點,服務端會占用一定的內存和cpu用來存儲和處理session計算的開銷,這也就是tomcat這個的web容器的并發連接那么低(tomcat官方文檔里默認的連接數是200)原因之一。因此很多java語言編寫的網站,在生產環境里web容器之前會加一個靜態資源服務器,例如:apache服務器或nginx服務器,靜態資源服務器沒有解決http無狀態問題的功能,因此部署靜態資源的服務器也就不會讓出內存或cpu計算資源專門去處理像session這樣的功能,這些內存和cpu資源可以更有效的處理每個http請求,因此靜態資源服務器的并發連接數更高,所以我們可以讓那些沒有狀態保持要求的請求直接在靜態服務器里處理,而要進行狀態保持的請求則在java的web容器里進行處理,這樣能更好的提升網站的效率。

?

當下的互聯網網站為了提高網站安全性和并發量,服務端的部署的服務器的數量往往是大于或等于兩臺,多臺服務器對外提供的服務是等價的,但是不同的服務器上面肯定會有不同的web容器,由上面的講述我們知道session的實現機制都是web容器里內部機制,這就導致一個web容器里所生成的sessionid值是不同的,因此當一個請求到了A服務器,瀏覽器得到響應后,客戶端存下的是A服務器上所生成的sessionid,當在另一個請求分發到了B服務器,B服務器上的web容器是不能識別這個sessionid值,更不會有這個sessionID所對應記錄下來的信息,這個時候就需要兩個不同web容器之間進行session的同步。Tomcat容器有一個官方的解決方案就是使用apache+tomcat+mod_jk方案,當一個web容器里session的信息發生變化后,該web容器會向另一個web容器進行廣播,另一個web收到廣播后將session信息同步到自己的容器里,這個過程是十分消耗系統資源,當訪問量增加會嚴重影響到網站的效率和穩定性。

?

我現在所做的網站里有一個解決方案,當用戶請求網站的時候會先將請求發送給硬件的負載均衡設備,該設備可以截獲客戶端發送過來的sessionid值,然后我們根據這個id值找到產生這個session的服務器,將請求直接發送給這臺服務器。這種解決方案看起來解決了session共享問題,其實結果是將集群系統最終變回了單點系統,如果處理請求的web容器掛掉了,那么用戶的相關會話操作也就廢掉了。此外,這種做法也干擾了負載均衡服務器的負載均衡的計算,讓請求的分發并不是公平的。

?

  一般大型互聯公司的網站都是有一個個獨立的頻道所組成的,例如我們常用的百度,會有百度搜索,百度音樂,百度百科等等,我相信他們不會把這些不同頻道都給一個開發團隊完成,應該每個頻道都是一個獨立開發團隊,因為每個頻道的應用的都是獨立的web應用,那么就存在一個跨站點的session同步的問題,跨站點的登錄可以使用單點登錄的(SSO)的解決方案,但是不管什么解決方案,跨站點的session共享任然是逃避不了的問題。

?

1.5?解決session相關問題的技術方案

由上所述,session一共有兩個問題需要解決:

1)?session的存儲應該獨立于web容器,也要獨立于部署web容器的服務器;

2)如何進行高效的session同步。

在講到解決這些問題之前,我們首先要考慮下session如何存儲才是高效,是存在內存、文件還是數據庫了?文件和數據庫的存儲方式都是將session的數據固化到硬盤上,操作硬盤的方式就是IOIO操作的效率是遠遠低于操作內存的數據,因此文件和數據庫存儲方式是不可取的,所以將session數據存儲到內存是最佳的選擇。因此最好的解決方案就是使用分布式緩存技術,例如:memcachedredis,將session信息的存儲獨立出來也是解決session同步問題的方法。

Tomcatsession同步也有使用memcache的解決方案,大家可以參加下面的文章:

?

  http://blog.sina.com.cn/s/blog_5376c71901017bqx.html

但是該方案只是解決了同步問題,session機制任然和web容器緊耦合,我們需要一個高效、可擴展的解決方案,那么我們就應該不是簡單的把session獨立出來存儲而是設計一個完全獨立的session機制,它既能給每個web應用提供session的功能又可以實現session同步,下面是一篇用zookeeper實現的分布式session方案:

http://www.open-open.com/lib/view/open1378556537303.html

?

好了寫完了,今天只是簡單剖析下session機制,以后有機會我拿出一套最好的獨立session設計機制方案來的。

轉載于:https://www.cnblogs.com/kabi/p/6703361.html

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/252910.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/252910.shtml
英文地址,請注明出處:http://en.pswp.cn/news/252910.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

(轉)Shell中獲取字符串長度的七種方法

Shell中獲取字符串長度的七種方法 原文:http://blog.csdn.net/jerry_1126/article/details/51835119 求字符串操作在shell腳本中很常用,下面歸納、匯總了求字符串的幾種可能方法: 【方法一】:利用${#str}來獲取字符串的長度 【方法二】:利用awk的length方…

linux下用core和gdb查詢出現段錯誤的地方

有些時候我們在一段C代碼的時候,由于對一個非法內存進行了操作,在程序運行的過程中,出現了"段錯誤"。呵呵,這種問題我想很多人會經常遇到。遇到這種問題是非常無語的,只是提示了"段錯誤"&#xff…

第一篇-Html標簽中head標簽,body標簽中input系列,textarea和select標簽

第十四周課程(1-12章節) HTML 裸體 CSS 穿華麗衣服 Javascript 動起來 一 HTML (20個標簽) 1.我們的瀏覽器是socket客戶端 2.一套規則,瀏覽器認識的規則 3.開發者: 學習html規則 開發后臺程序&#xff1a…

opencv3.2.0 Cmake 3.8.0 + tdm-gcc-5.1.0-3

實測 tdm-gcc-5.1.0-3 tdm32-1 32位版本無法正確編譯Opencv 3.2.0 會遇到諸多編譯問題 解決辦法 使用tdm-gcc-5.1.0-2 tdm64-1 64位版本轉載于:https://www.cnblogs.com/fundou/p/6710209.html

什么是商品屬性

一、什么是商品屬性: Definition of Product Attributes A product attribute is a characteristic that defines a particular product and will affect a consumers purchase decision. Product attributes can be tangible (or physical in nature) or intangibl…

linux用戶管理(1)----創建用戶(adduser和useradd)和刪除用戶(userdel)

arm linux的系統用戶管理: 1、刪除root用戶:deluser root2、刪除tt用戶:deluser tt3、建立root用戶:adduser root4、修改用戶密碼:登錄相應的用戶后,用passwd來修改密碼4、linux用戶和密碼的管理(ftp&#…

前端性能優化之圖像優化原理

前端性能優化中,圖像的優化是非常重要的一環,為什么要說圖像的優化呢,而不是我們常見的圖片優化?因為這里的圖像包括矢量圖和位圖,我們常說的圖片優化是指位圖的優化。這篇文章轉載至奇舞周刊,大佬總結的非…

Lua開發學習4-普通循環和迭代器循環

說句實話,每當看到Lua代碼,我都感覺是半個SQL代碼,寫起來還是感覺有點恐怖。 while循環: 與C#的while循環類似,沒有什么好說的; --------Lua的while循環 while(condition)dostatementsend For循環 exp1為起…

什么是js的嚴格模式

設立嚴格模式的原因: - 消除Javascript語法的一些不合理、不嚴謹之處,減少一些怪異行為; - 消除代碼運行的一些不安全之處,保證代碼運行的安全; - 提高編譯器效率,增加運行速度; - 為未來新版本的Javascrip…

Linux驅動設計ioctl函數的cmd參數不能為2

Linux驅動程序設計的時候偶然發現的ioctl()函數的cmd參數不能為2,如果為2,ioctl()函數返回-1,網上說就是這樣的,正常,不知道為什么,stack overflow上有一個外國學友的建議: “In general, you want to comp…

代碼解說Android Scroller、VelocityTracker

在編寫自己定義滑動控件時經常會用到Android觸摸機制和Scroller及VelocityTracker。Android Touch系統簡單介紹(二):實例具體解釋onInterceptTouchEvent與onTouchEvent的調用過程對Android觸摸機制須要用到的函數進行了具體的解釋。本文主要介紹兩個重要…

Effective_STL 學習筆記(四十四) 盡量使用成員函數代替同名的算法

有些容器擁有和 STL 算法同名的成員函數。 關聯容器提供了 count、find、lower_bound、upper_bound 和 euqal_range list 提供了 remove、remove_if、unique、merge 和 reverse 大多數時候應該用成員函數代替手寫算法,這樣做的兩個理由: 比起算法&#x…

(NFS移植到arm上)編譯portmap和nfs-utils

為了在播放機上實現NFS服務器的功能,我們已經在uClibc中打開了完整RPC支持,并且在新編譯的內核中打開了NFS服務器支持。此外還有兩個軟件包也是提供NFS服務所必需的:portmap和nfs-utils。portmap為RPC程序提供端口映射服務,nfs-ut…

HTML5上傳預覽

http://cobain-li.iteye.com/blog/2296538轉載于:https://www.cnblogs.com/winyh/p/7850049.html

支付寶支付

1 申請商戶平臺 2 申請開放平臺 3 申請APP支付 4 創建應用 (名稱,logo) 5 生成RSA秘鑰(公鑰,私鑰) 6 在應用中配置公鑰 7 配置其他內容,包括iOS bundle ID。配置安卓包名,和簽名。 獲取appid,公…

HttpRequest Java原生代碼封裝

HttpRequest Java原生代碼封裝 get提交 post提交 name1value1&name2value2 的形式 json形式兩種形式 package com.beisun.mbp.mbp.controller;import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.io.PrintWrit…

Linux 系統目錄

/ 根目錄 /bin 存放必要的命令 /boot 存放內核以及啟動所需的文件等 /dev 存放設備文件 /etc 存放系統的配置文件 /home 用戶文件的主目錄,用戶數據存放在其主目錄中 /lib 存放必要的運行庫 /mnt 存放臨時的映射文件系統,我們常把軟驅和光驅掛裝在這里的…

linux多線程學習設置線程調度權限

pthread_setschedparam 設置線程的權限 int pthread_setschedparam(pthread_t target_thread, int policy, const struct sched_param *param) 參數 1. target_thread是使用pthread_create所獲得的線程ID。   2.線程的調度有三種策略:SCHED_OTHER、…

不可錯過的CMS學習筆記

引子 帶著問題去學習一個東西,才會有目標感,我先把一直以來自己對CMS的一些疑惑羅列了下,希望這篇學習筆記能解決掉這些疑惑,希望也能對你有所幫助。 CMS出現的初衷、背景和目的? CMS的適用場景? CMS的tr…

團隊合作及個人成長

通過前一章的學習,我了解到了關于建模的很多初步的知識,但是這和成為一名軟件工程師是遠遠不夠的,完成一個程序通常都是一個團隊,而這個團隊重要的肯定是需要一些流程,這樣才能讓程序有條不紊的運行著。在這么一個團隊…