02 . Tomcat集羣會話共享

redis簡介

redis是一個key-value存儲系統。和Memcached相似,它支持存儲的value類型相對更多,包括string(字符串)、list(鏈表)、set(集合)、zset(sorted set –有序集合)和hash(哈希類型)。與memcached同樣,爲了保證效率,數據都是緩存在內存中。區別的是redis會週期性的把更新的數據寫入磁盤或者把修改操做寫入追加的記錄文件,而且在此基礎上實現master-slave(主從)同步。html

Redis詳細請看我專門寫的redisjava

https://www.cnblogs.com/you-men/tag/Redis/node

如何保持session會話

目前,爲了使web能適應大規模的訪問,須要實現應用的集羣部署。集羣最有效的方案就是負載均衡,而實現負載均衡用戶每個請求都有可能被分配到不固定的服務器上,這樣咱們首先要解決session的統一來保證不管用戶的請求被轉發到哪一個服務器上都能保證用戶的正常使用,即須要實現session的共享機制。mysql

在集羣系統下實現session統一的有以下幾種方案:linux

一、請求精肯定位:sessionsticky,例如基於訪問ip的hash策略,即當前用戶的請求都集中定位到一臺服務器中,這樣單臺服務器保存了用戶的session登陸信息,若是宕機,則等同於單點部署,會丟失,會話不復制。nginx

二、session複製共享:sessionreplication,如tomcat自帶session共享,主要是指集羣環境下,多臺應用服務器之間同步session,使session保持一致,對外透明。 若是其中一臺服務器發生故障,根據負載均衡的原理,調度器會遍歷尋找可用節點,分發請求,因爲session已同步,故能保證用戶的session信息不會丟失,會話複製,。c++

此方案的不足之處:git

必須在同一種中間件之間完成(如:tomcat-tomcat之間).github

session複製帶來的性能損失會快速增長.特別是當session中保存了較大的對象,並且對象變化較快時, 性能降低更加顯著,會消耗系統性能。這種特性使得web應用的水平擴展受到了限制。web

Session內容經過廣播同步給成員,會形成網絡流量瓶頸,即使是內網瓶頸。在大併發下表現並很差

三、基於cache DB緩存的session共享

基於memcache/redis緩存的 session 共享

即便用cacheDB存取session信息,應用服務器接受新請求將session信息保存在cache DB中,當應用服務器發生故障時,調度器會遍歷尋找可用節點,分發請求,當應用服務器發現session不在本機內存時,則去cache DB中查找,若是找到則複製到本機,這樣實現session共享和高可用。

nginx+tomcat+redis實現負載均衡、session共享

環境
主機 操做系統 IP地址 硬件/網絡
Nginx CentOS7.3 39.108.140.0 1C2G / 公有云
Tomcat-1 CentOS7.3 121.36.43.2 1C2G / 公有云
Tomcat-2 CentOS7.3 49.233.69.195 1C2G / 公有云
Redis CentOS7.3 116.196.83.113 1C2G / 公有云
MySQL CentOS7.3 116.196.83.113 1C2G / 公有云
實驗拓撲

在這個圖中,nginx作爲反向代理,實現靜動分離,將客戶動態請求根據權重隨機分配給兩臺tomcat服務器,redis作爲兩臺tomcat的共享session數據服務器,mysql作爲兩臺tomcat的後端數據庫。

nginx安裝配置

使用Nginx做爲Tomcat的負載平衡器,Tomcat的會話Session數據存儲在Redis,可以實現零宕機的7x24效果。由於將會話存儲在Redis中,所以Nginx就沒必要配置成stick粘貼某個Tomcat方式,這樣才能真正實現後臺多個Tomcat負載平衡。

部署nginx

#!/usr/bin/env bash
# Author: ZhouJian
# Mail: 18621048481@163.com
# Time: 2019-9-3
# Describe: CentOS 7 Install Nginx Source Code Script

version="nginx-1.14.2.tar.gz"
user="nginx"
nginx=${version%.tar*}
path=/usr/local/src/$nginx
echo $path
if ! ping -c2 www.baidu.com &>/dev/null
then
	echo "網絡不通,沒法安裝"
	exit
fi

yum install -y gcc gcc-c++ openssl-devel pcre-devel make zlib-devel wget psmisc
if [ ! -e $version ];then
	wget http://nginx.org/download/$version
fi
if ! id $user &>/dev/null
then
	useradd $user -M -s /sbin/nologin
fi

if [ ! -d /var/tmp/nginx ];then
	mkdir -p /var/tmp/nginx/{client,proxy,fastcgi,uwsgi,scgi}
fi
tar xf $version -C /usr/local/src
cd $path
./configure \
--prefix=/usr/local/nginx \
--user=nginx \
--group=nginx \
--with-http_ssl_module \
--with-http_flv_module \
--with-http_stub_status_module \
--with-http_sub_module \
--with-http_gzip_static_module \
--with-http_auth_request_module \
--with-http_random_index_module \
--with-http_realip_module \
--http-client-body-temp-path=/var/tmp/nginx/client \
--http-proxy-temp-path=/var/tmp/nginx/proxy \
--http-fastcgi-temp-path=/var/tmp/nginx/fastcgi \
--http-uwsgi-temp-path=/var/tmp/nginx/uwsgi \
--http-scgi-temp-path=/var/tmp/nginx/scgi \
--with-pcre \
--with-file-aio \
--with-http_secure_link_module && make && make install
if [ $? -ne 0 ];then
	echo "nginx未安裝成功"
	exit
