服務器集羣環境下session的共享問題

一,集羣和分佈式的區別

在進入今天的正題之前,對服務器集羣和分佈式服務器這兩個概念進行簡要說明。

服務器集羣:服務器集羣就是指將很多服務器集中起來一起進行同一種服務,在客戶端看來就像是隻有一個服務器。集羣可以利用多個計算機進行並行計算,從而獲得很高的計算速度,也可以用多個計算機做備份,,從而使得任何一個機器壞了整個系統還是能正常運行。

根據上述的信息簡單來說:服務器集中對外提供同一種服務,解決了大量用戶訪問同一服務存在的高併發問題;多臺服務器備份,解決了服務器的高可用問題;不至於說一臺服務器宕機, 這個服務就癱瘓了!

上文中提到的多臺服務器備份,備份的不就是會話信息session嗎?也就是今天我們要說的服務器集羣環境下session的共享問題。

分佈式服務器:隨着B/S架構系統的發展,開發一個互聯網項目的業務需求也越來越多。如果把這些業務模塊都放在一臺服務器上來提供服務,這肯定是不現實的,畢竟一臺服務器的性能各方面都是有限的。企業普遍會把這些業務模塊分別放到不同的服務上來提供服務,來滿足大量用戶訪問不同服務時存在的高併發問題

簡單來說服務器集羣和分佈式服務器的區別:
分佈式:項目的不同業務模塊(例如:用戶模塊,購物車模塊,支付模塊),部署在不同的服務器上
集羣:同一個業務(例如:用戶模塊),部署在多個服務器上

二,會話技術Cookie,Session

估計你們會在想:這個標題黨,真正的問題不解決,怎麼又扯出個會話技術。難道這就是傳說中的程序員修復Bug,真正的問題沒有解決,又冒出了另一個問題。

哈哈,不扯皮了。這裏主要是爲了說明Cookie,Session的聯繫和區別。

1.什麼是會話?

用戶開一個瀏覽器訪問頁面,訪問了很多網站,直到用戶關閉瀏覽器,這整個過程我們稱作一次會話。

2.會話過程中的信息存儲問題

HTTP是無狀態協議:每次都是單獨連接,不能保存用戶的信息,通俗來說,就是它區分不了到底是哪一個用戶在訪問網絡資源。而Cookie和Session就很好地解決了這個問題,

Cookie:
Cookie是客戶端技術,服務器把每個用戶的數據以cookie的形式寫給用戶各自的瀏覽器。當用戶使用瀏覽器再去訪問web資源時,瀏覽器就會帶着用戶的信息過去。這樣,web資源處理的就是用戶各自的數據了。

注意:Cookie是存放在瀏覽器端,分爲會話Cookie和持久性Cookie,默認情況下,Cookie是會話級別的,關閉瀏覽器就會消失。可以通過設置Cookie的有效時間來實現持久性Cookie存儲

Session:
雖然Cookie可以存放用戶信息,但cookie存儲在瀏覽器端是以明文方式存放,因此安全性較低。而Session是存放在服務器端的,我們把用戶的信息保存在服務器端Session中相對安全,然後把服務器創建的Session對象的Id存在中Cookie中,這樣用戶在訪問服務器資源時,Cookie就會帶着SessionId過來,服務器端就會根據這個SessionId來找到對應的Session,從而找到存儲在Session中的用戶信息。

注意:在訪問同一個服務器下的Web資源時,Session只會被創建一次,Sessinon在用戶訪問第一次訪問服務器時創建,需要注意只有訪問JSP、Servlet等程序時纔會創建Session

三,服務器集羣環境下session的共享問題

1.反向代理服務器Nginx

Nginx多在高併發情況下需要使用。其原理就是將用戶請求分攤到多個服務器執行,減輕每臺服務器的壓力,多臺服務器(集羣)共同完成工作任務,從而提高了數據的吞吐量。

在這裏插入圖片描述

在這裏插入圖片描述

正向代理:用戶想在某個指定的服務器上獲取資源
反向代理:用戶只要訪問Nginx就可以獲取到資源,而不用去關心具體訪問的是哪個服務器

Nginx的使用

Nginx的安裝過程跳過,主要演示Nginx的一些配置。

打開Nginx的nginx.conf文件,配置如下

在這裏插入圖片描述

#下面這個配置需要自己添加
	upstream xiaogui_server{
		server localhost:8080;
		server 127.0.0.1:8888;
	}

#修改配置文件,添加  proxy_pass http://xiaogui_server;
 location / {
            root   html;
			proxy_pass http://xiaogui_server;
            index  index.html index.htm;
        }

在服務器tomcat1下的測試頁面:

<%@ page language="java" contentType="text/html; charset=utf-8"
    pageEncoding="utf-8"%>
    
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>服務器1111111111111</title>
<style type="text/css">
</style>
</head>
<body>
		<h1>服務器1的頁面</h1>
		
		服務器1創建Session的Id:<%=session.getId() %>
		
		<%session.setAttribute("username", "xiaogui");%>
</body>
</html>

服務器tomcat2下的測試頁面

<%@ page language="java" contentType="text/html; charset=utf-8"
    pageEncoding="utf-8"%>
    
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>服務器2222222222222</title>
<style type="text/css">
</style>
</head>
<body>
		<h1>服務器2的頁面</h1>
		
		服務器2創建Session的Id:<%=session.getId() %><br/>
		
		服務器1創建的Session中的存入的username:<%session.getAttribute("username");%>
</body>
</html>

啓動tomcat1,tomcat2,nginx測試

當訪問tomcat1頁面時,在這裏插入圖片描述

刷新頁面,訪問tomcat2頁面:

在這裏插入圖片描述

****得出結論:使用Nginx訪問服務器,由於訪問的網址不會發生,所以Cookie中的信息在集羣的服務器之間是共享的

根據得出結論,當用戶第一次訪問服務時,服務器創建Session,這時服務器把Session存放到Redis當中,交由Redis管理。以SessionID作爲key,Session對象作爲值。當用戶再次訪問時,不管訪問的哪一個服務器,Cookie都會帶着這個SessionID過來,根據這個SessionID就可以在Redis中找到對應的Session,這樣就實現了Session共享。也就是下面我們要說到的這個方案。

使用nginx+tomcat+redis完成session共享(推薦方式)

在這裏插入圖片描述

redis安裝:https://blog.csdn.net/qq_41258204/article/details/83715582

下載tomcat-redis-session-manager相應的jar包,主要有三個:

在這裏插入圖片描述

commons-pool-1.6.jar :主要是來用管理redis
jedis-2.1.0.jar :用來操作redis的客戶端
tomcat-redis-session-manager:主要使用redis來管理服務器創建的Session

這三個jar包,網上不太容易找到,好多下載都要收費。而且下載之後還要考慮三個jar之間的兼容性。我把測試成功的這三個jar包放在文章末尾的示例項目中!

把這三個jar複製到tomcat的lib目錄下,
在這裏插入圖片描述

修改tomcat/conf目錄下的context.xml,在這個文件中,加入下面配置

	<Valve className="com.radiadesign.catalina.session.RedisSessionHandlerValve" />
<Manager className="com.radiadesign.catalina.session.RedisSessionManager"
         host="localhost"
         port="6379"
         database="0"
         maxInactiveInterval="60" />

注意:所有集羣的tomcat都要進行上述的配置。

啓動Redis,tomcat1,tomcat2,Nginx服務,進行測試

在這裏插入圖片描述

用戶再一次刷新頁面,

在這裏插入圖片描述

我們還可以通過redis的客戶端查看:
在這裏插入圖片描述

由於使用redis的客戶端查看,對數據進行了轉碼,所以會顯示成上面的結果。

tomcat的廣播機制,完成session共享(不推薦)

修改tomcat/conf下的server.xml文件
在這裏插入圖片描述

把這個註釋的部分去掉

 <Cluster className="org.apache.catalina.ha.tcp.SimpleTcpCluster"/>

在項目的web.xml中配置

<distributable/>

在集羣的tomcat上配置好以後,重啓tomcat即可。

根據用戶的IP進行hash計算,讓用戶訪問指定的tomcat

修改Nginx/conf目錄下的nginx.conf文件

	#下面這個配置需要自己添加
	upstream xiaogui_server{
		server localhost:8080;
		server 127.0.0.1:8888;
		ip_hash;
	}

在上面這個配置中加入ip_hash;即可。

缺點:1.由於局域網對外的IP都是一樣的,如果該局域網中的用戶都對服務進行訪問,根據這個配置會造成局域網內所有的用戶都會訪問該服務器,這時服務器的訪問壓力會很大。2.當這個服務器宕機之後,可能被分配到這個服務器上的用戶就沒有辦法進行訪問了。

Nginx第三方模塊upstream_hash解決session共享

爲了解決ip_hash的一些問題,可以使用upstream_hash這個第三方模塊,這個模塊多數情況下是用作url_hash的,但是並不妨礙將它用來做session共享:

假如前端是squid,他會將ip加入x_forwarded_for這個http_header裏,用upstream_hash可以用這個頭做因子,將請求定向到指定的後端:

hash $http_x_forwarded_for;

在nginx新版本中可支持讀取cookie值,所以也可以改成:

hash $cookie_jsessionid;

最後這種沒有做過測試,有興趣的話,自己可以測試一下。

分享示例項目在碼雲上的地址:https://gitee.com/xiaoguixiaogege/ClusterShareSession

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章