文章目錄
一、會話保持
會話保持,有時又可叫做 粘滯會話(Sticky Sessions)
。
- 會話保持是指:在負載均衡器上的一種機制,可以識別客戶端與服務器之間交互過程的關連性,在作負載均衡的同時還保證一系列相關連的訪問請求都會分配到一臺機器上。 通俗講就是,在一次會話過程中發起的多個請求都會落到同一臺機器上。
1.1 會話(session)與連接(connection)之間的區別
連接: 我們都知道TCP/IP協議中經常提到的:”三次握手,四次揮手“的問題。自然也知道客戶端和服務器端是經過三次握手以後,建立了連接(connection)
。當它們建立了連接以後,那麼客戶端就可以向服務端發送多次的請求。如果客戶端和服務器端需要斷開連接,那麼就需要經過四次的揮手過程才能夠斷開連接。
會話: 如果用戶需要登錄,那麼可以理解爲經過三次握手以後,客戶端與服務器端建立的就是會話(session)
。如果用戶不需要登錄,那麼可以理解爲經過三次握手以後,客戶端與服務器端建立的就是連接(connection).
從簡單的角度來看,如果用戶需要登錄,那麼就可以簡單的理解爲會話;如果不需要登錄,那麼就是連接。
1.2 爲什麼要會話保持?
實際上,會話保持機制
與負載均衡的基本功能
是完全矛盾的。
負載均衡
希望將來自客戶端的連接、請求均衡的轉發至後端的多臺服務器,以避免單臺服務器負載過高;會話保持機制
卻要求將某些請求轉發至同一臺服務器進行處理。
原始負載均衡的基本原理:
- 對於同一個連接中的數據包,負載均衡會將其進行NAT轉換後,轉發至後端固定的服務器進行處理,這是負載均衡最基本、最原始的功能。負載均衡系統內部會專門有一張表來記錄這些連接的狀況,包括:
[源IP:端口]、[目的IP:端口]、[服務器IP:端口]、空閒超時時間(Idle Timeout)等等
。
由於這張表需要消耗系統的內存資源,因此,這張表不可能無限大,所有廠家都會有一定的限制。這張表的大小一般稱之爲最大併發連接數,也就是系統同時能夠容納的連接數量。考慮到建立連接的客戶端或服務器會發生異常狀況,導致連接不能被正常終結掉,因此,負載均衡的當前連接狀態表項中有一個空閒超時時間的參數。如果在規定的時間內某個連接不再有請求,那麼這個連接就會被清除掉,釋放系統資源。那麼,刪除連接以後,客戶端的請求將無法繼續發往同一個後端的服務器,那麼就會導致數據丟失等等。
常見的異常場景包括:
- 客戶端輸入了正確的用戶名和密碼,但卻反覆跳到登錄頁面;
- 客戶端放入購物籃的物品丟失;
- 用戶輸入了正確的驗證碼,但是總提示驗證碼錯誤
因此,會話保持機制的意義就在於,確保將來自相同客戶端的請求,轉發至後端相同的服務器進行處理。如果在客戶端和服務器之間部署了負載均衡設備,很有可能,這多個連接會被轉發至不同的服務器進行處理。如果服務器之間沒有會話信息的同步機制,會導致其他服務器無法識別用戶身份,造成用戶在和應用系統發生交互時出現異常。
1.3 會話保持在Nginx中的實現
1、ip_hash機制
- ip_hash技術能夠將 某個ip 的請求定向到同一臺後端web機器中, 這樣一來這個ip 下的客戶端和某個後端web機器就能建立起穩固的session.
- ip_hash技術能夠讓某一客戶機在相當長的一段時間內只訪問固定的後端的某臺真實的web服務器,這樣會話就會得以保持,在網站頁面進行login的時候就不會在後面的web服務器之間跳來跳去了,也不會出現登錄一次的網站又提醒重新登錄的情況.
缺陷:
- nginx不是最前端的服務器:當多個客戶是通過 代理或地址轉換 的方式來訪問服務器時,由於都分配到同一臺服務器上,會導致服務器之間的負載嚴重失衡。例如,使用的是squid反代爲最前端.那麼nginx取ip時只能得到squid的服務器ip地址,用這個地址來作分流肯定是不對的。
- nginx的後端還有其它負載均衡:若nginx後端還有其它負載均衡,將請求又通過另外的方式分流了。
2、nginx-sticky-module這個第三方模塊
Sticky
是基於cookie
的一種負載均衡解決方案,通過分發和識別cookie,使來自同一個客戶端的請求落在同一臺服務器上,換一種說法,服務器給客戶端下發一個cookie,具有特定cookie的請求會分配給它的發行者,默認cookie標識名爲route
。
工作原理
- 客戶端首次發起訪問請求,nginx接收後,發現請求頭沒有cookie,則以輪詢方式將請求分發給後端服務器。
- 後端服務器處理完請求,將響應數據返回給nginx。
- 此時nginx生成帶route的cookie,返回給客戶端。route的值與後端服務器對應,可能是明文,也可能是md5、sha1等Hash值
- 客戶端接收請求,並保存帶route的cookie。
- 當客戶端下一次發送請求時,會帶上route,nginx根據接收到的cookie中的route值,轉發給對應的後端服務器。
什麼是cookie
HTTP協議本身是無狀態的。什麼是無狀態呢,即服務器無法判斷用戶身份。Cookie實際上是一小段的文本信息(key-value格式)。客戶端向服務器發起請求,如果服務器需要記錄該用戶狀態,就使用response向客戶端瀏覽器頒發一個Cookie。客戶端瀏覽器會把Cookie保存起來。當瀏覽器再請求該網站時,瀏覽器把請求的網址連同該Cookie一同提交給服務器。服務器檢查該Cookie,以此來辨認用戶狀態。
打個比方,我們去銀行辦理儲蓄業務,第一次給你辦了張銀行卡,裏面存放了身份證、密碼、手機等個人信息。當你下次再來這個銀行時,銀行機器能識別你的卡,從而能夠直接辦理業務。
二、實現會話保持具體過程
在上一篇博客中,我們已經實現了負載均衡,但是遺留問題:新的數據覆蓋舊的數據內容,造成數據的丟失,現在我們就來解決它。
實驗環境
主機(版本:ip) | 功用 |
---|---|
虛擬機server1(rhel6.5:172.25.2.1) | lnmp環境主機+tomcat1服務器 |
虛擬機server2(rhel6.5:172.25.2.2) | tomcat2服務器 |
真機(rhel7.3:172.25.2.250) | 測試機 |
1、在nginx-1.14中不支持nginx-sticky-module
模塊,所以使用nginx-1.10版本,重新編譯nginx
tar zxf nginx-1.10.1.tar.gz
tar zxf nginx-sticky-module-ng.tar.gz -C /usr/local/
2、註釋掉debug日誌,不顯示nginx的版本號,把openresty的nginx關掉,否則會佔用80端口,導致服務器起不來
/usr/local/openresty/nginx/sbin/nginx -s stop
3、重新編譯,加入sticky模塊,然後安裝:
./configure --prefix=/usr/local/lnmp/nginx \
--with-http_ssl_module \
--with-http_stub_status_module \
--with-threads --with-file-aio \
--user=nginx --group=nginx \
--add-module=/mnt/nginx-sticky-module-ng
make && make install
編譯完,我們可以查看是否加入了nginx-sticky-module
安裝
4、編輯nginx配置文件,其實複製之前的openresty下的nginx配置文件,修改即可。
[root@server1 nginx-1.10.1]# cp /usr/local/openresty/nginx/conf/nginx.conf /usr/local/lnmp/nginx/conf/
[root@server1 nginx-1.10.1]# vim /usr/local/lnmp/nginx/conf/nginx.conf
17 http {
18 upstream tomcat{
19 sticky;
20 server 172.25.2.1:8080;
21 server 172.25.2.2:8080;
22 }
不用的代碼可以註釋掉。
5、創建軟鏈接,並啓動nginx。
[root@server1 nginx-1.10.1]# ln -s /usr/local/lnmp/nginx/sbin/nginx /sbin/
[root@server1 nginx-1.10.1]# nginx
[root@server1 nginx-1.10.1]# netstat -tnlp
6、先清除緩存,訪問測試頁http://172.25.2.1/test.jsp
我們添加數據,發現數據不丟失,而且id號不改變,到此我們實現了會話保持。
7、此時,我們關閉tomcat1
,再次訪問測試頁面,卻發現server1
上面的數據沒有同步到server2
上
[root@server1 bin]# pwd
/usr/local/tomcat/bin
[root@server1 bin]# ./shutdown.sh
我們可以看出,客戶會一直訪問同一臺tomcat服務器,實現了會話保持,即使後臺一臺tomcat服務器宕機,切換到另外一臺tomcat服務器上面依然可以實現會話保持,但是此時在第一個tomcat主機上面的數據丟失。
在下一篇博客中,我們解決此問題。