fi

killall nginx
/usr/local/nginx/sbin/nginx
#echo "/usr/local/nginx/sbin/nginx" >> /etc/rc.local
#chmod +x /etc/rc.local
#systemctl start rc-local
#systemctl enable rc-local
ss -antp |grep nginx

配置nginx反向代理:反向代理+負載均衡+健康探測,nginx.conf文件內容:

vim /usr/local/nginx/conf/nginx.conf
worker_processes  4;
events {
        worker_connections  1024;
}
    http {
        include       mime.types;
        default_type  application/octet-stream;
        sendfile        on;
        keepalive_timeout  65;
        log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
                        '$status $body_bytes_sent "$http_referer" '
                        '"$http_user_agent" "$http_x_forwarded_for"';

    #blog lb by oldboy at 201303
        upstream backend_tomcat {
        #ip_hash;
        server 192.168.6.241:8080   weight=1 max_fails=2 fail_timeout=10s;
        server 192.168.6.242:8080   weight=1 max_fails=2 fail_timeout=10s;
        #server 192.168.6.243:8080   weight=1 max_fails=2 fail_timeout=10s;
        }

        server {
            listen       80;
            server_name  www.98yz.cn;
            charset utf-8;
            location / {
                root html;
                index  index.jsp index.html index.htm;
                    }
            location ~* \.(jsp|do)$ {
            proxy_pass  http://backend_tomcat;
            proxy_redirect off;
            proxy_set_header Host $host;
            proxy_set_header X-Real-IP $remote_addr;
            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
            proxy_next_upstream error timeout invalid_header http_500 http_502 http_503 http_504;
                }
        }

    }
安裝部署tomcat應用程序服務器

在tomcat-1和tomcat-2節點上安裝JDK

在安裝tomcat以前必須先安裝JDK,JDK的全稱是java development kit,是sun公司免費提供的java語言的軟件開發工具包,其中包含java虛擬機(JVM),編寫好的java源程序通過編譯可造成java字節碼,只要安裝了JDK,就能夠利用JVM解釋這些字節碼文件,從而保證了java的跨平臺性。

安裝JDK,Tomcat 程序

tar xvf jdk-8u151-linux-x64.tar.gz -C /usr/local/
wget https://mirrors.tuna.tsinghua.edu.cn/apache/tomcat/tomcat-8/v8.5.55/bin/apache-tomcat-8.5.55.tar.gz
tar xf apache-tomcat-8.5.55.tar.gz -C /usr/local/
cd /usr/local/
mv apache-tomcat-8.5.55/ tomcat
mv jdk1.8.0_151/ jdk

按照相同方法在tomcat-2也安裝

vim conf/server.xml

// 設置默認虛擬主機,並增長jvmRoute
<Engine name="Catalina" defaultHost="localhost" jvmRoute="tomcat-1">
  
// 修改默認虛擬主機,並將網站文件路徑指向/web/webapp1,在host段增長context段  
<Host name="localhost"  appBase="webapps"
unpackWARs="true" autoDeploy="true">
<Context docBase="/web/webapp1" path="" reloadable="true"/>
</Host>
  
  
// 增長文檔目錄與測試文件  
mkdir -p /web/webapp1
cd /web/webapp1
cat index.jsp 
<%@page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<html>
    <head>
        <title>tomcat-1</title>
    </head>
    <body>
        <h1><font color="red">Session serviced by tomcat</font></h1>
        <table aligh="center" border="1">
        <tr>
            <td>Session ID</td>
            <td><%=session.getId() %></td>
                <% session.setAttribute("abc","abc");%>
            </tr>
            <tr>
            <td>Created on</td>
            <td><%= session.getCreationTime() %></td>
            </tr>
        </table>
    tomcat-1
    </body>
<html>  
  
  
// 接下來咱們將tomcat和nginx都啓動起來,能夠發現用戶訪問index.jsp會一會跳轉tomcat1,一會tomcat2,session還不一致

Tomcat-2節點與tomcat-1節點配置基本相似,只是jvmRoute不一樣,另外爲了區分由哪一個節點提供訪問,測試頁標題也不一樣(生產環境兩個tomcat服務器提供的網頁內容是相同的)。其餘的配置都相同。

用瀏覽器訪問nginx主機,驗證負載均衡

驗證健康檢查的方法能夠關掉一臺tomcat主機,用客戶端瀏覽器測試訪問。

從上面的結果能看出兩次訪問,nginx把訪問請求分別分發給了後端的tomcat-1和tomcat-2,客戶端的訪問請求實現了負載均衡,但sessionid並同樣。因此,到這裏咱們準備工做就所有完成了,下面咱們來配置tomcat經過redis實現會話保持。

