1. 程式人生 > >nginx:負載均衡的session共享問題

nginx:負載均衡的session共享問題

一、場景

當nginx做了負載均衡之後,同一個ip的url請求伺服器的時候,負載均衡會根據每臺伺服器的權重等一些設定將請求轉發到不同的伺服器上去進行處理,這樣的話針對一些帶有狀態請求的情況來說就是個很大的問題,因為是帶有狀態的請求就好比登陸狀態一樣,A使用者登陸系統,負載均衡機制把A使用者的登陸請求分發給了s1伺服器,這個時候s1伺服器上就會記錄A使用者登陸的session資訊,登陸成功後,當A使用者進行相應的操作,比如進入個人中心,這時候這個請求經過反向代理伺服器的時候,負載均衡機制根據當前叢集中的各個伺服器的壓力效能等情況可能把請求分發給了s2伺服器處理,那麼這個時候會去驗證使用者的狀態是否登入,也就是驗證session,可是A使用者的session儲存在了s1伺服器上,造成再s2伺服器上請求驗證狀態找不到對應的session,就會認為使用者未登入而做的異常操作,就會提醒使用者去登入,從而跳轉到登入頁面,那麼這就是負載均衡針對帶有狀態的請求的一個弊端。

二、解決的方案

1. 不使用session,使用cookie

session是存放在伺服器端的,cookie是存放在客戶端的,我們可以把使用者訪問頁面產生的session放到cookie裡面,就是以cookie為中轉站。你訪問web伺服器A,產生了session然後把它放到cookie裡面,當你的請求被分配到B伺服器時,伺服器B先判斷伺服器有沒有這個session,如果沒有,再去看看客戶端的cookie裡面有沒有這個session,如果也沒有,說明session真的不存,如果cookie裡面有,就把cookie裡面的sessoin同步到伺服器B,這樣就可以實現session的同步了。

說明:這種方法實現起來簡單,方便,也不會加大資料庫的負擔,但是如果客戶端把cookie禁掉了的話,那麼session就無從同步了,這樣會給網站帶來損失;cookie的安全性不高,雖然它已經加了密,但是還是可以偽造的,所以這種方式也是不推薦的。

2. session存在資料庫mysql

session儲存在資料庫中,是把session表和其他的資料表存放在一起,那麼當用戶只要登入後隨便操作了些什麼就要去資料庫驗證一下session的狀態,這樣無疑加重了mysql資料庫的壓力;如果資料庫也做了叢集的話,那麼也就是說每個資料庫叢集的節點都得儲存這個session表,而且要保證每個叢集的節點中資料庫的session表的資料保持一致,實時同步

說明:session保持在資料庫,加重了資料庫的IO,增大資料庫的壓力和負擔,從而影響資料庫的讀寫效能,而且mysql叢集的話也不利於session的實時同步

3. session存在快取memcache或者redis中

memcache可以做分散式,php配置檔案中設定儲存方式為memcache,這樣php自己會建立一個session叢集,將session資料儲存在memcache中。

說明:這種方式來同步session,不會加大資料庫的負擔,而且安全性比用cookie儲存session大大的提高,把session放到記憶體裡面,比從檔案中讀取要快很多。但是memcache把記憶體分成很多種規格的儲存塊,有塊就有大小,這種方式也就決定了,memcache不能完全利用記憶體,會產生記憶體碎片,如果儲存塊不足,還會產生記憶體溢位。

4. ip_hash技術    nginx中可以配置,當某個ip下的客戶端請求指定(固定,因為根據IP地址計算出一個hash值,根據hash值來判斷分配給那臺伺服器,從而每次該ip請求都分配到指定的伺服器)的伺服器,這樣就可以保證有狀態請求的狀態的完整性,不至於出現狀態丟失的情況,一下是nginx的配置,可以參考一下:

upstream nginx.example.com  
    {   
             server 192.168.1.2:80;   
             server 192.168.1.3:80;  
             ip_hash;  
    }  
    server  
    {  
             listen 80;  
             location /  
             {  
                     proxy_pass  
                    http://nginx.example.com;  
             }  
 }  

注意:ip_hash這個方案確實可以保證帶有狀態的請求的完整性,但是它有一個很大的缺陷,那就是ip_hash方案必須保證Nginx是最前端的伺服器(接受真實的ip),如果nginx不是最前端的伺服器,還存在中介軟體(中間伺服器什麼的),那麼nginx獲取的ip地址就不是真實的ip地址,那麼這個ip_hash就沒有任何意義

5.還有其他的一些方法,本人暫時還不太清楚,有待繼續的學習(url_hash不知道可以不可以?是否新增一臺共享資料的伺服器,把狀態等一些公共的資料都保持到這臺伺服器上,從而叢集的所有伺服器都從共享伺服器上邊獲取狀態進行驗證??待求證)

內容出自網上各位兄弟姐妹的好文章,萬分感謝!!!

此文章轉自連結: link.