Nginx+Tomcat+memcached高可用會話保持

一、概述

之前文章已經描述了企業高可用負載相關的架構及實現,其中常用的nginx或haproxy,LVS結合keepalived做前端高可用調度器;但之前沒有提到會話高可用保持;
本文通過 Tomcat Session Replication Cluster(tomcat自帶)和tomcat結合memcat及第三方組件實現Tomcat Memcache Session Server高可用會話緩存服務;
實現的效果:
同一客戶端訪問業務網站,經過調度器負載調度到達後端,不管選擇的是那個後端,session ID都不變,都保存在兩臺或多臺的memcached緩存中(負載冗餘);以保持持會話;

架構圖:
Nginx+Tomcat+memcached高可用會話保持
說明:客戶端請求時nginx通過負載調度算法將請求調度至某一後端服務器;tomcat 把會話通過組播的方式複製到集羣各節點;所有節點共享會話;

Nginx+Tomcat+memcached高可用會話保持
說明:客戶端請求時nginx通過負載調度算法將請求調度至某一後端服務器;並把session存儲到兩臺memcached中;客戶端刷新(不換瀏覽器)時,請求換成另一個後端服務器響應時session ID保持不變;

測試環境:
nginx: CentOS7 epel 安裝nginx WAN:172.16.3.152 LAN:192.168.10.254
tomcat A: CentOS7 node1.san.com epel 安裝 tomcat 7 openjdk-1.8.0 memcached(現實環境中單獨服務器)
tomcat B: CentOS7 nodde2.san.com epel 安裝 tomcat 7 openjdk-1.8.0 memcached 現實環境中單獨服務器)
測試客戶端ubuntu 16.04

cat /etc/hosts
172.16.3.152       www.san.com

二、安裝配置集羣

nginx安裝

[root@nginx ~]# yum install epel-release -y
[root@nginx ~]# yum install nginx -y

nginx配置
在/etc/nginx/nginx.conf http段添加如下行

    upstream tcsrvs {
        server 192.168.10.11:8080;
        server 192.168.10.12:8080;
        }

cat /etc/nginx/conf.d/san.com.conf

[root@nginx ~]# cat /etc/nginx/conf.d/san.com.conf 
server {
            listen 80;
            server_name www.san.com;
            location / {
                proxy_pass http://tcsrvs;
                }
        }

Tomcat配置:
兩臺均需要安裝

#yum install epel-release -y
#yum install java-1.8.0 java-1.8.0-openjdk-devel tomcat tomcat-webapps tomcat-admin-webapps tomcat-docs-webapp  -y

說明:也可以通過oracle官方下載jdk 下載tomcat 解壓到指定目錄並添加環境變量;一般企業推薦此種方式;爲了快捷,我們用epel倉庫中的穩定版本;

添加測試頁
yum 安裝的tomcat工作目錄在/var/lib/tomcat/webapps 分別在node1與node2上,此目錄下創建測試項目,title 分別叫Tomcat A與Tomcat B 顏色分別爲green與red;以示區別;生產環境node1 與node2內容一致;這裏爲了測試區別node1與node2內容;

#mkdir -pv /var/lib/tomcat/webapps/test/{WEB-INF,META-INF,classes,lib}
#cat /var/lib/tomcat/webapps/test/index.jsp
<%@ page language="java" %>
 <html>
      <head><title>Tomcat A</title></head>
          <body>
             <h1><font color="red">TomcatA.san.com</font></h1>
           <table align="centre" border="1">
            <tr>
                <td>Session ID</td>
            <% session.setAttribute("san.com","san.com"); %>
            <td><%= session.getId() %></td>
            </tr>
            <tr>
            <td>Created on</td>
           <td><%= session.getCreationTime() %></td>
           </tr>
      </table>
    </body>
</html>

配置管理頁密碼
tomcat與管理程序安裝好後配置訪問密碼
修改註釋/etc/tomcat/tomcat-users.xml文件

<role rolename="admin-gui"/>
<role rolename="manager-gui"/>
<user username="tomcat" password="tomcat" roles="manager-gui,admin-gui"/>

備份默認/etc/tomcat/server.xml文件

