1. 程式人生 > >linux-Centos-7-64位:9、session同步共享(一)

linux-Centos-7-64位:9、session同步共享(一)

一、第一種方案

基於Nginx+Tomcat叢集的Session共享
在Linux環境下
第一步:下載對應的nginx 和 tomcat 包並解壓、安裝、配置(此步驟之前文章有提過,在此省略。。)
第二步:Linux下nginx配置

#Nginx所用使用者和組,windows下不指定   
user  www www;   

#指定工作衍生程序數(一般等於CPU的總核數或總核數的兩倍) 
worker_processes 8; 

#指定檔案描述符數量
worker_rlimit_nofile 51200; 

#指定pid存放的路徑  
pid        logs/nginx.pid;  

#指定錯誤日誌存放的路徑和級別,可選debug|info|notice|warn|error|crit 
#error_log  logs/error.log;  
#error_log  logs/error.log  notice; 
error_log   logs/error.log  info; 
events {  
	#使用的網路I/O模型,Windows下不用配置 
	useepoll;
	#允許的連線數 
	worker_connections  51200;
} 
http {  
	includemime.types; 
	default_type  application/octet-stream; 
	#設定使用的字符集
	#隱藏nginx的版本號
	server_tokens off;
	#自定義日誌格式 
	log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
						'$status $body_bytes_sent "$http_referer" '
						'upstream_response_time $upstream_response_time $upstream_addr' '"$http_user_agent" "$http_x_forwarded_for"'; 
	#access_log  logs/access.log  combined; 
	#access日誌存放路徑和格式  
	access_log  logs/access.log  main;
	
	#提升檔案傳輸效能
	sendfile on;
	#tcp_nopush on; 
	#設定客戶端能夠請求的單個檔案大小
	client_max_body_size 300m;
	keepalive_timeout  75;
	#proxy引數 
	#跟後端伺服器連線的超時時間,發起握手等候響應超時時間 
	proxy_connect_timeout 5; 
	#連線成功後,等候後端伺服器的響應時間 
	proxy_read_timeout 600;
	#後端伺服器資料回傳時間 
	proxy_send_timeout 600;
	#代理請求快取區  
	proxy_buffer_size 16k;  
	#同上,告訴nginx儲存單個用的幾個buffer、最大用多空間 
	proxy_buffers 4 64k; 
	#如果系統很忙時可以申請更大的proxy_buffers,官方推薦*2 
	proxy_busy_buffers_size 128k;
	proxy_temp_file_write_size 128k; 
	#開啟壓縮功能
	gzip on; 
	gzip_min_length 1k;
	gzip_buffers 4 16k;
	gzip_http_version 1.1; 
	gzip_comp_level 2; 
	#壓縮級別從低到高1-9  
	gzip_types text/plain application/x-javascript text/css application/xml;
	gzip_vary on; 
	#開啟gzip壓縮功能 
	#設定負載均衡池,此處是測試環境中的5個Tomcat的IP地址和埠號。 
	upstream tomcat_pool {
		server 10.0.5.43:8801; 
		server 10.0.5.43:8802; 
		server 10.0.5.43:8803; 
		server 10.0.5.43:8804; 
		server 10.0.5.43:8805;      
	}
	#server設定 
	server { 
		#監聽的IP和埠  
		listen 10.0.5.43:80; 
		#主機名稱  
		server_name  10.0.5.43; 
		#設定字符集  
		charset off;          
		#access_log  logs/host.access.log  main; 
		location / {    
			#HTML網頁檔案存放的目錄
			#root   /var/www/html; 
			#預設首頁檔案  
			#index  index.jsp index.html index.htm default.jsp index.do default.do; 
			proxy_pass http://tomcat_pool;   
			proxy_redirect off;    
			proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
			proxy_set_header X-Real-IP $remote_addr;   
			proxy_set_header Host $http_host;    
		}  
		#訪問控制    
		allow all; 
		#設定客戶端瀏覽器快取時間 
		location ~ \.(gif|jpg|jpeg|png|bmp)$  {  
			#對很少修改的檔案開啟expires,設定客戶端瀏覽器快取時間  
			expires 1h;  
			#如果找不到圖片,需要考慮root或proxypass         
		}          
		#error_page  404 /404.html;          
		#redirect server error pages to the static page /50x.html        
		#error_page 500 502 503 504  /50x.html; 
		location = /50x.html {
			root   html;  
		}
		# proxy the PHP scripts to Apache listening on 127.0.0.1:80         
		#         
		#location ~ \.php$ {         
		#    proxy_pass   http://127.0.0.1;         
		#}
		# pass the PHP scripts to FastCGI server listening on 127.0.0.1:9000         
		#         
		#location ~ \.php$ {        
		#    root           html;        
		#    fastcgi_pass   127.0.0.1:9000;        
		#    fastcgi_indexindex.php;        
		#    fastcgi_param  SCRIPT_FILENAME  /scripts$fastcgi_script_name;       
		#    includefastcgi_params;        
		#}        
		# deny access to .htaccess files, if Apache's document root        
		# concurs with nginx's one        
		#location ~ /\.ht {       
		#    deny  all;        
		#}
		#開啟nginx監控頁面   
		location /nginx_status{   
			stub_status on;   
			access_log off;    
			allow all;    
		}  
	}
}

