詳解分布式系統里session同步


1、什么是session?什么又是cookie?他倆有啥聯系和區別?

2、為什么要在多台服務器間進行session的共享同步?

3、以及有哪些方法來實現這個同步?

大家快搬板凳,老王開始扯淡咯~

1、session和cookie的纏綿與悱惻

相信有盆友跟老王一樣,曾經為session和cookie糾結過,或者現在正在為他們糾結。session在英文里的意思是會議,而cookie則是餅干。你說這個會議和餅干怎么就關聯上了呢?(開會的時候可以吃餅干)

我們先來看看百度百科的解釋吧:

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來實現的。

一招制勝---詳解分布式系統里session同步

以上就是我請求百度,他給我發放的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數據共享就成問題了。

一招制勝---詳解分布式系統里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同步

我 們session放入到cache集群或者數據庫中,每次請求的時候,都從他們中來獲取。這樣,所有的機器都能獲取到最新的session數據。這種方案 也是很多中大型網站采用的解決方案。他實現起來相對簡單(利用cache集群或者主從數據庫自身的管理來實現多機的互備),而且效率很高,安全性也不錯。

D、還有一種方式是從上面這種方式延展出來的,就是提供session服務。這個服務負責管理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/


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM