前言¶
本篇文章將介紹如何搭建使用Nginx和Tomcat的高可用高併發的網站,我們將會在CentOS系統上搭建這樣一個網站後端。這個系統的架構如下:

- 虛擬IP地址:192.168.204.221
- 主虛擬服務器:192.168.204.121
- 備虛擬服務器:192.168.204.122
- Nginx服務器1:192.168.204.123
- Nginx服務器2:192.168.204.124
- Tomcat服務器1:192.168.204.123
- Tomcat服務器2:192.168.204.124
創建CentOS虛擬機¶
我們這次安裝的虛擬機是CentOS迷你版,鏡像爲:CentOS-6.5-x86_64-minimal.iso,該鏡像可以到這裏下載:http://vault.centos.org/6.5/isos/x86_64/CentOS-6.5-x86_64-minimal.iso。參考筆者的這一篇文章CentOS搭建雲服務平臺的前半部分創建4個CentOS虛擬機,用來模仿後臺的多個系統,要注意的是這篇文章CentOS搭建雲服務平臺安裝的的桌面版,我們在本文章用的迷你版,但是安裝步驟差不多,可以參考b部分的安裝操作。關於創建CentOS虛擬機就不用重複介紹了,主要是說明這四個虛擬機的網絡配置。當然讀者的網段跟讀者的可能不一樣,所以讀者要根據自己的情況配置網絡。
node1的網絡配置:
DEVICE=eth0
TYPE=Ethernet
ONBOOT=yes
NM_CONTROLLED=yes
BOOTPROTO=static
IPADDR=192.168.204.121
NETMASK=255.255.255.0
GATEWAY=192.168.204.2
node2的網絡配置:
DEVICE=eth0
TYPE=Ethernet
ONBOOT=yes
NM_CONTROLLED=yes
BOOTPROTO=static
IPADDR=192.168.204.122
NETMASK=255.255.255.0
GATEWAY=192.168.204.2
node3的網絡配置:
DEVICE=eth0
TYPE=Ethernet
ONBOOT=yes
NM_CONTROLLED=yes
BOOTPROTO=static
IPADDR=192.168.204.123
NETMASK=255.255.255.0
GATEWAY=192.168.204.2
node4的網絡配置:
DEVICE=eth0
TYPE=Ethernet
ONBOOT=yes
NM_CONTROLLED=yes
BOOTPROTO=static
IPADDR=192.168.204.124
NETMASK=255.255.255.0
GATEWAY=192.168.204.2
安裝Nginx¶
接下來是安裝Nginx服務器,這個也是一個完整的服務器,可以當做普通的網站服務器。但是在這個結構中,我們是使用它來做反向代理,使它代理更多的Tomcat,在起分流的同時,也有高可用的作用,因爲就算一個Nginx服務器泵機了,還有其他的運行。我們在node3和node4的虛擬機下安裝Nginx。
安裝Nginx之前,先要安裝依賴庫:
yum -y install gcc openssl-devel pcre-devel zlib-devel
如果沒有安裝wget命令,要先安裝這個命令,因爲下面會用到這個命令:
yum -y install wget
下載Nginx並放在/opt下:
cd /opt
wget http://tengine.taobao.org/download/tengine-2.1.0.tar.gz
解壓Nginx壓縮包:
tar -zxvf tengine-2.1.0.tar.gz
進入到剛纔解壓得到的文件夾tengine-2.1.0,開始配置tengine,配置命令如下:
./configure \
--prefix=/opt/sxt/soft/tengine-2.1.0/ \
--error-log-path=/var/log/nginx/error.log \
--http-log-path=/var/log/nginx/access.log \
--pid-path=/var/run/nginx/nginx.pid \
--lock-path=/var/lock/nginx.lock \
--with-http_ssl_module \
--with-http_flv_module \
--with-http_stub_status_module \
--with-http_gzip_static_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/fcgi/ \
--http-uwsgi-temp-path=/var/tmp/nginx/uwsgi \
--http-scgi-temp-path=/var/tmp/nginx/scgi \
--with-pcre
配置完成之後,開始安裝,執行安裝之後,tengine會安裝在/opt/sxt/soft/tengine-2.1.0/目錄下:
make && make install
使用vim命令創建一個文件/etc/init.d/nginx用於啓動服務的,並添加以下內容:
#!/bin/bash
#
# chkconfig: - 85 15
# description: nginx is a World Wide Web server. It is used to serve
# Source function library.
. /etc/rc.d/init.d/functions
# Source networking configuration.
. /etc/sysconfig/network
# Check that networking is up.
[ "$NETWORKING" = "no" ] && exit 0
nginx="/opt/sxt/soft/tengine-2.1.0/sbin/nginx"
prog=$(basename $nginx)
NGINX_CONF_FILE="/opt/sxt/soft/tengine-2.1.0/conf/nginx.conf"
#[ -f /etc/sysconfig/nginx ] && . /etc/sysconfig/nginx
lockfile=/var/lock/subsys/nginx
start() {
[ -x $nginx ] || exit 5
[ -f $NGINX_CONF_FILE ] || exit 6
echo -n $"Starting $prog: "
daemon $nginx -c $NGINX_CONF_FILE
retval=$?
echo
[ $retval -eq 0 ] && touch $lockfile
return $retval
}
stop() {
echo -n $"Stopping $prog: "
killproc $prog -QUIT
retval=$?
echo
[ $retval -eq 0 ] && rm -f $lockfile
return $retval
}
restart() {
configtest || return $?
stop
sleep 1
start
}
reload() {
configtest || return $?
echo -n $"Reloading $prog: "
# -HUP是nginx平滑重啓參數
killproc $nginx -HUP
RETVAL=$?
echo
}
force_reload() {
restart
}
configtest() {
$nginx -t -c $NGINX_CONF_FILE
}
rh_status() {
status $prog
}
rh_status_q() {
rh_status >/dev/null 2>&1
}
case "$1" in
start)
rh_status_q && exit 0
$1
;;
stop)
rh_status_q || exit 0
$1
;;
restart|configtest)
$1
;;
reload)
rh_status_q || exit 7
$1
;;
force-reload)
force_reload
;;
status)
rh_status
;;
condrestart|try-restart)
rh_status_q || exit 0
;;
*)
echo $"Usage: $0 {start|stop|status|restart|condrestart|try-restart|reload|force-reload|configtest}"
exit 2
esac
然後對剛纔創建的文件分配權限:
chmod +x /etc/init.d/nginx
添加該文件到系統服務中
chkconfig --add /etc/init.d/nginx
查看是否添加成功:
chkconfig --list nginx
創建一個臨時目錄:
mkdir -p /var/tmp/nginx/client/
啓動Nginx:
service nginx start
關閉防火牆:
service iptables stop
最後輸入對應的IP地址,就可以訪問Nginx的網站了:
http://192.168.204.123
http://192.168.204.124
安裝Tomcat¶
接下來就是安裝我們最終的服務器,Tomcat服務器是我們真正部署網站的服務器,因爲我們搭建的是一個Java web網站。所以這一部分介紹如何在CentOS下安裝Tomcat。我們在node3和node4的虛擬機下安裝Tomcat,理論上面Tomcat不應該是跟Nginx同一個機器的,但是由於筆者的電腦安裝不了那麼多的虛擬機,就暫且公用一個機器。
首先要先有Java環境,先是下載JDK:
wget --no-check-certificate --no-cookies --header "Cookie: oraclelicense=accept-securebackup-cookie" http://download.oracle.com/otn-pub/java/jdk/8u131-b11/d54c1d3a095b4ff2b6607d096fa80163/jdk-8u131-linux-x64.rpm
下載完成之後可以進行安裝JDK:
rpm -ivh jdk-8u131-linux-x64.rpm
安裝完成之後,可以使用以下命令檢測安裝版本,如果正常輸出版本信息,那證明安裝成功了:
java -version
在/opt中下載Tomcat壓縮包:
cd /opt
wget http://mirrors.hust.edu.cn/apache/tomcat/tomcat-7/v7.0.88/bin/apache-tomcat-7.0.88.tar.gz
下載完成之後,要解壓Tomcat:
tar -zxvf apache-tomcat-7.0.88.tar.gz
解壓之後可以得到一個文件夾apache-tomcat-7.0.88,然後我們可以啓動Tomcat:
cd /opt/apache-tomcat-7.0.88/bin
./startup.sh
如果需要外界訪問的話,還要關閉防火牆:
service iptables stop
訪問網網站:
http://192.168.204.123:8080
http://192.168.204.124:8080
安裝lvs和keepalived¶
我們安裝lvs和keepalived是爲了保證高可用,首先使用l可以設置虛擬IP,這樣我們就可以只需要訪問一個虛擬IP就可以訪問所有的服務器了。keepalived是爲了保證虛擬服務器一直在運行,當主服務器掛掉了,馬上就啓動備用服務器,以確保網站一直正常運行。以下的操作在node1和node2下操作。
一、配置負載均衡服務器
首先安裝lvs和keepalived,命令如下:
yum -y install ipvsadm keepalived
備份keepalived的配置文件,如果以後需要還可以使用:
cp -a /etc/keepalived/keepalived.conf /etc/keepalived/backup.keepalived.conf
在主的負載均衡服務器中編輯配置文件/etc/keepalived/keepalived.conf,清空裏面的內容,加入以下的配置信息:
! Configuration File for keepalived
global_defs {
notification_email {
root@localhost #發送提醒郵件的目標地址可有多個
goldbin@126.com
}
notification_email_from test@localhost #發送郵件的from地址,可以隨意寫,郵件地址不存在都無所謂
smtp_server 127.0.0.1 #郵件服務的地址,一般寫本地
smtp_connect_timeout 30
router_id LVS_DEVEL
}
vrrp_instance VI_1 {
state MASTER # MASTER 主 和 BACKUP 從
interface eth0 #VIP需要綁定的網卡名稱
virtual_router_id 51
priority 101 #優先級 主的優先級要高
advert_int 1
authentication {
auth_type PASS
auth_pass 1111
}
virtual_ipaddress {
192.168.204.221/24 dev eth0 label eth0:0 #設置VIP
}
}
virtual_server 192.168.204.221 80 { #設置虛擬lvs服務,VIP PORT
delay_loop 6
lb_algo rr #調度算法wrr
lb_kind DR #lvs的模式
nat_mask 255.255.255.0
persistence_timeout 50 #同一個IP地址在50秒內lvs轉發給同一個後端服務器
protocol TCP
real_server 192.168.204.123 80 { #設置真實服務器的心跳機制 RID PORT
weight 1 #權重
HTTP_GET { #心跳檢測的方式
url {
path / #心跳檢查的地址
status_code 200 #心跳檢查返回的狀態
}
connect_timeout 2 #超時時間
nb_get_retry 3 #重複檢查3次
delay_before_retry 1 #每隔1秒鐘再次檢查
}
}
real_server 192.168.204.124 80 { #第二個真實服務器設置
weight 1
HTTP_GET {
url {
path /
status_code 200
}
connect_timeout 2
nb_get_retry 3
delay_before_retry 1
}
}
}
在備的負載均衡服務器中同樣以上的配置方式,但需要修改兩個地方,一個是state設置爲BACKUP,也就是備用的意思。另一個是priority,這個是優先級,需要設置比主的要低。
vrrp_instance VI_1 {
state BACKUP # MASTER 主 和 BACKUP 從
interface eth0 #VIP需要綁定的網卡名稱
virtual_router_id 51
priority 50 #優先級 主的優先級要高
advert_int 1
authentication {
auth_type PASS
auth_pass 1111
}
virtual_ipaddress {
192.168.204.221/24 dev eth0 label eth0:0 #設置VIP
}
}
配置好keepalived之後就可以啓動它了,命令如下:
service keepalived start
然後使用ipvsadm -L查看映射的IP地址,啓動一會再查看,因爲可能不會那麼快就映射,正常的話應該輸出以下信息,主備虛擬服務器都是一樣:
IP Virtual Server version 1.2.1 (size=4096)
Prot LocalAddress:Port Scheduler Flags
-> RemoteAddress:Port Forward Weight ActiveConn InActConn
TCP 192.168.204.221:http rr persistent 50
-> 192.168.204.123:http Route 1 0 0
-> 192.168.204.124:http Route 1 0 2
二、配置真實服務器
負載均衡服務器(虛擬服務器)設置好了,然後就可以設置真實服務器(Nginx服務器)了。通過命令輸入有點麻煩,我們可以編寫一個腳本,讓它來幫我們處理這些。node3和node4這個兩真實服務器都要配置,創建文件vim realserver.sh並添加以下信息:
#!/bin/bash
#description: Config realserver
VIP=192.168.204.221
/etc/rc.d/init.d/functions
case "$1" in
start)
/sbin/ifconfig lo:0 $VIP netmask 255.255.255.255 broadcast $VIP
/sbin/route add -host $VIP dev lo:0
echo "1" >/proc/sys/net/ipv4/conf/lo/arp_ignore
echo "2" >/proc/sys/net/ipv4/conf/lo/arp_announce
echo "1" >/proc/sys/net/ipv4/conf/all/arp_ignore
echo "2" >/proc/sys/net/ipv4/conf/all/arp_announce
sysctl -p >/dev/null 2>&1
echo "RealServer Start OK"
;;
stop)
/sbin/ifconfig lo:0 down
/sbin/route del $VIP >/dev/null 2>&1
echo "0" >/proc/sys/net/ipv4/conf/lo/arp_ignore
echo "0" >/proc/sys/net/ipv4/conf/lo/arp_announce
echo "0" >/proc/sys/net/ipv4/conf/all/arp_ignore
echo "0" >/proc/sys/net/ipv4/conf/all/arp_announce
echo "RealServer Stoped"
;;
*)
echo "Usage: $0 {start|stop}"
exit 1
esac
exit 0
然後執行這個腳本就可以自動配置了,命令如下:
sh realserver.sh start
然後使用ifconfig查看是否有添加以下網絡信息:
lo:0 Link encap:Local Loopback
inet addr:192.168.204.221 Mask:255.255.255.255
UP LOOPBACK RUNNING MTU:16436 Metric:1
安裝完成之後,可以測試是否可以正常工作,如何還沒啓動Nginx,首先啓動Nginx:
service nginx start
需要關閉防火牆:
service iptables stop
最後我們只需要通過虛擬IP地址就可以訪問真實服務器了。
http://192.168.204.221
我們可以手動關閉keepalived,觀察是否會自動啓動備的服務器。這就是keepalived的作用,當主服務器掛了,會自動啓動備虛擬服務器來指向真實服務器。
service keepalived stop
反向代理¶
我們希望是使用Nginx來代理更多的Tomcat服務器,來對用戶進行分流,以應對高併發時對單個服務器的壓力。所以我們要設置node3和node4的Nginx。
要配置這個反向代理,只要修改一個配置文件就可以了。如下:
vim /opt/sxt/soft/tengine-2.1.0/conf/nginx.conf
我們主要是添加upstream cluster1這個內容,這就是反向代理的服務器IP地址,同時也可以設置健康檢查的配置信息。
然後要在server中添加反向代理,還可以創建對各個代理的服務器進行健康檢查location /status。其他的地方不用修改。
upstream cluster1 {
# 服務器訪問的路徑,可以指定多個服務器
server 192.168.204.123:8080;
server 192.168.204.124:8080;
# 健康檢查
check interval=3000 rise=2 fall=5 timeout=1000 type=http;
check_http_send "HEAD / HTTP/1.0\r\n\r\n";
check_http_expect_alive http_2xx http_3xx;
}
server {
listen 80;
server_name localhost;
# 根目錄訪問路徑
location / {
# 指定反向代理,跟上面的名稱一樣cluster1
proxy_pass http://cluster1;
root html;
index index.html index.htm;
}
# 健康檢查路徑
location /status {
check_status;
}
}
修改配置文件之後,需要重啓Nginx:
service nginx restart
在訪問之前,要確保Tomcat是正常啓動了,因爲我們是反向代理了Tomcat的服務器,所以需要啓動Tomcat服務器。
如果在訪問路徑的時候加上健康檢查的路徑/status,就可查看各個服務器的健康問題。
http://192.168.204.123/status
http://192.168.204.124/status
通過訪問上面的地址就可以看到類似以下的頁面信息:

最後我們在正常訪問Nginx服務器的時候,就會訪問都Tomcat服務器了。而且Nginx是訪問到多個Tomcat。
比如筆者只是訪問其中的一個Nginx,如下:
http://192.168.204.123


上面是訪問Nginx服務器的IP地址的,我們在安裝lvs和keepalived這部分設置了虛擬IP,所以我們可以直接訪問這個虛擬IP就可以了。最終網站只需要訪問一個IP地址就可以了:
http://192.168.204.221/

部署網站¶
經過上面的搭建,已經組建好一個高可用高併發的的服務器,現在我們只要把Java web項目部署到Tomcat服務器就可以。接下來我們編寫一個簡單的實現登錄的網站。
搭建數據庫¶
我們使用的是MySQL數據庫,所以我們需要先安裝MySQL數據庫,然後對它進行一些配置就可以使用。現在我們在node4服務器上操作。
我們可以使用以下命令查看MySQL是否安裝了:
rpm -qa | grep mysql
應該會輸出一下日誌:
[root@localhost ~]# rpm -qa | grep mysql
mysql-libs-5.1.71-1.el6.x86_64
然後我們可以先移除這個MySQL,重新安裝一個:
yum -y remove mysql-libs-5.1.71-1.el6.x86_64
移除之前的MySQL之後,可以重新安裝MySQL:
yum -y install mysql-server mysql mysql-devel
最後在查看安裝情況:
rpm -qa | grep mysql
正常的應該會輸出以下信息:
mysql-5.1.73-8.el6_8.x86_64
mysql-libs-5.1.73-8.el6_8.x86_64
mysql-server-5.1.73-8.el6_8.x86_64
mysql-devel-5.1.73-8.el6_8.x86_64
如果已經安裝了MySQL,那麼我們可以直接啓動MySQL:
service mysqld start
然後我們可以把MySQL服務添加到開機自動啓,這樣就不用每次都啓動了。
chkconfig mysqld on
我們可以使用以下的命令查看是否成功添加到開機服務中了。
chkconfig --list | grep mysqld
設置MySQL數據庫的密碼:
mysqladmin -u root password 'root'
登錄數據庫,輸入該命令之後還有輸入數據庫的密碼,這個密碼就是上面設置的root:
mysql -u root -p
因爲我們的網站是在其他的服務器,當連接這個數據庫的話,就是遠程連接數據庫了,所以要設置數據庫支持遠程連接,在登錄數據庫之後輸入以下命令:
mysql> GRANT ALL PRIVILEGES ON *.* TO 'root'@'%' IDENTIFIED BY 'root' WITH GRANT OPTION;
mysql> FLUSH PRIVILEGES;
配置好數據庫之後,就可以創建數據表了,我們在MySQL自帶的test數據庫上面創建一張user表。
首先我們可以使用命令查看當前有那些數據庫了:
mysql> SHOW DATABASES;
以下是輸出信息,可以看到有3個數據庫,我們使用test數據庫作爲我們的項目數據庫:
+--------------------+
| Database |
+--------------------+
| information_schema |
| mysql |
| test |
+--------------------+
3 rows in set (0.01 sec)
然後我們使用test數據庫,開始創建數據表。
mysql> USE test
然後在這個數據庫中創建一個user表,這個表只要兩個字段。
mysql> CREATE TABLE user(`number` VARCHAR(100) NOT NULL, `password` VARCHAR(100) NOT NULL);
然後在user表中添加一條數據,方便之後的登錄。
mysql> INSERT INTO user(number, password) VALUES('hello', 'world');
然後我們查詢看看有沒有添加成功數據:
mysql> select * from user;
可以看到已經成功添加數據了:
+--------+----------+
| number | password |
+--------+----------+
| hello | world |
+--------+----------+
1 row in set (0.00 sec)
編寫網站項目¶
我們這項目比較簡單,只有登錄功能。雖然是簡單,但是完全可以測試整個網站的運行情況了。我們主要的創建3個頁面和一個Servlet,具體代碼如下:
index.jsp代碼,主要完成登錄頁面:
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>登錄</title>
</head>
<body>
<form action="/Test2/login" method="post">
賬號:<input type="text" name="number"><br>
密碼:<input type="password" name="password"><br>
<button type="submit">登錄</button>
</form>
</body>
</html>
success.jsp代碼,主要是完成登錄成功頁面,可以在session中獲取登錄成功的用戶名:
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>登錄成功</title>
</head>
<body>
<h1>登錄成功,歡迎<% out.print(session.getAttribute("number"));%></h1>
</body>
</html>
fail.jsp代碼,登錄失敗頁面:
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>登錄失敗</title>
</head>
<body>
<h1>登錄失敗</h1>
</body>
</html>
LoginServlet.java代碼,登錄驗證Servlet:
package com.test.test;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.IOException;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
@WebServlet(name = "LoginServlet",urlPatterns = {"/login"})
public class LoginServlet extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
this.doGet(request, response);
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
ConnectionDBUtil dbUtil = new ConnectionDBUtil();
String number = request.getParameter("number");
String password = request.getParameter("password");
String sql = "SELECT * FROM user WHERE number = ? AND password = ?";
Boolean result = false;
try {
PreparedStatement ps = dbUtil.getConn().prepareStatement(sql);
ps.setString(1, number);
ps.setString(2, password);
ResultSet rs = ps.executeQuery();
while (rs.next()) {
result = true;
}
ps.close();
} catch (SQLException e) {
e.printStackTrace();
}
dbUtil.closeConn();
if (result){
HttpSession session = request.getSession();
session.setAttribute("number", number);
response.sendRedirect("/Test2/success.jsp");
}else {
response.sendRedirect("/Test2/fail.jsp");
}
}
}
ConnectionDBUtil.jsp代碼,主要的用於連接數據庫的工具,別忘了還要導入連接數據庫的jar包mysql-connector-java-5.1.46-bin.jar。我們連接數據庫的node4的數據庫,所以IP地址是192.168.204.124。
package com.test.test;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
public class ConnectionDBUtil {
private Connection conn= null;
private static final String DBURL = "jdbc:mysql://192.168.204.124:3306/test";
private static final String DBUSER = "root";
private static final String DBPASSWD = "root";
public ConnectionDBUtil(){
try {
Class.forName("com.mysql.jdbc.Driver");
conn = DriverManager.getConnection(DBURL, DBUSER, DBPASSWD);
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (SQLException e) {
e.printStackTrace();
}
}
public Connection getConn(){
return conn;
}
public void closeConn(){
if (conn != null){
try {
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}
然後使用這些代碼在開發環境上編譯,得到一個war的文件或者是文件夾,然後我們把這個文件或者文件夾放在node3和node4的Tomcat服務器上,目錄爲/opt/apache-tomcat-7.0.88/webapps。最後可以在瀏覽器上訪問我們的虛擬IP地址加上項目名稱就可以訪問到這個網站了。如下:
http://192.168.204.221/Test2/
這個是登錄的頁面:

這個是登錄成功的頁面,在這裏就可以看到登錄成功的用戶名:

這個是登錄失敗的頁面:

這個就是我們的網站項目,雖然是簡單,但是我們已經讓這個項目在我們的高可用高併發的服務器上正常運行工作了。這個已經證明我們的服務器已經可以正常工作了。
解決session一致性¶
現在有一個問題,就是我們的Tomcat服務器有好幾個,而且都不在同一個機器上,那問題就來了。我們使用session保存了用戶名,但是當我們在次訪問的時候,也行不是原來的那個Tomcat服務器,那之前保存的session就不存在了,我們可以驗證看看。
這個是我們的登錄成功的界面,我們在登錄成功之後,會把用戶名保存的session中。然後在這個頁面就可以查看到,但是我們通過不斷刷新,可以看到用戶名有時候會爲空,這就是去到了其他的Tomcat服務器,也就沒有了之前保存的session。
在當前登錄成功的服務器上:

已經去到其他服務器了:

那麼我們現在就來解決這個session一致性問題。我們是使用Redis來解決session一致性的。以下操作在node3和node4下操作。
下載session一致性的jar包,把裏面的三個jar包複製到Tomcat的lib目錄下,路徑如下:
cd /opt/apache-tomcat-7.0.88/lib/
然後編輯server.xml配置文件,node3和node4都要操作:
vim /opt/apache-tomcat-7.0.61/conf/server.xml
第一個Tomcat的上找到Engine,然後在上面加上jvmRoute="tomcat1",同樣在第二個Tomcat加上jvmRoute="tomcat2",如下:
<Engine name="Catalina" defaultHost="localhost" jvmRoute="tomcat1">
<!--For clustering, please take a look at documentation at:
/docs/cluster-howto.html (simple how to)
/docs/config/cluster.html (reference documentation) -->
<Engine name="Catalina" defaultHost="localhost" jvmRoute="tomcat2">
<!--For clustering, please take a look at documentation at:
/docs/cluster-howto.html (simple how to)
/docs/config/cluster.html (reference documentation) -->
然後編輯context.xml配置文件,node3和node4都要操作:
vim /opt/apache-tomcat-7.0.61/conf/context.xml
在<Context>和</Context>之間添加如下內容,其中host是Redis所在的服務器,筆者在node3上安裝Redis,所以這裏是node3的IP地址。
<Valve className="com.orangefunction.tomcat.redissessions.RedisSessionHandlerValve" />
<Manager className="com.orangefunction.tomcat.redissessions.RedisSessionManager"
host="192.168.204.123"
port="6379"
database="0"
maxInactiveInterval="60" />
上面說到Redis緩存數據庫,所以我們還有安裝Redis緩存數據庫。我們在node3上安裝Redis緩存數據庫。
cd /opt/
wget http://download.redis.io/releases/redis-4.0.2.tar.gz
tar -zxvf redis-4.0.2.tar.gz
cd redis-4.0.2
make
make install
安裝完成之後,我們編輯vim /opt/redis-4.0.2/redis.conf這個配置文件,修改裏面的bind地址,把地址改成node3的IP地址。如下:
# bind 127.0.0.1
bind 192.168.204.123
然後就可以啓動Redis了,注意這裏要回車兩次。
/opt/redis-4.0.2/src/redis-server /opt/redis-4.0.2/redis.conf &
啓動的界面如下:
[root@node3 src]# /opt/redis-4.0.2/src/redis-server /opt/redis-4.0.2/redis.conf &
[2] 4809
[1] Done /opt/redis-4.0.2/src/redis-server redis.conf (wd: /opt/redis-4.0.2)
(wd now: /opt/redis-4.0.2/src)
[root@node3 src]# 4809:C 22 Jun 16:21:13.162 # oO0OoO0OoO0Oo Redis is starting oO0OoO0OoO0Oo
4809:C 22 Jun 16:21:13.162 # Redis version=4.0.2, bits=64, commit=00000000, modified=0, pid=4809, just started
4809:C 22 Jun 16:21:13.162 # Configuration loaded
4809:M 22 Jun 16:21:13.165 * Increased maximum number of open files to 10032 (it was originally set to 1024).
_._
_.-``__ ''-._
_.-`` `. `_. ''-._ Redis 4.0.2 (00000000/0) 64 bit
.-`` .-```. ```\/ _.,_ ''-._
( ' , .-` | `, ) Running in standalone mode
|`-._`-...-` __...-.``-._|'` _.-'| Port: 6379
| `-._ `._ / _.-' | PID: 4809
`-._ `-._ `-./ _.-' _.-'
|`-._`-._ `-.__.-' _.-'_.-'|
| `-._`-._ _.-'_.-' | http://redis.io
`-._ `-._`-.__.-'_.-' _.-'
|`-._`-._ `-.__.-' _.-'_.-'|
| `-._`-._ _.-'_.-' |
`-._ `-._`-.__.-'_.-' _.-'
`-._ `-.__.-' _.-'
`-._ _.-'
`-.__.-'
4809:M 22 Jun 16:21:13.171 # WARNING: The TCP backlog setting of 511 cannot be enforced because /proc/sys/net/core/somaxconn is set to the lower value of 128.
4809:M 22 Jun 16:21:13.171 # Server initialized
最後啓動Tomcat服務器就可以了,如果之前已經啓動過了,需要關閉Tomcat再重新啓動,node3和node4都需要。
啓動之後,再重新登錄,在登錄成功頁面無論我們如何刷新都會顯示用戶名,這是因爲我們已經保持了每一個Tomcat的session都是一一致的。

本章是介紹網站的邏輯部分的分佈式部署,要應對真實的高併發還有對數據庫做分佈式部署,以應對龐大的數據查詢。在下一章的《CentOS下安裝和使用Mycat實現分佈式數據庫》介紹如何在CentOS上部署分佈式數據庫。
注意¶
這裏要說一下的是,我們爲了方便外界可以訪問到服務器的端口,我們把防火牆關閉了,但是這種是非常不安全的。所以我們可以單獨開放某一端口,比如我們要開放MySQL數據庫的3306端口號,操作如下:
編輯防火牆配置文件:
vim /etc/sysconfig/iptables
添加以下信息:
-A INPUT -m state --state NEW -m tcp -p tcp --dport 3306 -j ACCEPT
如下圖所示:

保存退出,最後重啓防火牆:
service iptables restart
開放其他端口也是同樣的操作。
參考資料¶
- https://blog.csdn.net/u010392801/article/details/52085394
- https://blog.csdn.net/u012852986/article/details/52412174
- https://blog.csdn.net/love_zngy/article/details/78581995
- https://www.cnblogs.com/renzhicai/p/7773080.html
- https://blog.csdn.net/ymf827311945/article/details/76461115