Tomcat在linux的基本配置

第一處埠修改:Xml程式碼

<!--  修改port埠:18005, 5個tomcat不能重複,埠隨意,別太小。本文測試中的5個tomcat設定分別為:18005,18006,18007,18008,18009-->   
<Server port="18005" shutdown="SHUTDOWN">

第二處埠修改:xml程式碼


<!-- port="18081" tomcat監聽埠,隨意設定,別太小 本文件中,5個tomcat分別設定為:8801-8443;8802-8444;8803-8445;8804-8446;8805-8447.-->  
<Connector port="8801" protocol="HTTP/1.1" 
				maxThreads="1500" 
				maxSpareThreads="500"  
				minSpareThreads="100"
				acceptCount="1000" 
				enableLookups="false"  
				connectionTimeout="20000"
				redirectPort="8443"
				URIEncoding="UTF-8" />

第三處埠修改:XML程式碼

<!-- 本文件中,5個tomcat分別設定為:8005-8443;8006-8444;8007-8445;8008-8446;8009-8447.-->
<Connector port="8005" protocol="AJP/1.3" redirectPort="8443" />

Engine元素增加jvmRoute屬性:xml程式碼

<!-- 本文件中,5個tomcat分別設定為:node1,node2,node3,node4,node5.-->
<Engine name="Catalina" defaultHost="localhost" jvmRoute="node1"> 

叢集配置
Tomcat叢集配置主要是在conf目錄下的server.xml中新增以下程式碼:

