一、什麼是session?什麼又是cookie?他倆有啥聯繫和區別?java
二、爲何要在多臺服務器間進行session的共享同步?nginx
三、以及有哪些方法來實現這個同步?web
你們快搬板凳,老王開始扯淡咯~算法
1、session和cookie的纏綿與悱惻數據庫
相信有盆友跟老王同樣,曾經爲session和cookie糾結過,或者如今正在爲他們糾結。session在英文裏的意思是會議,而cookie則是餅乾。你說這個會議和餅乾怎麼就關聯上了呢?(開會的時候能夠吃餅乾)瀏覽器
咱們先來看看百度百科的解釋吧:tomcat
A、cookie:安全
Cookie, 有時也用其複數形式Cookies,指某些網站爲了辨別用戶身份、進行session跟蹤而儲存在用戶本地終端上的數據(一般通過加密)。Cookie是 由服務器端生成,發送給User-Agent(通常是瀏覽器),瀏覽器會將Cookie的key/value保存到某個目錄下的文本文件內,下次請求同一 網站時就發送該Cookie給服務器(前提是瀏覽器設置爲啓用cookie)性能優化
B、session:服務器
在計算機中,尤爲是在網絡 應用中,稱爲「會話控制」。Session對象存儲特定用戶會話所需的屬性及配置信息。這樣,當用戶在應用程序的 Web 頁之間跳轉時,存儲在 Session 對象中的變量將不會丟失,而是在整個用戶會話中一直存在下去。當用戶請求來自應用程序的 Web 頁時,若是該用戶尚未會話,則 Web 服務器將自動建立一個 Session 對象。當會話過時或被放棄後,服務器將終止該會話。
你們看懂了嘛?我打包票,確定仍是有盆友沒看懂。老王本身是這麼來理解他們的:
A、cookie:
瀏覽器請求服務器,服務器爲了區別不一樣的用戶請求,就須要給他們打上標籤,好比:發放一個訪問令牌(access_token)給客戶端。發放的過程是經過在HTTP請求返回的時候,經過設置HTTP的header:Set-Cookie來實現的。
以上就是我請求百度,他給我發放的cookie們。每個Set-Cookie裏通常會含有設置的key=value、過時時間,以及域和路徑。
當瀏覽器接收到這樣的返回頭之後,就把他穩妥當當的存起來,之後每次發送請求的時候,就會把他帶上(具體還要看過時時間、做用的域和路徑)。
這個cookie看起來像個什麼東東呢?像不像有關部門給咱們發放的身份證?你去有關部門申請,他就把你的ID、性別、年齡等等信息給你打到一張叫作身份證的東東上,而後發給你。之後你每次去辦點啥關鍵的事情,就須要帶上這些cookie們。
一 般服務器會在瀏覽器裏種上一些相似於訪問令牌(access_token)、用戶ID(user_id)等等的cookie,這樣你一去訪問對應的網站, 他就把你認出來了。特別,像java的服務器,還會種一些相似jsession_id的cookie,服務器採用必定的算法(好比隨機算法),生成一個一 定長度(好比10字節)的字符串" angOwberup ",而後發放給瀏覽器: Set-Cookie:jssesion_id= angOwberup,當瀏覽器收到這個cookie之後,就跟拿到寶同樣,好好的把這個key和value收藏了起來,之後每次去服務器請求都帶上。
B、session:
與 此同時,服務器把這個字符串"angOwberup"做爲key,把一個叫作User的類的一個實例user,設置好id、nickname等等信息以 後,放入了一個相似於map的容器裏:map.put("angOwberup", user)。當瀏覽器請求來的時候,服務器就會getCookie("jsession_id"),把這個種在瀏覽器裏的字符串取出來,而後用這個字符串 去map裏找找,看看有沒有對應的User對象:map.get(sessionId)。若是取到了,說明就找到了這個用戶的id、nickname等等 信息,直接就能夠在網頁上顯示:「老王你好,歡迎回來!」。若是沒有找到,有可能就跳到登陸頁面,讓用戶作登陸。
咱們把用戶在必定時間內訪問某個網站時,請求不一樣頁面的過程叫作一個會話,也就是session。在同一個session裏,咱們能夠記錄用戶訪問的狀態和信息。這樣,那個相似於map的容器就是session管理器。
打 個形象的比喻,若是cookie是身份證,那session就是你的檔案。你的全部信息都存放在檔案裏,有關部門(server)管理着你的檔案。當你要 辦重要的事情時,就須要拿着身份證去有關部門提取檔案,有關部門查閱檔案後,再看要不要給你辦事兒。若是你作了壞事,他們就會往你的檔案 (session)裏寫一些很差的東西;固然,若是你得了什麼獎,也會往裏面放。
這下,是否是有點清楚cookie和session有什麼聯繫和區別了呢?再簡要的總結一下:
A、cookie就是服務器發放給客戶端的一些標識,讓客戶端記住每次請求的時候帶上,以區分不一樣的用戶;
B、session是服務器存放在本身那裏的用戶相關的數據,用每次用戶帶來的cookie去提取出來,恢復一個以前訪問的歷史或者相關環境。
好了,有了上面的內容,接下來,咱們就須要討論一下那個相似於map的session管理器了。
2、session的管理
上面說了,服務器用了一個相似於map的容器來管理session。那具體來看,這個map是怎麼樣來實現的呢?
不 同的服務器、不一樣的語言框架都有不一樣的實現。好比java的服務器,有的是用文件方式來存儲的、有的是用內存cache的方式來存儲的。老王還據說有的語 言的服務器將數據作加密,而後設置成cookie,存到了客戶端(瀏覽器)。那這些實現方式都有哪些優缺點呢?咱們逐個來分析。(固然,有可能還有其餘的 實現方法,老王可能不瞭解,不過大致思路類似,若有遺漏請指正)
A、文件方式:這種方式,將文件做爲一個map,當新增一個數據的時候,就在文件中增長相似這樣的一條數據:
angOwberup =>
data={"user":{"id":1,"nickname":"老王"}};
expiry="2016-10-0100:00:00"
(固然,具體實現的時候有多是用的二進制方式,而不是字符串)
這 種方式的好處,就是可以存儲大量的用戶session,使得這個session有效期能夠比較長(好比:三個月用戶不用登陸)。不過這個方式也有對應的問 題,就是文件操做比較麻煩。好比,有一個用戶的session過時了,須要刪掉這條記錄,那這個文件就須要挪動或重寫。
B、cache方 式:有好多web端的邏輯服務器都採用這種方式。這種方式好處很是明顯,就是實現起來很是簡單。將全部數據放入到內存cache中。若是有失效,直接內存 刪除就能夠了。不過帶來的問題也很明顯,當服務器重啓之後,全部session都丟失了。或者當有大量用戶登陸(也有多是遭受攻擊),就會很快讓 cache被充滿,而後大量session被LRU算法淘汰,形成session的大量失效,使得用戶須要反覆登陸等操做。
C、 cookie方式:這種方式是最偷懶的方式。就是我服務器任何數據都不存,我把大家全部的客戶端當作個人存儲器,我就須要作一個加密和解密操做。固然這種 方式最大的好處就是實現極其簡單(還有其餘的好處,稍後再說),不過問題也是很明顯的,就是客戶端要記錄大量信息,同時還要保證加密信息的安全。若是 session裏要存放大數據,這種方式就不是很適合了。
除了上述說到的優缺點之外,A、B兩種方式還有另一個問題,就是當我有不止一臺服務器的時候,不一樣服務器間的session數據共享就成問題了。
比 如,最初我只有一臺服務器1,他的session裏記錄了user-1和user-2的數據。這個時候,我須要增長一臺服務器2。當nginx把用戶的請 求轉發到服務器2的時候,他就傻眼了:用戶帶了一個jsession_id=angOwberup這個的cookie過來,而在他的session管理器 裏卻找不到這樣一個session數據。那該怎麼辦?!(苦!惱!啊!)
所以,就出現了咱們文章一開始提到的問題:在分佈式系統裏,用戶session如何才能實現同步?
3、session的同步
有了上面的狀況,咱們就必需要去考慮,如何在多個服務器之間實現session同步這個操做。常見的作法有如下幾種,咱們逐個來看看:
A、進程間通訊傳遞session數據。
這是最容易想到的一個方法。咱們在不一樣的server服務裏開一個socket,而後用socket來將相互擁有的session數據進行傳遞。我記得多年之前tomcat就是採用這樣的方式來作的(已經好久沒用過tomcat了,不知道如今是否還在這樣使用)。
這 種方式的好處很明顯,就是原理簡單明瞭;壞處也很明顯,就是同步合併過程複雜,還容易形成同步延遲。好比,某個用戶在server-1登陸 了,server-1存儲了這個用戶的session,當正準備將數據同步給server-2的時候,因爲用戶訪問實在是太快(飛通常的速 度),server-2還沒收到server-1傳來的session數據,用戶訪問就已經來了。這個時候,server-2就不能識別這個用戶,形成用 戶須要再次登陸。
並且,當有成千上萬臺服務器的時候,session同步就是一個噩夢:每個服務器都要將本身擁有的session廣播給其餘全部機器,並且還要隨時進行,不能停歇…… (最後這些機器估計都是累死的)
B、 cookie存儲方式。咱們在上面講到了一個很偷懶的方式,就是把session數據作加密,而後存儲到cookie中。用戶請求到了,就直接從 cookie讀取,而後作解密。這種方式真是把分佈式思想發揮到了一個至關的高度。他把用戶也當作分佈式的一員,你要訪問數據,那你就本身攜帶着他,每次 到服務器的時候,咱們的服務器就只負責解密……
對於session裏只存放小數據,而且加密作的比較好(防止碰撞作暴力破解)的系統來說,這是一個比較好的選擇。他實現超級簡單,並且不用考慮數據的同步。
不過若是要往session裏存放大數據的狀況就不是太好處理。或者安全性要求很高的系統,也不是太好的一個方式(數據有被破解的風險)。
C、cache集羣或者數據庫作session管理。咱們也能夠採用另一種架構來解決session同步問題,那就是引入統一session接入點。
我 們session放入到cache集羣或者數據庫中,每次請求的時候,都從他們中來獲取。這樣,全部的機器都能獲取到最新的session數據。這種方案 也是不少中大型網站採用的解決方案。他實現起來相對簡單(利用cache集羣或者主從數據庫自身的管理來實現多機的互備),並且效率很高,安全性也不錯。
D、還有一種方式是從上面這種方式延展出來的,就是提供session服務。這個服務負責管理session,其餘服務器每次從這個服務處獲取session數據,從而達到數據的共享。
大 家若是仔細觀察一下baidu或者google,你作登陸的時候,他們可能會讓你跳到passport.baidu.com 或者accounts.google.com這兩個域名之下。這兩個就是他們用來作用戶登陸和相似session管理的一個地方(因爲以前只呆過 baidu,因此google並非很是清楚)。當一個訪問請求來的時候,server就從cookie裏取相似session_id的東東,而後用這個 東東去passport服務去請求用戶的session數據。
這種方式的好處就在於:
A、能夠很是方便的擴展用戶登陸的數量以及存儲數據的大小。當時在x度的時候,N億用戶的session都在這個系統裏進行管理;
B、 方便作性能優化。若是用cache集羣的方案,若是cache有機器壞掉,那麼就會形成一部分用戶session失效;若是用數據庫方案,若是量太大,有 可能會出現性能問題。而這種方案在實現的時候,能夠用cache和數據庫結合的實現方式,保證高效和穩定。同時,針對一些接口,能夠作性能的優化,提高查 詢效率;
C、對外封閉,保證數據安全。這種方式還有一個好處,就是能夠將加密算法、密鑰等封閉在系統內部,對外只暴露接口,使得數據安全性更有保障。(涉及到用戶信息的,都是隱私!)
不過,這種方式也有本身的問題,就是運維相對更復雜,有可能須要專門的團隊去管理這些系統。
注:本文出自 https://www.toutiao.com/a6294758409293086977/