天天看點

負載均衡叢集中的session解決方案

前言

在我們給Web站點使用負載均衡之後,必須面臨的一個重要問題就是Session的處理辦法,無論是PHP、Python、Ruby還是Java,隻要使用伺服器儲存Session,在做負載均衡時都需要考慮Session的問題。

分享目錄:

問題在哪裡?如何處理?

會話保持(案例:Nginx、Haproxy)

會話複制(案例:Tomcat)

會話共享(案例:Memcached、Redis)

問題在哪裡?

從使用者端來解釋,就是當一個使用者第一次通路被負載均衡代理到後端伺服器A并登入後,伺服器A上保留了使用者的登入資訊;當使用者再次發送請求時,根據負載均衡政策可能被代理到後端不同的伺服器,例如伺服器B,由于這台伺服器B沒有使用者的登入資訊,是以導緻使用者需要重新登入。這對使用者來說是不可忍受的。是以,在實施負載均衡的時候,我們必須考慮Session的問題。

在負載均衡中,針對Session的處理,我們一般有以下幾種方法:

Session 保持

Session 複制

Session 共享

Session保持(會話保持)是我們見到最多的名詞之一,通過會話保持,負載均衡進行請求分發的時候保證每個用戶端固定的通路到後端的同一台應用伺服器。會話保持方案在所有的負載均衡都有對應的實作。而且這是在負載均衡這一層就可以解決Session問題。

Nginx 做負載均衡的Session保持

對于Nginx可以選用Session保持的方法實行負載均衡,nginx的upstream目前支援5種方式的配置設定方式,其中有兩種比較通用的Session解決方法,ip_hash和url_hash。注意:後者不是官方子產品,需要額外安裝。

ip_hash

每個請求按通路ip的hash結果配置設定,這樣每個訪客固定通路一個後端伺服器,達到了Session保持的方法。

例:

<code>upstream bakend {</code>

<code>   </code><code>ip_hash;</code>

<code>   </code><code>server192.168.0.11:80;</code>

<code>   </code><code>server192.168.0.12:80;</code>

<code> </code><code>}</code>

Haproxy做負載均衡的Session保持

    Haproxy作為一個優秀的反向代理和負載均衡軟體,也提供了多種Session保持的方法,下面列舉了兩種最常用的:

源位址 Hash

haroxy 将使用者IP經過hash計算後指定到固定的真實伺服器上(類似于nginx 的ip hash 指令)

<code>配置指令:balancesource</code>

使用cookie 進行識别 

也就是Haproxy在使用者第一次通路的後在使用者浏覽器插入了一個Cookie,使用者下一次通路的時候浏覽器就會帶上這個Cookie給Haproxy,Haproxy進行識别。

<code>配置指令:cookie  SESSION_COOKIE  insert indirect nocache</code>

配置例子如下:

<code>cookie SERVERID insert indirect nocache</code>

<code>server web01 192.168.56.11:8080 check cookie web01</code>

<code>server web02 192.168.56.12:8080 check cookie web02</code>

會話保持的缺點:

會話保持看似解決了Session同步的問題,但是卻帶來的一些其它方面的問題:

負載不均衡了:由于使用了Session保持,很顯然就無法保證負載絕對的均衡。

沒有徹底解決問題:如果後端有伺服器當機,那麼這台伺服器的Session丢失,被配置設定到這台服務請求的使用者還是需要重新登入。

既然,我們的目标是所有伺服器上都要保持使用者的Session,那麼将每個應用伺服器中的Session資訊複制到其它伺服器節點上是不是就可以呢?這就是Session的第二中處理辦法:會話複制。

 會話複制在Tomcat上得到了支援,它是基于IP多點傳播(multicast)來完成Session的複制,Tomcat的會話複制分為兩種:

全局會話複制:利用Delta Manager複制會話中的變更資訊到叢集中的所有其他節點。

非全局複制:使用Backup Manager進行複制,它會把Session複制給一個指定的備份節點。

    不過,這裡我不準備來解釋會話複制的Tomcat配置,如果有需求可以參考Tomcat官方文檔,主要是因為會話複制不适合大的叢集。根據筆者在生産的實踐案例,當時是在叢集超過6個節點之後就會出現各種問題,不推薦生産使用。

既然會話保持和會話複制都不完美,那麼我們為什麼不把Session放在一個統一的地方呢,這樣叢集中的所有節點都在一個地方進行Session的存取就可以解決問題。

    Session存放到哪裡?

對于Session來說,肯定是頻繁使用的,雖然你可以把它存放在資料庫中,但是真正生産環境中我更推薦存放在性能更快的分布式KV資料中,例如:Memcached和Redis。

PHP設定Session共享

如果你使用的是PHP那麼恭喜你,配置非常的簡單。PHP通過兩行配置就可以把Session存放在Memcached或者Redis中,當然你要提前配置好他們。修改php.ini:

<code>session.save_handler = memcache</code>

<code>session.save_path = </code><code>"tcp://192.168.56.11:11211"</code>

使用Redis存儲Session

<code>session.save_handler = redis</code>

<code>session.save_path =</code><code>"tcp://localhost:6379"</code>

提醒:别忘了給PHP安裝memcache或者redis插件。

Tomcat設定Session共享

Django設定Session共享

在Django中Session是通過一個中間件管理的。如果要在應用程式中使用Session,需要在settings.py中的MIDDLEWARE_CLASSES變量中加入’django.contrib.sessions.middleware.SessionMiddleware’ 。Django的Session引擎可以将Session存放在三個地方,分别是:資料庫、緩存、檔案。

使用資料庫儲存Session

如果你想使用資料庫支援的會話,你需要添加'django.contrib.sessions'到你的INSTALLED_APPS設定中。在配置完成之後,請運作manage.py migrate來安裝儲存會話資料的一張資料庫表。

使用緩存保持Session

對于簡單的緩存會話:

可以設定SESSION_ENGINE 為"django.contrib.sessions.backends.cache"。此時會話資料将直接存儲在你的緩存中。然而,緩存資料将可能不會持久:如果緩存填滿或者緩存伺服器重新開機,緩存資料可能會被清理掉。

  若要持久的緩存資料:

可以設定SESSION_ENGINE為"django.contrib.sessions.backends.cached_db"。它的寫操作使用緩存,對緩存的每次寫入都将再寫入到資料庫。對于讀取的會話,如果資料不在緩存中,則從資料庫讀取。兩種會話的存儲都非常快,但是簡單的緩存更快,因為它放棄了持久性。大部分情況下,cached_db後端已經足夠快,但是如果你需要榨幹最後一點的性能,并且接受會話資料丢失的風險,那麼你可使用cache而不是cached_db

使用檔案儲存Session

使用檔案儲存Session不再我們的讨論之類,因為很難進行共享,PHP預設也是将Session存放在/tmp目錄下。

本文轉自 a928154159 51CTO部落格,原文連結:

http://blog.51cto.com/zhibeiwang/1965018