<Cluster className="org.apache.catalina.ha.tcp.SimpleTcpCluster" channelSendOptions="8">		   
	<Manager className="org.apache.catalina.ha.session.DeltaManager"
			expireSessionsOnShutdown="false"  
			notifyListenersOnReplication="true"/>   
	<Channel className="org.apache.catalina.tribes.group.GroupChannel"> 
		<--此處可以不做修改,Tomcat叢集的預設組播地址就是228.0.0.4,預設埠為:45564-->  
		<Membership className="org.apache.catalina.tribes.membership.McastService"
				address="228.0.0.4"  
				port="45564"
				frequency="500" 
				dropTime="3000"/>  
		<--此處需要根據需要進行修改,address為Tomcat所在主機的IP地址,port為接收組播訊息的埠,預設為4000到5000,可以在該範圍內隨意設定。確保叢集內埠號唯一即可。-->    
		<Receiver className="org.apache.catalina.tribes.transport.nio.NioReceiver "
				address="10.0.5.43"    
				port="4001"   
				autoBind="100"    
				selectorTimeout="5000"    
				maxThreads="6"/>  
		<Sender className="org.apache.catalina.tribes.transport.ReplicationTransmitter">  
		<Transport className="org.apache.catalina.tribes.transport.nio.Pooled ParallelSender" />  
		</Sender>  
		<Interceptor className="org.apache.catalina.tribes.group.interceptors.TcpFailureDetector"/>
		<Interceptor className="org.apache.catalina.tribes.group.interceptors.MessageDispatch15Interceptor"/>
		<Interceptor className="org.apache.catalina.tribes.group.interceptors.ThroughputInterceptor"/>  
	</Channel>  
	<Valve className="org.apache.catalina.ha.tcp.ReplicationValve" filter=""/>   
	<Valve className="org.apache.catalina.ha.session.JvmRouteBinderValve"/>
	<DeployerclassName="org.apache.catalina.ha.deploy.FarmWarDeployer"  
		    tempDir="/tmp/war-temp/"     
		    deployDir="/tmp/war-deploy/"     
		    watchDir="/tmp/war-listen/"      
		    watchEnabled="false"/>  
	<ClusterListener className="org.apache.catalina.ha.session.JvmRouteSessionIDBinderListener"/>   
	<ClusterListener className="org.apache.catalina.ha.session.ClusterSessionListener"/>
</Cluster>

最後,在需要進行session共享的應用中WEB-INF目錄下的web.xml中新增屬性。否則將不會實現Tomcat叢集應用中的session資料共享。

上述程式碼的詳細說明:
1、Cluster

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

1)Tomcat叢集主元素,在這個元素裡面可以配置叢集的所有詳細資訊
2)className 主要的叢集類,當前只提供了 org.apache.catalina.ha.tcp.SimpleTcpCluste作為實現類
3)channelSendOptionssession傳送方式,預設值是8,這個標識確定通過SimpleTcpCluste如何傳送訊息
4)Channel.SEND_OPTIONS_SYNCHRONIZED_ACK = 0x0004
Channel.SEND_OPTIONS_ASYNCHRONOUS = 0x0008
Channel.SEND_OPTIONS_USE_ACK = 0x0002
如果使用(ASYNCHRONOUS)加(USE_ACK)方式來發送訊息,那麼值應該是10(8+2)或者0x000B
如果使用(SYNCHRONIZED_ACK)加(USE_ACK)方式來發送訊息,那麼值應該是6(4+2)或者0x0006
2、Manager

 <Manager className="org.apache.catalina.ha.session.BackupManager"
		 expireSessionsOnShutdown="false" 
		 notifyListenersOnReplication="true" 
		 mapSendOptions="6"/> 

1)管理tomcat之間的session複製
2)className當前有兩個實現類:org.apache.catalina.ha.session.DeltaManager和org.apache.catalina.ha.session.BackupManager
3)DeltaManager複製併發送Session資料到叢集下所有的節點,這個實現類被證明非常可靠、執行得非常好。不過有個侷限性就是叢集的節點型別要相同,而且要部署相同的應用程式
4)expireSessionsOnShutdown當一個web程式被結束時,tomcat分發銷燬命令到每個Session,並通知所有session listener執行。當叢集下某個節點被停止時,如果想銷燬所有節點下的的Session,設定為true,預設為false
5)notifyListenersOnReplication如果設定為true,當session屬性被複制和移動的時候,session listener被通知
3、Channel

<Channel className="org.apache.catalina.tribes.group.GroupChannel">

Channel是Apache Tribes的主元件,channel管理一組子元件,並和它們一起組成了tomcat例項間的通訊框架。在tomcat叢集中,DeltaManager通過SimpleTcpCluster呼叫channel來實現資訊傳遞,而BackupManager自己呼叫channel以及子元件這些元件來實現資訊傳遞。ReplicatedContext也會呼叫channel傳遞context屬性。
4、Membership

