Linux redis緩存服務(wù)器(Nginx+Tomcat+redis+MySQL實(shí)現(xiàn)session會(huì)話共享)

2018-07-31 14:45 更新

防偽碼:我想是我因?yàn)槲也粔驕厝?,不能分?dān)你的憂愁。

一、redis介紹

redis是一個(gè)key-value存儲(chǔ)系統(tǒng)。和Memcached類似,它支持存儲(chǔ)的value類型相對(duì)更多,包括string(字符串)、list(鏈表)、set(集合)、zset(sorted set --有序集合)和hash(哈希類型)。與memcached一樣,為了保證效率,數(shù)據(jù)都是緩存在內(nèi)存中。區(qū)別的是redis會(huì)周期性的把更新的數(shù)據(jù)寫入磁盤或者把修改操作寫入追加的記錄文件,并且在此基礎(chǔ)上實(shí)現(xiàn)master-slave(主從)同步。

Redis是一個(gè)高性能的key-value數(shù)據(jù)庫(kù)。redis的出現(xiàn),很大程度補(bǔ)償了memcached這類key/value存儲(chǔ)的不足,在部分場(chǎng)合可以對(duì)關(guān)系數(shù)據(jù)庫(kù)起到很好的補(bǔ)充作用。它提供了Java,C/C++,C#,PHP,JavaScript,Perl,Object-C,Python,Ruby等客戶端,使用很方便。

如果簡(jiǎn)單地比較Redis與Memcached的區(qū)別,基本上有以下3點(diǎn):
1、Redis不僅僅支持簡(jiǎn)單的k/v類型的數(shù)據(jù),同時(shí)還提供list,set,zset,hash等
數(shù)據(jù)結(jié)構(gòu)的存儲(chǔ)。
2、Redis支持?jǐn)?shù)據(jù)的備份,即master-slave模式的數(shù)據(jù)備份。
3、Redis支持?jǐn)?shù)據(jù)的持久化,可以將內(nèi)存中的數(shù)據(jù)保持在磁盤中,重啟的時(shí)候可以再次加載進(jìn)行使用。

在Redis中,并不是所有的數(shù)據(jù)都一直存儲(chǔ)在內(nèi)存中的。這是和Memcached相比一個(gè)最大的區(qū)別。Redis只會(huì)緩存所有的key的信息,如果Redis發(fā)現(xiàn)內(nèi)存的使用量超過(guò)了某一個(gè)閥值,將觸發(fā)swap的操作,Redis根據(jù)“swappability = age*log(size_in_memory)”計(jì)算出哪些key對(duì)應(yīng)的value需要swap到磁盤。然后再將這些key對(duì)應(yīng)的value持久化到磁盤中,同時(shí)在內(nèi)存中清除。這種特性使得Redis可以保持超過(guò)其機(jī)器本身內(nèi)存大小的數(shù)據(jù)。當(dāng)然,機(jī)器本身的內(nèi)存必須要能夠保持所有的key,因?yàn)檫@些數(shù)據(jù)是不會(huì)進(jìn)行swap操作的。

當(dāng)從Redis中讀取數(shù)據(jù)的時(shí)候,如果讀取的key對(duì)應(yīng)的value不在內(nèi)存中,那么Redis就需要從swap文件中加載相應(yīng)數(shù)據(jù),然后再返回給請(qǐng)求方。

memcached和redis的比較

1、網(wǎng)絡(luò)IO模型

Memcached是多線程,非阻塞IO復(fù)用的網(wǎng)絡(luò)模型,分為監(jiān)聽(tīng)主線程和worker子線程,監(jiān)聽(tīng)線程監(jiān)聽(tīng)網(wǎng)絡(luò)連接,接受請(qǐng)求后,將連接描述字pipe 傳遞給worker線程,進(jìn)行讀寫IO, 網(wǎng)絡(luò)層使用libevent封裝的事件庫(kù),多線程模型可以發(fā)揮多核作用。

Redis使用單線程的IO復(fù)用模型,自己封裝了一個(gè)簡(jiǎn)單的AeEvent事件處理框架,主要實(shí)現(xiàn)了epoll、kqueue和select,對(duì)于單純只有IO操作來(lái)說(shuō),單線程可以將速度優(yōu)勢(shì)發(fā)揮到最大,但是Redis也提供了一些簡(jiǎn)單的計(jì)算功能,比如排序、聚合等,對(duì)于這些操作,單線程模型實(shí)際會(huì)嚴(yán)重影響整體吞吐量,CPU計(jì)算過(guò)程中,整個(gè)IO調(diào)度都是被阻塞住的。

2、內(nèi)存管理方面

Memcached使用預(yù)分配的內(nèi)存池的方式,使用slab和大小不同的chunk來(lái)管理內(nèi)存,value根據(jù)大小選擇合適的chunk存儲(chǔ)。Redis使用現(xiàn)場(chǎng)申請(qǐng)內(nèi)存的方式來(lái)存儲(chǔ)數(shù)據(jù)。

3、存儲(chǔ)方式及其它方面

Memcached基本只支持簡(jiǎn)單的key-value存儲(chǔ),不支持持久化和復(fù)制等功能,Redis除key/value之外,還支持list,set,sortedset,hash等眾多數(shù)據(jù)結(jié)構(gòu)

 

二、如何保持session會(huì)話

目前,為了使web能適應(yīng)大規(guī)模的訪問(wèn),需要實(shí)現(xiàn)應(yīng)用的集群部署。集群最有效的方案就是負(fù)載均衡,而實(shí)現(xiàn)負(fù)載均衡用戶每一個(gè)請(qǐng)求都有可能被分配到不固定的服務(wù)器上,這樣我們首先要解決session的統(tǒng)一來(lái)保證無(wú)論用戶的請(qǐng)求被轉(zhuǎn)發(fā)到哪個(gè)服務(wù)器上都能保證用戶的正常使用,即需要實(shí)現(xiàn)session的共享機(jī)制。

在集群系統(tǒng)下實(shí)現(xiàn)session統(tǒng)一的有如下幾種方案:

1、請(qǐng)求精確定位:sessionsticky,例如基于訪問(wèn)ip的hash策略,即當(dāng)前用戶的請(qǐng)求都集中定位到一臺(tái)服務(wù)器中,這樣單臺(tái)服務(wù)器保存了用戶的session登錄信息,如果宕機(jī),則等同于單點(diǎn)部署,會(huì)丟失,會(huì)話不復(fù)制。

2、session復(fù)制共享:sessionreplication,如tomcat自帶session共享,主要是指集群環(huán)境下,多臺(tái)應(yīng)用服務(wù)器之間同步session,使session保持一致,對(duì)外透明。 如果其中一臺(tái)服務(wù)器發(fā)生故障,根據(jù)負(fù)載均衡的原理,調(diào)度器會(huì)遍歷尋找可用節(jié)點(diǎn),分發(fā)請(qǐng)求,由于session已同步,故能保證用戶的session信息不會(huì)丟失,會(huì)話復(fù)制,。

此方案的不足之處:

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

session復(fù)制帶來(lái)的性能損失會(huì)快速增加.特別是當(dāng)session中保存了較大的對(duì)象,而且對(duì)象變化較快時(shí), 性能下降更加顯著,會(huì)消耗系統(tǒng)性能。這種特性使得web應(yīng)用的水平擴(kuò)展受到了限制。

Session內(nèi)容通過(guò)廣播同步給成員,會(huì)造成網(wǎng)絡(luò)流量瓶頸,即便是內(nèi)網(wǎng)瓶頸。在大并發(fā)下表現(xiàn)并不好

3、基于cache DB緩存的session共享

基于memcache/redis緩存的 session 共享

即使用cacheDB存取session信息,應(yīng)用服務(wù)器接受新請(qǐng)求將session信息保存在cache DB中,當(dāng)應(yīng)用服務(wù)器發(fā)生故障時(shí),調(diào)度器會(huì)遍歷尋找可用節(jié)點(diǎn),分發(fā)請(qǐng)求,當(dāng)應(yīng)用服務(wù)器發(fā)現(xiàn)session不在本機(jī)內(nèi)存時(shí),則去cache DB中查找,如果找到則復(fù)制到本機(jī),這樣實(shí)現(xiàn)session共享和高可用。

 

三、nginx+tomcat+redis實(shí)現(xiàn)負(fù)載均衡、session共享

1、實(shí)驗(yàn)環(huán)境

主機(jī)

操作系統(tǒng)

IP地址

Nginx

Centos7.2

192.168.31.141

Tomcat-1

192.168.31.83

Tomcat-2

192.168.31.250

Mysql

192.168.31.225

Redis

192.168.31.106


2、實(shí)驗(yàn)拓?fù)?/span>


在這個(gè)圖中,nginx做為反向代理,實(shí)現(xiàn)靜動(dòng)分離,將客戶動(dòng)態(tài)請(qǐng)求根據(jù)權(quán)重隨機(jī)分配給兩臺(tái)tomcat服務(wù)器,redis做為兩臺(tái)tomcat的共享session數(shù)據(jù)服務(wù)器,mysql做為兩臺(tái)tomcat的后端數(shù)據(jù)庫(kù)。

3、nginx安裝配置

使用Nginx作為Tomcat的負(fù)載平衡器,Tomcat的會(huì)話Session數(shù)據(jù)存儲(chǔ)在Redis,能夠?qū)崿F(xiàn)零宕機(jī)的7x24效果。因?yàn)閷?huì)話存儲(chǔ)在Redis中,因此Nginx就不必配置成stick粘貼某個(gè)Tomcat方式,這樣才能真正實(shí)現(xiàn)后臺(tái)多個(gè)Tomcat負(fù)載平衡。

安裝nginx:

安裝zlib-devel、pcre-devel等依賴包

1
[root@www ~]# yum -y install gccgcc-c++ make libtoolzlibzlib-develpcrepcre-developensslopenssl-devel

注:

結(jié)合proxy和upstream模塊實(shí)現(xiàn)后端web負(fù)載均衡

結(jié)合nginx默認(rèn)自帶的ngx_http_proxy_module模塊 和ngx_http_upstream_module模塊實(shí)現(xiàn)后端服務(wù)器的健康檢查

創(chuàng)建nginx程序用戶

1
[root@www ~]# useradd -s /sbin/nologin www

編譯安裝nginx

[root@www ~]# tar zxf nginx-1.10.2.tar.gz

1
2
3
4
[root@www ~]# cd nginx-1.10.2/
[root@www nginx-1.10.2]# ./configure --prefix=/usr/local/nginx1.10 --user=www --group=www --with-http_stub_status_module --with-http_realip_module --with-http_ssl_module
--with-http_gzip_static_module  --with-pcre  --with-http_flv_module
[root@www nginx-1.10.2]# make&& make install

優(yōu)化nginx程序的執(zhí)行路徑

1
2
3
4
[root@www nginx-1.10.2]# ln -s /usr/local/nginx1.10/sbin/nginx /usr/local/sbin/
[root@www nginx-1.10.2]# nginx -t
nginx: the configuration file /usr/local/nginx1.10/conf/nginx.conf syntax is ok
nginx: configuration file /usr/local/nginx1.10/conf/nginx.conf test is successful

編寫nginx服務(wù)腳本:腳本內(nèi)容如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
[root@www ~]# cat /etc/init.d/nginx
#!/bin/bash
# nginx Startup script for the Nginx HTTP Server
# chkconfig: - 85 15
# pidfile: /usr/local/nginx1.10/logs/nginx.pid
# config: /usr/local/nginx1.10/conf/nginx.conf
nginxd=/usr/local/nginx1.10/sbin/nginx
nginx_config=/usr/local/nginx1.10/conf/nginx.conf
nginx_pid=/usr/local/nginx1.10/logs/nginx.pid
RETVAL=0
prog="nginx"
# Source function library.
/etc/rc.d/init.d/functions
# Start nginx daemons functions.
start() {
if [ -f $nginx_pid ] ; then
echo "nginx already running...."
exit 1
fi
echo -n "Starting $prog: "
   $nginxd -c ${nginx_config}
   RETVAL=$?
[ $RETVAL = 0 ] && touch /var/lock/subsys/nginx
}
# Stop nginx daemons functions.
stop() {
echo -n "Stopping $prog: "
        $nginxd -s stop
        RETVAL=$?
[ $RETVAL = 0 ] &&rm -f /var/lock/subsys/nginx
}
# reloadnginx service functions.
reload() {
echo -n "Reloading $prog: "
    $nginxd -s reload
}
# statusngnx service functions
status() {
if [ -f $nginx_pid ] ; then
echo  "$prog is running"
else
echo  "$prog is stop"
fi
}
case "$1" in
start)
start
        ;;
stop)
stop
        ;;
reload)
reload
        ;;
restart)
stop
start
        ;;
status)
status
        ;;
*)
echo "Usage: $prog {start|stop|restart|reload|status}"
exit 1
        ;;
esac
[root@www ~]# chmod +x /etc/init.d/nginx
[root@www ~]# chkconfig --add nginx
[root@www ~]# chkconfignginx on
[root@www ~]# systemctl daemon-reload

配置nginx反向代理:反向代理+負(fù)載均衡+健康探測(cè),nginx.conf文件內(nèi)容:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
[root@www ~]# cat /usr/local/nginx1.10/conf/nginx.conf
user  wwwwww;
worker_processes  4;
worker_cpu_affinity 0001 0010 0100 1000;
error_log  logs/error.log;
#error_log  logs/error.log  notice;
#error_log  logs/error.log  info;
worker_rlimit_nofile 10240;
pid        logs/nginx.pid;
events {
useepoll;
worker_connections  4096;
}
http {
includemime.types;
default_type  application/octet-stream;
log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
                      '$status $body_bytes_sent "$http_referer" '
                      '"$http_user_agent" "$http_x_forwarded_for"';
access_log  logs/access.log  main;
server_tokens off;
sendfile        on;
tcp_nopush     on;
    #keepalive_timeout  0;
keepalive_timeout  65;
    #Compression Settings
gzip on;
gzip_comp_level 6;
gzip_http_version 1.1;
gzip_proxied any;
gzip_min_length 1k;
gzip_buffers 16 8k;
gzip_types text/plain text/css text/javascript application/json application/javascript application/x-javascript application/xml;
gzip_vary on;
    #end gzip
    # http_proxy Settings
client_max_body_size   10m;
client_body_buffer_size   128k;
proxy_connect_timeout   75;
proxy_send_timeout   75;
proxy_read_timeout   75;
proxy_buffer_size   4k;
proxy_buffers   4 32k;
proxy_busy_buffers_size   64k;
proxy_temp_file_write_size  64k;
    #load balance Settings
upstreambackend_tomcat {
server 192.168.31.83:8080 weight=1 max_fails=2 fail_timeout=10s;
server 192.168.31.250:8080 weight=1 max_fails=2 fail_timeout=10s;
    }
    #virtual host Settings
server {
listen       80;
server_name  www.benet.com;
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;
        }
location /nginx_status {
stub_status on;
access_log off;
allow 192.168.31.0/24;
deny all;
        }
    }
}

重啟nginx服務(wù),使修改生效

1
[root@www ~]# service  nginx restart

配置防火墻規(guī)測(cè)

1
2
3
4
[root@www ~]# firewall-cmd --permanent --add-port=80/tcp
success
[root@www ~]# firewall-cmd --reload 
success

4、安裝部署tomcat應(yīng)用程序服務(wù)器

在tomcat-1和tomcat-2節(jié)點(diǎn)上安裝JDK

在安裝tomcat之前必須先安裝JDK,JDK的全稱是java  development kit,是sun公司免費(fèi)提供的java語(yǔ)言的軟件開發(fā)工具包,其中包含java虛擬機(jī)(JVM),編寫好的java源程序經(jīng)過(guò)編譯可形成java字節(jié)碼,只要安裝了JDK,就可以利用JVM解釋這些字節(jié)碼文件,從而保證了java的跨平臺(tái)性。

安裝JDK,配置java環(huán)境:

將jdk-7u65-linux-x64.gz解壓

1
[root@tomcat-1 ~]# tar zxf jdk-7u65-linux-x64.gz

將解壓的jdk1.7.0_65目錄移致動(dòng)到/usr/local/下并重命名為java

1
[root@tomcat-1 ~]# mv jdk1.7.0_65/ /usr/local/java

在/etc/profile文件中添加內(nèi)容如下:

1
2
export JAVA_HOME=/usr/local/java
export PATH=$JAVA_HOME/bin:$PATH

通過(guò)source命令執(zhí)行profile文件,使其生效。

1
2
3
[root@tomcat-1 ~]# source /etc/profile
[root@tomcat-1 ~]# echo $PATH
/usr/local/java/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/root/bin

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

分別在在tomcat-1和tomcat-2節(jié)點(diǎn)運(yùn)行java  -version命令查看java版本是否和之前安裝的一致。

1
2
3
4
[root@tomcat-1 ~]# java -version
java version "1.7.0_65"
Java(TM) SE Runtime Environment (build 1.7.0_65-b17)
Java HotSpot(TM) 64-Bit Server VM (build 24.65-b04, mixed mode)

至此java環(huán)境已經(jīng)配置完成

在tomcat-1和tomcat-2節(jié)點(diǎn)安裝配置tomcat

解壓apache-tomcat-7.0.54.tar.gz包

1
[root@tomcat-1 ~]# tar zxf apache-tomcat-7.0.54.tar.gz

將解壓生成的文件夾移動(dòng)到/usr/local/下,并改名為tomcat7

1
[root@tomcat-1 ~]# mv apache-tomcat-7.0.54 /usr/local/tomcat7

配置tomcat環(huán)境變量

/etc/profile文件內(nèi)容如下:

1
2
3
export JAVA_HOME=/usr/local/java
export CATALINA_HOME=/usr/local/tomcat7
export PATH=$JAVA_HOME/bin:$CATALINA_HOME/bin:$PATH

通過(guò)source命令執(zhí)行profile文件,使其生效。

1
2
3
[root@tomcat-1 ~]# source /etc/profile
[root@tomcat-1 ~]# echo $PATH
/usr/local/java/bin:/usr/local/tomcat7/bin:/usr/local/java/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/root/bin

查看tomcat的版本信息

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
[root@tomcat-1 ~]# catalina.sh version
Using CATALINA_BASE:   /usr/local/tomcat7
Using CATALINA_HOME:   /usr/local/tomcat7
Using CATALINA_TMPDIR: /usr/local/tomcat7/temp
Using JRE_HOME:        /usr/local/java
Using CLASSPATH:       /usr/local/tomcat7/bin/bootstrap.jar:/usr/local/tomcat7/bin/tomcat-juli.jar
Server version: Apache Tomcat/7.0.54
Server built:   May 19 2014 10:26:15
Server number:  7.0.54.0
OS Name:        Linux
OS Version:     3.10.0-327.el7.x86_64
Architecture:   amd64
JVM Version:    1.7.0_65-b17
JVM Vendor:     Oracle Corporation
啟動(dòng)tomcat
[root@tomcat-1 ~]# /usr/local/tomcat7/bin/startup.sh 
Using CATALINA_BASE:   /usr/local/tomcat7
Using CATALINA_HOME:   /usr/local/tomcat7
Using CATALINA_TMPDIR: /usr/local/tomcat7/temp
Using JRE_HOME:        /usr/local/java
Using CLASSPATH:       /usr/local/tomcat7/bin/bootstrap.jar:/usr/local/tomcat7/bin/tomcat-juli.jar
Tomcat started.

Tomcat默認(rèn)運(yùn)行在8080端口,運(yùn)行netstat命令查看8080端口監(jiān)聽(tīng)的信息

1
2
3
[root@tomcat-1 ~]# netstat -anpt | grep java
tcp6       0      0 :::8009      :::*                    LISTEN      42330/java          
tcp6       0      0 :::8080      :::*                    LISTEN      42330/java

防火墻規(guī)則配置:

1
2
3
4
[root@tomcat-1 ~]# firewall-cmd --permanent --add-port=8080/tcp
success
[root@tomcat-1 ~]# firewall-cmd --reload
success

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

打開瀏覽器分別對(duì)tomcat-1和tomcat-2訪問(wèn)測(cè)試

如果想關(guān)閉tomcat則運(yùn)行/usr/local/tomcat7/bin/shutdown.sh命令

好了,大家可以看到訪成功。說(shuō)明我們的tomcat安裝完成,下面我們來(lái)修改配置文件

1
2
[root@tomcat-1 ~]# vim /usr/local/tomcat
7/conf/server.xml

設(shè)置默認(rèn)虛擬主機(jī),并增加jvmRoute

1
<Engine name="Catalina" defaultHost="localhost" jvmRoute="tomcat-1">

修改默認(rèn)虛擬主機(jī),并將網(wǎng)站文件路徑指向/web/webapp1,在host段增加context段

1
2
3
4
<Host name="localhost"  appBase="webapps"
unpackWARs="true" autoDeploy="true">
<Context docBase="/web/webapp1" path="" reloadable="true"/>
</Host>

增加文檔目錄與測(cè)試文件

1
2
3
[root@tomcat-1 ~]# mkdir -p /web/webapp1
[root@tomcat-1 ~]# cd /web/webapp1/
[root@ tomcat-1 webapp1]# viindex.jsp

index.jsp內(nèi)容如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<%@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>
</body>
<html>

停止tomcat運(yùn)行,檢查配置文件并啟動(dòng)tomcat

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
[root@tomcat-1 ~]# shutdown.sh
[root@tomcat-1 ~]# netstat -anpt | grep java
[root@tomcat-1 ~]# catalina.shconfigtest
Using CATALINA_BASE:   /usr/local/tomcat7
Using CATALINA_HOME:   /usr/local/tomcat7
Using CATALINA_TMPDIR: /usr/local/tomcat7/temp
Using JRE_HOME:        /usr/local/java
Using CLASSPATH:       /usr/local/tomcat7/bin/bootstrap.jar:/usr/local/tomcat7/bin/tomcat-juli.jar
Nov 16, 2016 1:04:05 AM org.apache.catalina.core.AprLifecycleListenerinit
INFO: The APR based Apache Tomcat Native library which allows optimal performance in production environments was not found on the java.library.path: /usr/java/packages/lib/amd64:/usr/lib64:/lib64:/lib:/usr/lib
Nov 16, 2016 1:04:05 AM org.apache.coyote.AbstractProtocolinit
INFO: Initializing ProtocolHandler ["http-bio-8080"]
Nov 16, 2016 1:04:05 AM org.apache.coyote.AbstractProtocolinit
INFO: Initializing ProtocolHandler ["ajp-bio-8009"]
Nov 16, 2016 1:04:05 AM org.apache.catalina.startup.Catalina load
INFO: Initialization processed in 534 ms
[root@tomcat-1 ~]# startup.sh 
Using CATALINA_BASE:   /usr/local/tomcat7
Using CATALINA_HOME:   /usr/local/tomcat7
Using CATALINA_TMPDIR: /usr/local/tomcat7/temp
Using JRE_HOME:        /usr/local/java
Using CLASSPATH:       /usr/local/tomcat7/bin/bootstrap.jar:/usr/local/tomcat7/bin/tomcat-juli.jar
Tomcat started.
[root@tomcat-1 ~]# netstat -anpt | grep java
tcp6       0      0 :::8009    :::*                    LISTEN      8180/java           
tcp6       0      0 :::8080    :::*                    LISTEN      8180/java

Tomcat-2節(jié)點(diǎn)與tomcat-1節(jié)點(diǎn)配置基本類似,只是jvmRoute不同,另外為了區(qū)分由哪個(gè)節(jié)點(diǎn)提供訪問(wèn),測(cè)試頁(yè)標(biāo)題也不同(生產(chǎn)環(huán)境兩個(gè)tomcat服務(wù)器提供的網(wǎng)頁(yè)內(nèi)容是相同的)。其他的配置都相同。

用瀏覽器訪問(wèn)nginx主機(jī),驗(yàn)證負(fù)載均衡

第一次訪問(wèn)的結(jié)果

第二次訪問(wèn)的結(jié)果

驗(yàn)證健康檢查的方法可以關(guān)掉一臺(tái)tomcat主機(jī),用客戶端瀏覽器測(cè)試訪問(wèn)。

從上面的結(jié)果能看出兩次訪問(wèn),nginx把訪問(wèn)請(qǐng)求分別分發(fā)給了后端的tomcat-1和tomcat-2,客戶端的訪問(wèn)請(qǐng)求實(shí)現(xiàn)了負(fù)載均衡,但sessionid并一樣。所以,到這里我們準(zhǔn)備工作就全部完成了,下面我們來(lái)配置tomcat通過(guò)redis實(shí)現(xiàn)會(huì)話保持。

5、安裝redis

下載redis源碼,并進(jìn)行相關(guān)操作,如下:

1
2
wget 
http://download.redis.io/releases/redis-3.2.3.tar.gz

解壓安裝redis

1
[root@redis ~]# tar zxf redis-3.2.3.tar.gz

解壓完畢后,現(xiàn)在開始安裝,如下:

1
2
[root@redis ~]# cd redis-3.2.3/
[root@redis redis-3.2.3]# make&& make install

通過(guò)上圖,我們可以很容易的看出,redis安裝到/usr/local,/usr/local/bin,/usr/local/share,/usr/local/include,/usr/local/lib,/usr/local/share/man目錄下。

然后再切換到utils目錄下,執(zhí)行redis初始化腳本install_server.sh,如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
[root@redis redis-3.2.3]# cdutils/
[root@redisutils]# ./install_server.sh
Welcome to the redis service installer
This script will help you easily set up a running redis server
  
Please select the redis port for this instance: [6379] 
Selecting default: 6379
Please select the redisconfig file name [/etc/redis/6379.conf] 
Selected default - /etc/redis/6379.conf
Please select the redis log file name [/var/log/redis_6379.log]
Selected default - /var/log/redis_6379.log
Please select the data directory for this instance [/var/lib/redis/6379
Selected default - /var/lib/redis/6379
Please select the redis executable path [/usr/local/bin/redis-server
Selected config:
Port           : 6379
Config file    /etc/redis/6379.conf
Log file       /var/log/redis_6379.log
Data dir       /var/lib/redis/6379
Executable     : /usr/local/bin/redis-server
CliExecutable : /usr/local/bin/redis-cli
Is this ok? Then press ENTER to go on or Ctrl-C to abort.
Copied /tmp/6379.conf => /etc/init.d/redis_6379
Installing service...
Successfully added to chkconfig!
Successfully added to runlevels 345!
Starting Redis server...
Installation successful!

通過(guò)上面的安裝過(guò)程,我們可以看出redis初始化后redis配置文件為/etc/redis/6379.conf,日志文件為/var/log/redis_6379.log,數(shù)據(jù)文件dump.rdb存放到/var/lib/redis/6379目錄下,啟動(dòng)腳本為/etc/init.d/redis_6379。

現(xiàn)在我們要使用systemd,所以在 /etc/systems/system 下創(chuàng)建一個(gè)單位文件名字為 redis_6379.service。

1
[root@redisutils]# vi /etc/systemd/system/redis_6379.service

內(nèi)容如下:

1
2
3
4
5
6
7
8
[Unit]
Description=Redis on port 6379
[Service]
Type=forking
ExecStart=/etc/init.d/redis_6379 start
ExecStop=/etc/init.d/redis_6379 stop
[Install]
WantedBy=multi-user.target

注:這里Type=forking是后臺(tái)運(yùn)行的形式

啟動(dòng)redis

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
[root@redisutils]# systemctl daemon-reload 
[root@redisutils]# systemctl enable redis_6379.service
[root@redisutils]# systemctl start redis_6379.service
[root@redisutils]# systemctl status redis_6379.service 
● redis_6379.service - Redis on port 6379
   Loaded: loaded (/etc/systemd/system/redis_6379.service; enabled; vendor preset: disabled)
   Active: active (running) since Wed 2016-11-16 21:07:26 CST; 4min 25s ago
  Process: 7732 ExecStart=/etc/init.d/redis_6379 start (code=exited, status=0/SUCCESS)
 Main PID: 7734 (redis-server)
CGroup: /system.slice/redis_6379.service
└─7734 /usr/local/bin/redis-server 127.0.0.1:6379
  
Nov 16 21:07:26 redissystemd[1]: Starting Redis on port 6379...
Nov 16 21:07:26 redis redis_6379[7732]: Starting Redis server...
Nov 16 21:07:26 redissystemd[1]: Started Redis on port 6379.
[root@redisutils]# netstat -anpt | grep 6379
tcp        0      0 127.0.0.1:6379     0.0.0.0:*     LISTEN      7734/redis-server 1

從顯示結(jié)果可以看到redis默認(rèn)監(jiān)聽(tīng)的是127.0.0.1的6379端口

防火墻規(guī)則設(shè)置

1
2
3
4
[root@redisutils]# firewall-cmd --permanent --add-port=6379/tcp
success
[root@redisutils]# firewall-cmd --reload 
success

現(xiàn)在來(lái)查看redis版本使用redis-cli –version命令,如下

1
2
[root@redisutils]# redis-cli --version
redis-cli 3.2.3

通過(guò)顯示結(jié)果,我們可以看到redis版本是3.2.3。

到此源碼方式安裝redis就介紹完畢。

redis安裝完畢之后,我們?cè)賮?lái)配置redis

設(shè)置redis監(jiān)聽(tīng)的地址,添加監(jiān)聽(tīng)redis主機(jī)的ip

考慮到安全性,我們需要啟用redis的密碼驗(yàn)證功能requirepass參數(shù)

最終redis配置文件如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
[root@redis ~]# grep -Ev '^#|^$' /etc/redis/6379.conf 
bind 127.0.0.1 192.168.31.106
protected-mode yes
port 6379
tcp-backlog 511
timeout 0
tcp-keepalive 300
daemonize yes
supervised no
pidfile /var/run/redis_6379.pid
loglevel notice
logfile /var/log/redis_6379.log
databases 16
save 900 1
save 300 10
save 60 10000
stop-writes-on-bgsave-error yes
rdbcompression yes
rdbchecksum yes
dbfilenamedump.rdb
dir /var/lib/redis/6379
slave-serve-stale-data yes
slave-read-only yes
repl-diskless-sync no
repl-diskless-sync-delay 5
repl-disable-tcp-nodelay no
slave-priority 100
requirepass pwd@123
appendonly no
appendfilename "appendonly.aof"
appendfsynceverysec
no-appendfsync-on-rewrite no
auto-aof-rewrite-percentage 100
auto-aof-rewrite-min-size 64mb
aof-load-truncated yes
lua-time-limit 5000
slowlog-log-slower-than 10000
slowlog-max-len 128
latency-monitor-threshold 0
notify-keyspace-events ""
hash-max-ziplist-entries 512
hash-max-ziplist-value 64
list-max-ziplist-size -2
list-compress-depth 0
set-max-intset-entries 512
zset-max-ziplist-entries 128
zset-max-ziplist-value 64
hll-sparse-max-bytes 3000
activerehashing yes
client-output-buffer-limit normal 0 0 0
client-output-buffer-limit slave 256mb 64mb 60
client-output-buffer-limitpubsub 32mb 8mb 60
hz 10
aof-rewrite-incremental-fsync yes

重新啟動(dòng)redis服務(wù)

1
2
3
[root@redis ~]# systemctl restart redis_6379.service
[root@redis ~]# netstat -anpt | grep redis
tcp   0   0 192.168.31.106:6379     0.0.0.0:*   LISTEN      8418/redis-server 1

redis配置文件配置完畢后,我們來(lái)啟動(dòng)redis并進(jìn)行簡(jiǎn)單的操作。如下:

1
2
3
4
5
6
7
8
[root@redis ~]# redis-cli -h 192.168.31.106 -p 6379 -a pwd@123
192.168.31.106:6379> keys *
(empty list or set)
192.168.31.106:6379> set name lisi
OK
192.168.31.106:6379> get name
"lisi"
192.168.31.106:6379>

說(shuō)明:

關(guān)于redis-cli -h 192.168.31.106 -p 6379 -a pwd@123的參數(shù)解釋

這條命令是說(shuō)要連接redis服務(wù)器,IP是192.168.31.106,端口是6379,密碼是pwd@123。

keys *是查看redis所有的鍵值對(duì)。

set namelisi添加一個(gè)鍵值name,內(nèi)容為lisi。

get name查看name這個(gè)鍵值的內(nèi)容。

redis的命令使用暫時(shí)我們就介紹這么多

6、配置tomcat session redis同步

下載tomcat-redis-session-manager相應(yīng)的jar包,主要有三個(gè):

1
2
3
tomcat-redis-session-manage-tomcat7.jar
jedis-2.5.2.jar
commons-pool2-2.2.jar

下載完成后拷貝到$TOMCAT_HOME/lib中

1
[root@tomcat-1 ~]# cp tomcat-redis-session-manage-tomcat7.jar jedis-2.5.2.jar commons-pool2-2.2.jar /usr/local/tomcat7/lib/

修改tomcat的context.xml:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
[root@tomcat-1 ~]# cat /usr/local/tomcat7/conf/context.xml 
<?xml version='1.0' encoding='utf-8'?>
<!--
  Licensed to the Apache Software Foundation (ASF) under one or more
contributor license agreements.  See the NOTICE file distributed with
this work for additional information regarding copyright ownership.
  The ASF licenses this file to You under the Apache License, Version 2.0
  (the "License"); you may not use this file except in compliance with
the License.  You may obtain a copy of the License at
      http://www.apache.org/licenses/LICENSE-2.0
  Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  See the License for the specific language governing permissions and
limitations under the License.
-->
<!-- The contents of this file will be loaded for each web application -->
<Context>
<!-- Default set of monitored resources -->
<WatchedResource>WEB-INF/web.xml</WatchedResource>
<!-- Uncomment this to disable session persistence across Tomcat restarts -->
<!--
<Manager pathname="" />
    -->
<!-- Uncomment this to enable Comet connection tacking (provides events
on session expiration as well as webapp lifecycle) -->
<!--
<Valve className="org.apache.catalina.valves.CometConnectionManagerValve" />
    -->
<Valve className="com.orangefunction.tomcat.redissessions.RedisSessionHandlerValve" />
<Manager className="com.orangefunction.tomcat.redissessions.RedisSessionManager"
host="192.168.31.106"
password="pwd@123"
port="6379"
database="0"
maxInactiveInterval="60" />
</Context>

重啟tomcat服務(wù)

說(shuō)明:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
maxInactiveInterval="60":session的失效時(shí)間
[root@tomcat-1 ~]# shutdown.sh 
Using CATALINA_BASE:   /usr/local/tomcat7
Using CATALINA_HOME:   /usr/local/tomcat7
Using CATALINA_TMPDIR: /usr/local/tomcat7/temp
Using JRE_HOME:        /usr/local/java
Using CLASSPATH:       /usr/local/tomcat7/bin/bootstrap.jar:/usr/local/tomcat7/bin/tomcat-juli.jar
[root@tomcat-1 ~]# startup.sh 
Using CATALINA_BASE:   /usr/local/tomcat7
Using CATALINA_HOME:   /usr/local/tomcat7
Using CATALINA_TMPDIR: /usr/local/tomcat7/temp
Using JRE_HOME:        /usr/local/java
Using CLASSPATH:       /usr/local/tomcat7/bin/bootstrap.jar:/usr/local/tomcat7/bin/tomcat-juli.jar
Tomcat started.

tomcat-2執(zhí)行和tomcat-1相同的操作

通過(guò)瀏覽器訪問(wèn)http://192.168.31.141/index.jsp測(cè)試頁(yè)

刷新頁(yè)面

可以看出,分別訪問(wèn)了不同的tomcat,但是得到的session卻是相同的,說(shuō)明達(dá)到了集群的目的。

注:從Tomcat6開始默認(rèn)開啟了Session持久化設(shè)置,測(cè)試時(shí)可以關(guān)閉本地Session持久化,其實(shí)也很簡(jiǎn)單,在Tomcat的conf目錄下的context.xml文件中,取消注釋下面那段配置即可:

修改前:

1
2
3
4
<!-- Uncomment this to disable session persistence across Tomcat restarts -->
<!--
<Manager pathname="" />
-->

修改后:

1
2
<!-- Uncomment this to disable session persistence across Tomcat restarts -->
<Manager pathname="" />

重啟tomcat服務(wù)

查看redis:

1
2
3
4
5
6
[root@redis ~]# redis-cli -h 192.168.31.106 -p 6379 -a pwd@123
192.168.31.106:6379> keys *
1) "6C3F950BE6413AD2E0EF00F930881224.tomcat-1.tomcat-1"
2) "name"
3) "7A6D5D4C5B1EA52C4E9EED1C5523FEB5.tomcat-2.tomcat-2"
4) "32C35EEA064884F065E93CB00C690662.tomcat-1.tomcat-1"

7、tomcat連接數(shù)據(jù)庫(kù)

192.168.31.225作為mysql數(shù)據(jù)庫(kù)服務(wù)器

1
2
3
4
5
6
7
8
9
10
11
12
[root@db ~]# mysql -uroot -p123.abc
mysql> grant all on *.* to javauser@'192.168.31.%' identified by 'javapasswd';
Query OK, 0 rows affected, 1 warning (0.02 sec)
  
mysql> create database javatest;
Query OK, 1 row affected (0.01 sec)
  
mysql> use javatest;
Database changed
  
mysql> create table testdata(id int not null auto_increment primary key,foo varchar(25),bar int);
Query OK, 0 rows affected (0.02 sec)

插入些數(shù)據(jù)

1
2
3
4
5
6
7
8
9
10
11
mysql> insert into testdata(foo,bar) values ('hello','123456'),('ok','654321');
Query OK, 2 rows affected (0.04 sec)
Records: 2  Duplicates: 0  Warnings: 0
mysql> select * from testdata;
+----+-------+--------+
id | foo   | bar    |
+----+-------+--------+
|  1 | hello | 123456 |
|  2 | ok    | 654321 |
+----+-------+--------+
2 rows in set (0.00 sec)

mysql防火墻配置

配置tomcat服務(wù)器連接mysql數(shù)據(jù)庫(kù)

下載mysql-connector-java-5.1.22-bin.jar并復(fù)制到$CATALINA_HOME/lib目錄下

1
2
3
4
5
6
7
8
9
10
11
12
13
[root@tomcat-1 ~]# cp mysql-connector-java-5.1.22-bin.jar /usr/local/tomcat7/lib/
[root@tomcat-1 ~]# ls /usr/local/tomcat7/lib/mysql-connector-java-5.1.22-bin.jar 
/usr/local/tomcat7/lib/mysql-connector-java-5.1.22-bin.jar
  
context configuration
configure the JNDI datasource in tomcat by adding a declaration for your resource to your
context
[root@tomcat-1 ~]# vi /usr/local/tomcat7/conf/context.xml
在<Context>中添加如下內(nèi)容:
<Resource name="jdbc/TestDB" auth="Container" type="javax.sql.DataSource"
maxActive="100" maxIdle="30" maxWait="10000"
username="javauser" password="javapass" driverClassName="com.mysql.jdbc.Driver"
url="jdbc:mysql://192.168.31.225:3306/javatest"/>

保存修改并退出

1
2
3
web.xml configuration
[root@tomcat-1 ~]# mkdir /web/webapp1/WEB-INF
[root@tomcat-1 ~]# vi /web/webapp1/WEB-INF/web.xml

添加內(nèi)容如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
<web-app xmlns="http://java.sun.com/xml/ns/j2ee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee
http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd"
version="2.4">
<description>MySQL Test App</description>
<resource-ref>
<description>DB Connection</description>
<res-ref-name>jdbc/TestDB</res-ref-name>
<res-type>javax.sql.DataSource</res-type>
<res-auth>Container</res-auth>
</resource-ref>
</web-app>

保存修改并退出,重啟tomcat服務(wù)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
[root@tomcat-1 ~]# shutdown.sh 
Using CATALINA_BASE:   /usr/local/tomcat7
Using CATALINA_HOME:   /usr/local/tomcat7
Using CATALINA_TMPDIR: /usr/local/tomcat7/temp
Using JRE_HOME:        /usr/local/java
Using CLASSPATH:       /usr/local/tomcat7/bin/bootstrap.jar:/usr/local/tomcat7/bin/tomcat-juli.jar
[root@tomcat-1 ~]# startup.sh 
Using CATALINA_BASE:   /usr/local/tomcat7
Using CATALINA_HOME:   /usr/local/tomcat7
Using CATALINA_TMPDIR: /usr/local/tomcat7/temp
Using JRE_HOME:        /usr/local/java
Using CLASSPATH:       /usr/local/tomcat7/bin/bootstrap.jar:/usr/local/tomcat7/bin/tomcat-juli.jar
Tomcat started.
tomcat-2進(jìn)行和tomcat-1相同的操用
Test code
Now create a simple test.jsp page,內(nèi)容如下:
[root@tomcat-2 ~]# vi /web/webapp1/test.jsp
[root@tomcat-2 webapp1]# cattest.jsp
<%@ page language="java" import="java.sql.*" pageEncoding="GB2312"%>
<html>
<head>
<title>MySQL</title>
</head>
<body>
connect MySQL<br>
<%
String driverClass="com.mysql.jdbc.Driver";
String url="jdbc:mysql://192.168.31.225:3306/javatest";
String username = "javauser"
String password = "javapasswd"
Class.forName(driverClass); 
Connection conn=DriverManager.getConnection(url, username, password); 
Statement stmt=conn.createStatement();
ResultSetrs = stmt.executeQuery("select * from testdata"); 
while(rs.next()){
out.println("<br>foo:"+rs.getString(2)+"bar:"+rs.getString(3));
}
rs.close();
stmt.close();
conn.close();
%>
</body></html>

通過(guò)瀏覽器訪問(wèn)http://192.168.31.141/test.jsp測(cè)試頁(yè)

注:

以上配置可以參考tomcat docs



 

 

 


本文出自 “一盞燭光” 博客,謝絕轉(zhuǎn)載!

以上內(nèi)容是否對(duì)您有幫助:
在線筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號(hào)
微信公眾號(hào)

編程獅公眾號(hào)