cd /etc/tomcat
cp server.xml server.xml_def

測試頁訪問
http://www.san.com/test 如圖:出現Tomcat A
Nginx+Tomcat+memcached高可用會話保持
Ctrl+F5強制刷新 又出現Tomcat B
Nginx+Tomcat+memcached高可用會話保持

引發問題:如果是兩臺內容一樣的配置,客戶端訪問刷新一下就換到另一個後端處理;類似通過session保留信息的服務(購買物車)如何保留?換句話說,如何保持會話不中斷,無論請求被分配到那一個後端?

解決方案
1)會話sticky(粘性):分爲source_ip 基於源ip和cookie
source_ip在不同的調度器上有不同的實現方式:
lvs:sh算法;
nginx:ip_hash或hash $request_uri consistent(一致性哈希算法)
haproxy: source

cookie:
nginx:hash 或 hash $cookie_name consistent;
haproxy:cookie

2)會話集羣(session cluster):delta session manager
3)session server: redis(store),memcached(cache)

以下基於tomcat自帶會話集羣與memcached實現會話保持 功能;

三、Tomcat Session Replication Cluster配置

Tomcat Session Replication Cluster中文又叫 tomcat 會話複製集羣,即會話通過組播方式複製到每一個後端tomcat節點;
可參考自帶幫助文檔:http://www.san.com/docs/cluster-howto.html
兩臺node1 node2節點/etc/hosts中添加如下:

#cat /etc/hosts
192.168.10.11 node1.san.com node1
192.168.10.12 node2.san.com node2

兩臺tomcat 節點sever.xml的Host字段中添加如下內容:

<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">
            <Membership className="org.apache.catalina.tribes.membership.McastService"
                        address="228.10.0.4"
                        port="45564"
                        frequency="500"
                        dropTime="3000"/>
            <Receiver className="org.apache.catalina.tribes.transport.nio.NioReceiver"
                      address="auto"           <!--   如果沒有/etc/hosts解析則需要本機ip   -->
                      port="4000"
                      autoBind="100"
                      selectorTimeout="5000"
                      maxThreads="6"/>

            <Sender className="org.apache.catalina.tribes.transport.ReplicationTransmitter">
              <Transport className="org.apache.catalina.tribes.transport.nio.PooledParallelSender"/>
            </Sender>
            <Interceptor className="org.apache.catalina.tribes.group.interceptors.TcpFailureDetector"/>
            <Interceptor className="org.apache.catalina.tribes.group.interceptors.MessageDispatch15Interceptor"/>
          </Channel>

          <Valve className="org.apache.catalina.ha.tcp.ReplicationValve"
                 filter=""/>
          <Valve className="org.apache.catalina.ha.session.JvmRouteBinderValve"/>

          <Deployer className="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>

複製 /etc/tomcat/web.xml /var/lib/tomcat/webapps/test/WEB-INF/ 下並在web.xml的"<web-app >"字段下添加 "<distributable/>";
重啓tomcat 並再次訪問http://www.san.com/test 如圖:
Nginx+Tomcat+memcached高可用會話保持
Ctrl + F5強制刷新如圖:
Nginx+Tomcat+memcached高可用會話保持
可以可出會話得到保持,只要是從同一個客戶端中請求,刷新或關閉重新打開(基於同一個瀏覽器) 只要會話沒有過期,會話(session id) 無論來自那個後端,均是一樣;

缺點:
tomcat自帶支持會話集羣(能過多播方式發送各節點);但有一個缺點;後端tomcat節點過多時效率低下,不適用大規模;

四、Tomcat Memcache Session Server高可用配置