<Membership  className="org.apache.catalina.tribes.membership.McastService"   
			address="228.0.0.4" 
			port="45564"  
			frequency="500" 
			dropTime="3000"/> 

MemberShip元件自動檢索發現叢集裡的新節點或已經停止工作的節點,併發出相應的通知。預設使用組播(Multicast)實現。
5、Receiver

<Receiver className="org.apache.catalina.tribes.transport.nio.NioReceiver"  
			address="auto" 
			port="5000"  
			selectorTimeout="100" 
			maxThreads="6"/>

負責監聽接收其他節點傳送過來的資料。預設使用non-blocking TCP Server sockets。
6、Sender

<Sender  className="org.apache.catalina.tribes.transport.ReplicationTransmitter">  
	<Transport  className="org.apache.catalina.tribes.transport.nio.PooledParallelSender"/> 
</Sender>

管理從一個節點發送到另外一個節點的出站連線和資料資訊,允許資訊並行傳送。預設使用TCP Client Sockets。
7、Interceptor

<Interceptor  className="org.apache.catalina.tribes.group.interceptors.TcpFailureDetector"/>  <Interceptor  className="org.apache.catalina.tribes.group.interceptors.MessageDispatch15Interceptor"/>  <Interceptor  className="org.apache.catalina.tribes.group.interceptors.ThroughputInterceptor"/>  

Channel通過Interceptor堆疊進行訊息傳遞,在這裡可以自定義訊息的傳送和接收方式,甚至MemberShip的處理方式。
8、Value

<Valve className="org.apache.catalina.ha.tcp.ReplicationValve"  
	filter=".*\.gif|.*\.js|.*\.jpeg|.*\.jpg|.*\.png|.*\.htm|.*\.html|.*\.css|.*\.txt"/>

1)Value在呼叫Http Request 鏈中起著攔截器的作用,用來決定什麼情況下資料需要被複制。
org.apache.catalina.ha.tcp.ReplicationValve,ReplicationValue在Http Request結尾判斷當前資料是否需要被複制。
2)Filter內容為url或者檔案結尾,當訪問連結配置filter時,不論實際session有沒有改變,叢集會認為session沒有任何變化,從而不會複製和傳送改變的session屬性。
9、Deployer

<DeployerclassName="org.apache.catalina.ha.deploy.FarmWarDeployer" 
		tempDir="/tmp/war-temp/" 
		deployDir="/tmp/war-deploy/" 
		watchDir="/tmp/war-listen/" 
		watchEnabled="false"/>

使叢集支援farmed deployment
10、ClusterListener

<ClusterListener  className="org.apache.catalina.ha.session.ClusterSessionListener"/>

Clusterlistener用來追蹤資訊傳送和接收。
ClusterSessionListener用來監聽叢集元件接收資訊,當使用DeltaManager的時候,資訊被叢集接收,並通過ClusterSessionListener傳遞給Session Manager。

以下開始測試
先到安裝nginx目錄下 輸入測試命令驗證是否正確

#./nginx -t

然後啟動配置的N個tomcat,如果都正常啟動說明埠不衝突,可以正常使用
現在在Tomcat下webapps中的ROOT應用中新增兩個jsp頁面:test.jsp和test2.jsp。然後重啟Tomcat.
(因為本人是配置Tomcat的server.xml,進行自啟動,所以兩個jsp頁面就放到專案根路徑下便可,與WEB-INF同級即可訪問)
test.jsp

