1. 程式人生 > 實用技巧 >【轉】Nginx叢集Tomcat時session共享問題

【轉】Nginx叢集Tomcat時session共享問題

描述

  nginx實現tomcat集群后會出現這樣的情形,登入時請求由tomcat1處理,而跳轉到首頁時負載到了tomcat2,而tomcat2中又沒有tomcat1中的登入資訊,又會需要登入,這樣會造成登入死迴圈。如何解決呢?

方法一:複製session資訊

原理:講道理,這個方法比較蠢,就是有幾個tomcat,就複製幾個session,只要有一個tomcat中的session發生變化,其他tomcat中的session跟著複製變化,保證所有使用者的session在所有的tomcat中都存在而且相同。這樣一來無論使用者的請求被分配到哪個tomcat都是無所謂的,因為所有的tomcat中都有他們存放的session。

實現:

1、修改server.xml檔案:將Cluster的註釋去掉

Cluster標籤為tomcat叢集的配置。

2、開啟自己專案的web.xml(不是tomcat/conf/web.xml),增加distributable。表明叢集下某一節點生成或改變的session,將廣播到該叢集的其它節點。

優點:實現簡單,沒有什麼花裡胡哨的操作。如果叢集的tomcat不多,而且使用者沒有那麼多的時候可以選擇這種方式。

缺點:只要Session資料有變化,就需要將資料同步到所有其他機器上,機器越多,同步帶來的網路頻寬開銷就越大;當用戶很多時,每臺機器用於儲存Session資料的內容佔用會很嚴重。

方法二:ip繫結

原理:使用nginx中的ip_hash負載均衡演算法,它能夠將某個ip的請求定向到同一臺後端,這樣一來這個ip下的某個客戶端和某個後端就能建立起穩固的session

優點:實現比較簡單,修改一下nginx的配置檔案,reload即可。

缺點:ip_hash要求nginx一定是最前端的伺服器,否則nginx得不到正確ip,就不能根據ip作hash。譬如nginx前面還有硬體負載均衡器,那麼nginx取ip時只能得到硬體負載均衡器的ip地址,用這個地址來作分流肯定是錯亂的。

方法三:tomcat-redis-session-manager

版本:apache-tomcat-8.0.32、nginx-1.13.12、redis-3.2.1

github地址:https://github.com/mzd123/session_manager 讀者可以直接下載體驗一下。

實現:

1、下載:https://github.com/ran-jit/tomcat-cluster-redis-session-manager/wiki

2、解壓之後,將jar包放入tomcat的lib中(注意是tomcat/lib中,不是我們自己專案的lib

3、配置解壓只夠的redis-data-cache.properties(根據你的redis配置吧)。配置完將這個檔案放入tomcat/conf資料夾中。

4、配置tomcat/conf/context.xml,增加如下兩行。

5、注意:因為tomcat-redis-session-manager這個版本的不同,classname會隨著變化,2.0.4的版本是叫這兩個。其實可以開啟你下載的tomcat-cluster-redis-session-manager.jar看看他到底叫什麼(不少小夥伴,本人第一次搞也是,網上程式碼一抄,發現tomcat啟動就報類找不到。。。你classname都填錯了,當然找不到了,能找到就奇怪了。。。)

測試:

1、nginx配置:

upstream mzd{
       server 127.0.0.1:8091;
       server 127.0.0.1:8090;
    }

    server {
        listen       80;
        server_name  www.tuesdayma.com;

        location / {
            proxy_pass http://mzd;
            proxy_connect_timeout 3s;
            proxy_read_timeout 5s;
            proxy_send_timeout 3s;
            index  index.html index.htm;
        }
        error_page   500 502 503 504  /50x.html;
        location = /50x.html {
            root   html;
        }


    }

2、準備兩個tomcat,一個埠為8090,一個為8091

3、tomcat中jsp程式碼:

<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>  
<%@ page language="java" import="java.text.SimpleDateFormat"%>
<%  
  request.getSession().setAttribute("mzd","123");
  SimpleDateFormat simpleDateFormat=new SimpleDateFormat("YYYY-MM-dd HH:mm:ss");
  String date=simpleDateFormat.format(new Date());
%>  

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">  
<html>  
  <head>   
    <title>tomcat1</title>  
  </head>  
  <body>  
        SessionID:<%=session.getId()%>  
        <BR>  
        當前時間為:<%=date%>  
        <BR>  
        SessionPort:<%=request.getServerPort()%>  
        <BR>  
        mzd的值為:<%=session.getAttribute("mzd")%>  
       <BR>  
        <%  
        out.println("這是tomcat1");  
        %> 
  </body>  
</html>  
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%> 
<%@ page language="java" import="java.text.SimpleDateFormat"%>
<%  
   SimpleDateFormat simpleDateFormat=new SimpleDateFormat("YYYY-MM-dd HH:mm:ss");
   String date=simpleDateFormat.format(new Date());
%>  
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">  
<html>  
  <head>   
      <title>tomcat2</title>  
  </head>  
  <body>  
        SessionID:<%=session.getId()%>  
        <BR>  
        當前時間為:<%=date%>  
        <BR>  
        SessionPort:<%=request.getServerPort()%>  
        <BR>  
        mzd的值為:<%=session.getAttribute("mzd")%>  
       <BR>  
        <%  
        out.println("這是tomcat2");  
        %> 
  </body>  
</html>  

4、啟動兩個tomcat和redis:如果不啟動redis是會報錯的

結果:

測試結果很明顯,sessionid沒有改變。而且在tomcat1中設定的mzd值在tomcat2中jsp也能拿到這個值。

方法四:使用jwt

原理:放棄session機制,使用jwt機制。簡單來說就是userid+隨機數+簽名加密生成一個token,前後端通訊通過token來互動。客戶端第一次請求登入之後,伺服器端給客戶端一個token,伺服器將token作為key值,userid作為value值,30分鐘作為有效時間存入redis中;客戶端第二次訪問controller之前進行攔截,判斷是否有token,如果有token解密獲取userid,然後去查詢redis,token和userid是否匹配,如果匹配就允許訪問controller,請求返回之後,伺服器將重新生成新的token返回給客戶端。簡單來說就是每次請求成功之後token都會改變,token存在redis中,這樣一來至於redis分發到哪個tomat並不影響,因為token是存在redis中的。

轉載自《nginx叢集tomcat,session共享問題