原理說明:
客戶端請求到達前端nginx調度器並分配到後端某tomcat節點時,tomcat會優先使用本機內存保存session,當一個請求結束後,tomcat會通過第三方組件(kryo,javolution,xstream,flexjson)把session序列化併發送到memcached節點上存放作備份,第二次請求時,如果本地有session就直接返回,第二次請求結束,把session修改後的信息更新到後端的memcached服務器,以這樣的方式來保持本地的session與memcached上的session同步。當這個tomcat節點宕機時,那麼用戶的下一次請求就會被前端的負載均衡器路由到另一個tomcat節點上,而這個節點上並沒有這個用戶的session信息,這個節點就從memcached服務器上去讀取session,並把session保存到本地的內存,當請求結束,session又被修改,再送回到memcached進行存放備份
當後端配置了多臺memcached時,tomcat在更新session信息時會同時向多個memcached節點更新session,當一個memcached節點故障時,tomcat可以從選擇一個正常工作的memcached節點讀取session信息來發送給用戶的瀏覽器,讓其重置session信息,這樣,memcached也達到了高可用的目的;
以下操作均在兩臺node上操作
還原默認配置文件

#cd /etc/tomcat/
#cp server.xml server.xml_cluster
#cp server.xml_def server.xml
#systemctl stop tomcat

安裝memcached服務

#yum install memcached -y
#systemctl start memcached

memcache配置(默認即可,生產環境時需要加大內存與併發連接數)

# cat /etc/sysconfig/memcached 
PORT="11211"
USER="memcached"
MAXCONN="1024"
CACHESIZE="64"
OPTIONS=""

兩臺/etc/tomcat/server.xml Host段中添加如下內容:

<Context path="/test" docBase="test" reloadable="true">
        <Manager className="de.javakaffee.web.msm.MemcachedBackupSessionManager"
                memcachedNodes="m1:192.168.10.11:11211,m2:192.168.10.12:11211"
                failoverNodes="m1"
                requestUriIgnorePattern=".*\.(ico|png|gif|jpg|css|js)$"
                transcoderFactoryClass="de.javakaffee.web.msm.serializer.javolution.JavolutionTranscoderFactory"/>
        </Context>

說明:
添加兩個冗餘備份memcached節點分別叫m1,m2 failoverNodes="m1" 表示m1作爲備份;當m2失敗時連接;即使用m2;

安裝對應版本組件

下載以下JAR包到tomcat庫目錄;
cd /usr/share/tomcat/lib 
wget http://www.java2s.com/Code/JarDownload/javolution/javolution-5.5.1.jar.zip  
#需要解壓 unzip javolution-5.5.1.jar.zip
wget http://repo1.maven.org/maven2/net/spy/spymemcached/2.12.1/spymemcached-2.12.1.jar
wget http://repo1.maven.org/maven2/de/javakaffee/msm/msm-javolution-serializer/2.1.1/msm-javolution-serializer-2.1.1.jar
wget http://repo1.maven.org/maven2/de/javakaffee/msm/memcached-session-manager-tc7/2.1.1/memcached-session-manager-tc7-2.1.1.jar
wget http://repo1.maven.org/maven2/de/javakaffee/msm/memcached-session-manager/2.1.1/memcached-session-manager-2.1.1.jar

注意:epel安裝的tomcat 和openjdk版本如下:
openjdk: "1.8.0_161"
tomcat : "7.0.76"
以上第三方插件須和對應的版本是兼容的;如發現tomcat啓動有問題;無法訪問或如下類似錯誤

#tail -fn 100 /var/log/tomcat/catalina.xxxx.log
三月 23, 2018 4:12:52 下午 org.apache.catalina.core.StandardContext startInternal
嚴重: The session manager failed to start
org.apache.catalina.LifecycleException: Failed to start component [de.javakaffee.web.msm.MemcachedBackupSessionManager[/test]]
    at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:162)
    at org.apache.catalina.core.StandardContext.startInternal(StandardContext.java:5643)
    at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:145)

則表示第三方組件與tomcat不兼容!請重新下載版本;

測試:
瀏覽器訪問http://www.san.com/test 如圖:
Nginx+Tomcat+memcached高可用會話保持
Ctrl+F5強刷新 如圖:
Nginx+Tomcat+memcached高可用會話保持

從測試上可以看出目前已經通過memcache存儲session等緩存信息;並同步到兩臺memcache上;當前只使用m2節點;

總結:

通過nginx快速實現負載tomcat應用;引用session不可保持問題;通過自帶的Tomcat Session Replication Cluster和結合memcached及第三方組件實現高可用會話緩存服務來保持會話;前者不適合大規模應用;

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