安裝redis
yum -y install gcc
wget http://download.redis.io/releases/redis-4.0.14.tar.gz
tar xvf redis-4.0.14.tar.gz -C /opt/
cd /opt/redis-4.0.14

編譯安裝

# Redis的編譯,只將命令文件編譯,將會在當前目錄生成bin目錄
make && make install  PREFIX=/usr/local/redis
cd ..
mv redis-4.0.14/* /usr/local/redis/

# 建立環境變量
echo 'PATH=$PATH:/usr/local/redis/src/' >> /etc/profile
source /etc/profile

# 此時在任何目錄位置均可以是用redis-server等相關命令
[root@redis1 ~]# redis-
redis-benchmark  redis-check-rdb  redis-sentinel   redis-trib.rb    
redis-check-aof  redis-cli        redis-server

配置Redis

# 設置後臺啓動
# 因爲Redis默認是前臺啓動,不建議使用.能夠修改成後臺
daemonize yes


# 禁止protected-mode yes/no(保護模式,是否只容許本地訪問)
protected-mode


# 設置遠程訪問
# Redis默認只容許本機訪問,把bind修改成bind 0.0.0.0 此設置會變成容許全部遠程訪問,若是指定限制訪問,可設置對應IP。
# bind指定是redis所在服務器網卡的IP,不指定本機網卡IP,可能致使你的Redis實例沒法啓動
# 若是想限制IP訪問,內網的話經過網絡接口(網卡限定),讓客戶端訪問固定網卡連接redis
# 若是是公網,經過iptables指定某個IP容許訪問
bind 0.0.0.0

# 配置Redis日誌記錄
# 找到logfile,默認爲logfile "",改成自定義日誌格式
logfile  /var/log/redis_6379.log

# 把requirepass修改成123456,修改以後重啓下服務
requirepass "123456"
# 不重啓Redis設置密碼
# 在配置文件中配置requirepass的密碼(當Redis重啓時密碼依然生效)
127.0.0.1:6379> config set requirepass test123
# 查詢密碼
127.0.0.1:6379> config get requirepass
1) "requirepass"
2) "test123"

# 密碼驗證
127.0.0.1:6379> auth test123
OK
127.0.0.1:6379> set name flying
OK
127.0.0.1:6379> get name
"flying"

# 遠程主機鏈接
# redis-cli  -h  redis_ip -p redis_port -a password

啓動測試

# 放到後臺輸出,redis自帶日誌了,能夠輸出到黑洞
nohup redis-server /usr/local/redis/redis.conf &> /usr/local/redis/redis.log &

# 關閉命令
redis-cli -h 127.0.0.1 -p 6379 -a 123456 shutdown
# 注意:不建議使用 kill -9,這種方式不但不會作持久化操做,還會形成緩衝區等資源不能優雅關閉。極端狀況下形成 AOF 和 複製丟失數據 的狀況。
# shutdown 還有一個參數,表明是否在關閉 redis 前,生成 持久化文件,命令爲 redis-cli shutdown nosave|save。


# 設置開機自啓動
echo "redis-server /usr/local/redis.conf" >> /etc/rc.local
配置tomcat session redis同步

經過TomcatClusterRedisSessionManager,這種方式支持redis3.0的集羣方式
下載TomcatRedisSessionManager-2.0.zip包,https://github.com/ran-jit/tomcat-cluster-redis-session-manager,放到$TOMCAT_HOMA/lib下,並解壓

cd /usr/local/tomcat/lib/
wget https://github.com/ran-jit/tomcat-cluster-redis-session-manager/releases/download/2.0.4/tomcat-cluster-redis-session-manager.zip
unzip tomcat-cluster-redis-session-manager.zip 
cp tomcat-cluster-redis-session-manager/lib/* ./
cp tomcat-cluster-redis-session-manager/conf/redis-data-cache.properties ../conf/
cat ../conf/redis-data-cache.properties     
#-- Redis data-cache configuration
//遠端redis數據庫的地址和端口
#- redis hosts ex: 127.0.0.1:6379, 127.0.0.2:6379, 127.0.0.2:6380, ....
redis.hosts=192.168.6.244:6379
//遠端redis數據庫的鏈接密碼
#- redis password (for stand-alone mode)
redis.password=pwd@123
//是否支持集羣,默認的是關閉
#- set true to enable redis cluster mode
redis.cluster.enabled=false
//鏈接redis的那個庫
#- redis database (default 0)
#redis.database=0
//鏈接超時時間
#- redis connection timeout (default 2000)
#redis.timeout=2000
//在這個<Context>標籤裏面配置

vim ../conf/context.xml
<Valve className="tomcat.request.session.redis.SessionHandlerValve" />
<Manager className="tomcat.request.session.redis.SessionManager" />

配置會話到期時間在../conf/web.xml

<session-config>
<session-timeout>60</session-timeout>
</session-config>

啓動tomcat服務

[root@linux-node2 lib]# ../bin/startup.sh

Tomcat-2節點與tomcat-1節點配置相同

測試,咱們每次強刷他的sessionID都是一致的,因此咱們認爲他的session會話保持已經完成,大家也能夠選擇換個客戶端的IP地址來測試

相關文章
相關標籤/搜索