<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%> 
<%String path = request.getContextPath();  String basePath = request.getScheme()+"://"+request.getServerName()+":"+ request.getServerPort()+path+"/"; %>  
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> 
<html> 
	<head><title>應用叢集測試---session共享</title></head>
	<body>   
		<center><b>伺服器資訊</b></center> 
		<hr/>
		<% out.println("實際訪問地址:"+request.getLocalAddr() + " : "   + request.getLocalPort()+"<br>"); %> 
		<hr/>
		 // 如果有新的 Session 屬性設定 
		<% out.println("<br> Session ID: " + session.getId()+"<br><hr/>");  
		  String dataName = request.getParameter("dataName"); 
		  if (dataName != null &&dataName.length() > 0) {      
			  String dataValue = request.getParameter("dataValue");
			  session.setAttribute(dataName, dataValue);  
		  }
		  out.println("<b>Session 列表</b><br><hr/>");  
		  out.println("<table border=\"1\"><tr><td width=\"200\">屬性名稱</td><td width=\"300\">屬性值</td></tr>");  
		  System.out.println("============================");  
		  Enumeration<String> e = session.getAttributeNames(); 
		  while (e.hasMoreElements()) {       
			  String name = (String)e.nextElement();      
			  String value = session.getAttribute(name).toString();  
			  out.println("<tr><td>" +name+ "</td><td>" +value+ "</td></tr>"); 
			  System.out.println( name + " = " + value);   
		  } 
		 out.println("</table>"); %> 
		 <hr/>
		 <div>
			 <form action="test2.jsp" method="POST">  
				 <b>屬性名稱:</b><input type=text size=25 name="dataName"> 
				 &nbsp;&nbsp;&nbsp;&nbsp     
				 <b>屬性賦值:</b><input type=text size=25 name="dataValue"> 
				 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;      
				 <input type=submit value="設定屬性">     
			</form> 
		</div>
	</body> 
</html>

test2.jsp

<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%> 
<%  String path = request.getContextPath();  String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/"; %>  
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> 
<html>
	<head><title>應用叢集測試---session共享</title></head> 
	<body>   
	<%  String dataName = request.getParameter("dataName"); 
		if (dataName != null &&dataName.length() > 0) {  
			String dataValue = request.getParameter("dataValue"); 
			session.setAttribute(dataName, dataValue);  
			response.sendRedirect("test.jsp");   
		}
    %>
    </body>
</html>

此時重新整理頁面將會發現如下介面:
這裡寫圖片描述

我們回發現實際訪問的地址是發生了變化:由10.0.5.43:8801變成了:10.0.5.43:8802。SessionID除了後面的node1變成node2,具體的sessionID沒有發生變化。同時,如果在下面的表單中新增session的屬性名和屬性值,會發現session值會在5個Tomcat中實現共享。
這裡寫圖片描述

重新整理可檢視
這裡寫圖片描述
這裡寫圖片描述

此基於Nginx+Tomcat叢集的session共享的配置和校驗測試結束。

第二種方式,,**********************等下一次有時間再收集資料單獨寫一篇
Nginx+Tomcat+Redis實現session共享
Redis服務
192.168.1.178:6379

Tomcat服務
192.168.1.177:8001
192.168.1.177:8002
192.168.1.177:8003

Nginx服務
192.168.1.179

配置Tomcat讓其session儲存到redis上,在context.xml配置(Value標籤一定要在Manager標籤前面):
這裡寫圖片描述

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

配置Nginx

upstream mytomcats {  
  server 192.168.1.177:8001;   
  server 192.168.1.177:8002;  
  server 192.168.1.177:8003;   
}
log_format www_iu14_com '$remote_addr - $remote_user [$time_local] $request ' '"$status" $body_bytes_sent "$http_referer"'  '"$http_user_agent" "$http_x_forwarded_for"';   
server {  
	listen  80;   
	server_name www.iu14.com;       
	location / {           
		 proxy_pass http:// mytomcats;          
		 proxy_set_header Host $host;           
		 proxy_set_header X-Real-IP $remote_addr;           
		 proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;    
	}
	access_log /usr/tmp/logs/redis.iu14.log www_iu14_com;   
} 

依次啟動Redis、Tomcat、Nginx,訪問Nginx