对于web应用集群的技术实现而言,最大的难点就是:如何能在集群中的多个节点之间保持数据的一致性,会话(Session)信息是这些数据中最重要的一块。要实现这一点, 大致上有两种方式:
一种是把全部Session数据放到一台服务器上或者数据库中,集群中的全部节点经过访问这台Session服务器来获取数据;
另外一种就是在集群中的全部节点间进行Session数据的同步拷贝,任何一个节点均保存了全部的Session数据。javascript
Tomcat集群session同步方案有如下几种方式:
1)使用tomcat自带的cluster方式,多个tomcat间自动实时复制session信息,配置起来很简单。但这个方案的效率比较低,在大并发下表现并很差。
2)利用nginx的基于访问ip的hash路由策略,保证访问的ip始终被路由到同一个tomcat上,这个配置更简单。但若是应用是某一个局域网大量用户同时登陆,这样负载均衡就没什么做用了。
3)利用nginx插件实现tomcat集群和session同步,nginx-upstream-jvm-route-0.1.tar.gz,是一个Nginx的扩展模块,用来实现基于Cookie的Session Sticky的功能。
4)利用memcached实现(MSM工具)。memcached存储session,并把多个tomcat的session集中管理,前端在利用nginx负载均衡和动静态资源分离,在兼顾系统水平扩展的同时又能保证较高的性能。
5)利用redis实现。使用redis不只仅能够将缓存的session持久化,还由于它支持的单个对象比较大,并且数据类型丰富,不仅是缓存 session,还能够作其余用途,能够一举几得。
6)利用filter方法实现。这种方法比较推荐,由于它的服务器使用范围比较多,不只限于tomcat ,并且实现的原理比较简单容易控制。
7)利用terracotta服务器共享session。这种方式配置比较复杂。php
在Tomcat集群中,当一个节点出现故障,虽然有高可用集群来负责故障转移,但用户的session信息如何保持呢?
下面介绍第4种方案,session复制同步使用MSM(Memcache-Session-Manager),即利用MSM+Memcached作Session共享。css
MSM介绍:(详细介绍能够参考:http://www.cnblogs.com/kevingrace/p/6401025.html)
MSM是一个高可用的Tomcat Session共享解决方案,除了能够从本机内存快速读取Session信息(仅针对黏性Session)外,还可以使用Memcached存取Session,以实现高可用。
传统tomcat集群,会话复制随着结点数增多,扩展性成为瓶颈。MSM使用memcached完成统一管理tomcat会话,避免tomcat结点间过多会话复制。
MSM利用Value(Tomcat 阀)对Request进行跟踪。Request请求到来时,从memcached加载session,Request请求结束时,将tomcat session更新至memcached,以达到session共享之目的, 支持sticky和non-sticky模式:
sticky : 会话粘连模式(黏性session)。客户端在一台tomcat实例上完成登陆后,之后的请求均会根据IP直接绑定到该tomcat实例。
no-sticky:会话非粘连模式(非粘性session)。客户端的请求是随机分发,多台tomcat实例均会收到请求。html
在进行环境部署以前,要对cookie和session的工做机制很是了解,若是不了解其中的原理且只是机械性地去按照参考文档部署,那么这是毫无心义的。
a)cookie是怎么工做的?
加入咱们建立了一个名字为login的Cookie来包含访问者的信息,建立Cookie时,服务器端的Header以下面所示,这里假设访问者的注册名是“wangshibo”,同时还对所建立的Cookie的属性如path、domain、expires等进行了指定。前端
1
2
|
Set-Cookie:login=wangshibo;path=/;domain=msn.com;
expires=Monday,01-Mar-99 00:00:01 GMT
|
上面这个Header会自动在浏览器端计算机的Cookie文件中添加一条记录。浏览器将变量名为“login”的Cookie赋值为“wangshibo”。
注意,在实际传递过程当中这个Cookie的值是通过了URLEncode方法的URL编码操做的。 这个含有Cookie值的HTTP Header被保存到浏览器的Cookie文件后,Header就通知浏览器将Cookie经过请求以忽略路径的方式返回到服务器,完成浏览器的认证操做。
此外,咱们使用了Cookie的一些属性来限定该Cookie的使用。例如Domain属性可以在浏览器端对Cookie发送进行限定,具体到上面的例子,该Cookie只能传到指定的服务器上,而决不会跑到其余的Web站点上去。Expires属性则指定了该Cookie保存的时间期限,例如上面的Cookie在浏览器上只保存到1999年3月1日1秒。 固然,若是浏览器上Cookie太多,超过了系统所容许的范围,浏览器将自动对它进行删除。至于属性Path,用来指定Cookie将被发送到服务器的哪个目录路径下。
说明:浏览器建立了一个Cookie后,对于每个针对该网站的请求,都会在Header中带着这个Cookie;不过,对于其余网站的请求Cookie是绝对不会跟着发送的。并且浏览器会这样一直发送,直到Cookie过时为止。java
b)session是如何工做的?
因为http是无状态的协议,你访问了页面A,而后再访问B页面,http没法肯定这2个访问来自一我的,所以要用cookie或session来跟踪用户,根据受权和用户身份来 显示不一样的页面。好比用户A登录了,那么能看到本身的我的信息,而B没登录,没法看到我的信息。还有A可能在购物,把商品放入购物车,此时B也有这个过程, 你没法肯定A,B的身份和购物信息,因此须要一个session ID来维持这个过程。
cookie是服务器发给客户端并保持在客户端的一个文件,里面包含了用户的访问信息(帐户密码等),能够手动删除或设置有效期,在下次访问的时候,会返给服务器。
注意:cookie能够被禁用,因此要想其余办法,这就是session。cookie数据存放在客户的浏览器上,session数据放在服务器上。cookie同时也是session id的载体,cookie保存session id。另外:cookie不是很安全,别人能够分析存放在本地的cookie并进行cookie欺骗,考虑到安全应当使用session。session是服务器端缓存,cookie是客户端缓存。因此建议:将登录信息等重要信息存放为session;其余信息若是须要保留,能够放在cookie中,
好比:你去商场购物,商场会给你办一张会员卡,下次你来出示该卡,会有打折优惠,该卡能够本身保存(cookie),或是商场代为保管,因为会员太多,我的须要保存卡号信息(session ID)。node
为何要持久化session(共享session)?
由于:在客户端每一个用户的Session对象存在Servlet容器中,若是Tomcat服务器重启或者宕机的话,那么该session就会丢失,而客户端的操做会因为session丢失而形成数据丢失;若是当前用户访问量巨大,每一个用户的Session里存放大量数据的话,那么就很占用服务器大量的内存,进而导致服务器性能受到影响。
可使用数据库持久化session,分为物理数据库和内存数据库。物理数据库备份session,因为其性能缘由,不推荐;内存数据库可使用redis和memcached,这里介绍memcached的方法。linux
MSM工做原理:
a)Sticky Session(黏性) 模式下的工做原理:
Tomcat本地Session为主Session,Memcached 中的Session为备Session。
安装在Tomcat上的MSM使用本机内存保存Session,当一个请求执行完毕以后,若是对应的Session在本地不存在(即某用户的第一次请求),则将该Session复制一份至Memcached;当该Session的下一个请求到达时,会使用Tomcat的本地Session,请求处理结束以后,Session的变化会同步更新到 Memcached,保证数据一致。
当集群中的一个Tomcat挂掉,下一次请求会被路由到其余Tomcat上。负责处理此此请求的Tomcat并不清楚Session信息,因而从Memcached查找该Session,更新该Session并将其保存至本机。这次请求结束,Session被修改,送回Memcached备份。
b)Non-sticky Session (非黏性)模式下的工做原理(记住:多台tomcat集群或多个tomcat实例时须要选择Non-Sticky模式,即sticky="false"):
Tomcat本地Session为中转Session,Memcached为主备Session。
收到请求,加载备Session至本地容器,若备Session加载失败则从主Session加载;
请求处理结束以后,Session的变化会同步更新到Memcached,并清除Tomcat本地Session。nginx
------------------------------------------------------------------------------------------------------------
废话很少说了,下面直接看nginx+memcached+tomcat实现session共享的集群操做记录::
1、集群实验环境信息c++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
主机 端口 开源软件
192.168.1.118 80 nginx(nginx-1.8.1)
192.168.1.118 8081 tomcat1(版本为tomcat7)
192.168.1.118 8091 tomcat2
192.168.1.118 11211 memcached(memcached-1.4.34)
192.168.1.118 11212 memcached(memcached-1.4.34)
服务器系统均是centos6.8
我这里是在一台测试服务器(192.168.1.118
/110
.110.115.118)上操做的,即nginx、memcached、tomcat均是部署在同一台服务器上,只是为了测试。
若是在生产环境下,ngixn、tocmat、memcached应该是部署到不一样的服务器上。
为何在两个tomcat实例前要放一个nginx?
1)nginx能够做为两个tomcat的负载均衡,均衡两个tomat负载压力,负载均衡也可使得客户端访问可使用统一的url,若是没有nginx,那么访问tomcat1必需要用http:
//localhost
:8081/,而访问tomcat2须要用http:
//localhost
:8091/
2)nginx处理静态资源的性能比tomcat好不少
|
实验拓扑图:
2、nginx安装
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
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
|
1)安装依赖包
[root@linux-node3 ~]
# yum -y install gcc gcc-c++
2)安装pcre库
[root@linux-node3 ~]
# cd /usr/local/src/
[root@linux-node3 src]
# wget https://jaist.dl.sourceforge.net/project/pcre/pcre/8.37/pcre-8.37.tar.gz
[root@linux-node3 src]
# tar -zvxf pcre-8.37.tar.gz
[root@linux-node3 src]
# cd pcre-8.37
[root@linux-node3 pcre-8.37]
# ./configure && make && make install
3)安装zlib库
[root@linux-node3 src]
# wget http://www.zlib.net/zlib-1.2.11.tar.gz
[root@linux-node3 src]
# tar -zvxf zlib-1.2.11.tar.gz
[root@linux-node3 zlib-1.2.11]
# ./configure && make && make install
4)安装openssl
[root@linux-node3 src]
# wget http://www.openssl.org/source/openssl-1.0.1c.tar.gz
[root@linux-node3 src]
# tar -zvxf openssl-1.0.1c.tar.gz && cd openssl-1.0.1c && ./config && make && make install
5)安装nginx
特别注意要指定prce zlib openssl原码包位置
[root@linux-node3 src]
# wget http://nginx.org/download/nginx-1.8.1.tar.gz
[root@linux-node3 src]
# tar -zvxf nginx-1.8.1.tar.gz
[root@linux-node3 src]
# cd nginx-1.8.1
[root@linux-node3 nginx-1.8.1]
# ./configure --prefix=/usr/local/nginx --with-http_ssl_module --with-pcre=/usr/local/src/pcre-8.37 --with-zlib=/usr/local/src/zlib-1.2.11 --with-openssl=/usr/local/src/openssl-1.0.1c
[root@linux-node3 nginx-1.8.1]
# make && make install
6)安装成功后配置nginx
[root@linux-node3 nginx-1.8.1]
# vim /usr/local/nginx/conf/nginx.conf
#user nobody;
worker_processes 8;
#error_log logs/error.log;
#error_log logs/error.log notice;
#error_log logs/error.log info;
#pid logs/nginx.pid;
worker_rlimit_nofile 65535;
events {
use epoll;
worker_connections 65535;
}
http {
include mime.types;
default_type application
/octet-stream
;
charset utf-8;
######
## set access log format
######
log_format main
'$http_x_forwarded_for $remote_addr $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_cookie" $host $request_time'
;
#######
## http setting
#######
sendfile on;
tcp_nopush on;
tcp_nodelay on;
keepalive_timeout 65;
fastcgi_connect_timeout 30000;
fastcgi_send_timeout 30000;
fastcgi_read_timeout 30000;
fastcgi_buffer_size 256k;
fastcgi_buffers 8 256k;
fastcgi_busy_buffers_size 256k;
fastcgi_temp_file_write_size 256k;
fastcgi_intercept_errors on;
##cache##
client_header_timeout 60s;
client_body_timeout 60s;
client_max_body_size 10m;
client_body_buffer_size 1m;
proxy_connect_timeout 5;
proxy_read_timeout 60;
proxy_send_timeout 5;
proxy_buffer_size 64k;
proxy_buffers 4 128k;
proxy_busy_buffers_size 128k;
proxy_temp_file_write_size 1m;
proxy_temp_path
/home/temp_dir
;
proxy_cache_path
/home/cache
levels=1:2 keys_zone=cache_one:200m inactive=1d max_size=30g;
##end##
gzip
on;
gzip_min_length 1k;
gzip_buffers 4 16k;
gzip_http_version 1.1;
gzip_comp_level 9;
gzip_types text
/plain
application
/x-javascript
text
/css
application
/xml
text
/javascript
application
/x-httpd-php
;
gzip_vary on;
## includes vhosts
include vhosts/*.conf;
}
[root@linux-node3 nginx-1.8.1]
# cd /usr/local/nginx/conf/
[root@linux-node3 conf]
# mkdir vhosts
[root@linux-node3 conf]
# cd vhosts/
[root@linux-node3 vhosts]
# vim test.conf
upstream tomcat-lb {
server 127.0.0.1:8081;
server 127.0.0.1:8091;
}
server {
listen 80;
server_name www.wangshibo.com;
location / {
proxy_pass http:
//tomcat-lb
;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header REMOTE-HOST $remote_addr;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
location ~ .*\.(gif|jpg|png|htm|html|css|ico|flv|swf)(.*) {
proxy_pass http:
//tomcat-lb
;
proxy_redirect off;
proxy_set_header Host $host;
proxy_cache cache_one;
proxy_cache_valid 200 302 1h;
proxy_cache_valid 301 1d;
proxy_cache_valid any 10m;
expires 30d;
proxy_cache_key $host$uri$is_args$args;
}
}
|
3、memcached安装
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@linux-node3 src]
# yum -y install libevent libevent-devel
[root@linux-node3 src]
# wget http://memcached.org/files/memcached-1.4.34.tar.gz
[root@linux-node3 src]
# tar -zvxf memcached-1.4.34.tar.gz
[root@linux-node3 src]
# cd memcached-1.4.34
[root@linux-node3 memcached-1.4.34]
# ./configure --prefix=/usr/local/memcached
[root@linux-node3 memcached-1.4.34]
# make && make install
启动memcached,端口11211能够根据本身须要修改不一样端口
[root@linux-node3 memcached-1.4.34]
# /usr/local/memcached/bin/memcached -d -m 512 -u root -p 11211 -c 1024 -P /var/lib/memcached.11211pid
[root@linux-node3 memcached-1.4.34]
# /usr/local/memcached/bin/memcached -d -m 512 -u root -p 11212 -c 1024 -P /var/lib/memcached.11212pid
[root@linux-node3 memcached-1.4.34]
# ps -ef|grep memcached
root 44007 1 0 14:21 ? 00:00:00
/usr/local/memcached/bin/memcached
-d -m 512 -u root -p 11211 -c 1024 -P
/var/lib/memcached
.11211pid
root 44018 1 0 14:21 ? 00:00:00
/usr/local/memcached/bin/memcached
-d -m 512 -u root -p 11212 -c 1024 -P
/var/lib/memcached
.11212pid
root 44038 21647 0 14:22 pts
/2
00:00:00
grep
memcached
测试一下memcached链接,以下说明成功(输入quit退出)
[root@linux-node3 ~]
# telnet 192.168.1.118 11211
Trying 192.168.1.118...
Connected to 192.168.1.118.
Escape character is
'^]'
.
[root@linux-node3 ~]
# telnet 192.168.1.118 11212
Trying 192.168.1.118...
Connected to 192.168.1.118.
Escape character is
'^]'
.
|
4、安装jdk
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
76
77
78
79
80
81
82
83
|
查看CentOS自带JDK是否已安装
[root@linux-node3 ~]
# yum list installed |grep java
[root@linux-node3 ~]
#
如有自带安装的JDK,如何卸载CentOS系统自带Java环境?
卸载JDK相关文件输入:yum -y remove java-1.7.0-openjdk*。
卸载tzdata-java输入:yum -y remove tzdata-java.noarch。
当结果显示为Complete!即卸载完毕。
注:
"*"
表示卸载掉java 1.7.0的全部openjdk相关文件。
查看yum库中的java安装包
[root@linux-node3 ~]
# yum -y list java*
........
java-1.5.0-gcj.x86_64 1.5.0.0-29.1.el6 base
java-1.5.0-gcj-devel.x86_64 1.5.0.0-29.1.el6 base
java-1.5.0-gcj-javadoc.x86_64 1.5.0.0-29.1.el6 base
java-1.5.0-gcj-src.x86_64 1.5.0.0-29.1.el6 base
java-1.6.0-openjdk.x86_64 1:1.6.0.41-1.13.13.1.el6_8 updates
java-1.6.0-openjdk-demo.x86_64 1:1.6.0.41-1.13.13.1.el6_8 updates
java-1.6.0-openjdk-devel.x86_64 1:1.6.0.41-1.13.13.1.el6_8 updates
java-1.6.0-openjdk-javadoc.x86_64 1:1.6.0.41-1.13.13.1.el6_8 updates
java-1.6.0-openjdk-src.x86_64 1:1.6.0.41-1.13.13.1.el6_8 updates
java-1.7.0-openjdk.x86_64 1:1.7.0.131-2.6.9.0.el6_8 updates
java-1.7.0-openjdk-demo.x86_64 1:1.7.0.131-2.6.9.0.el6_8 updates
java-1.7.0-openjdk-devel.x86_64 1:1.7.0.131-2.6.9.0.el6_8 updates
java-1.7.0-openjdk-javadoc.noarch 1:1.7.0.131-2.6.9.0.el6_8 updates
java-1.7.0-openjdk-src.x86_64 1:1.7.0.131-2.6.9.0.el6_8 updates
java-1.8.0-openjdk.x86_64 1:1.8.0.121-0.b13.el6_8 updates
java-1.8.0-openjdk-debug.x86_64 1:1.8.0.121-0.b13.el6_8 updates
java-1.8.0-openjdk-demo.x86_64 1:1.8.0.121-0.b13.el6_8 updates
java-1.8.0-openjdk-demo-debug.x86_64 1:1.8.0.121-0.b13.el6_8 updates
java-1.8.0-openjdk-devel.x86_64 1:1.8.0.121-0.b13.el6_8 updates
java-1.8.0-openjdk-devel-debug.x86_64 1:1.8.0.121-0.b13.el6_8 updates
java-1.8.0-openjdk-headless.x86_64 1:1.8.0.121-0.b13.el6_8 updates
java-1.8.0-openjdk-headless-debug.x86_64 1:1.8.0.121-0.b13.el6_8 updates
java-1.8.0-openjdk-javadoc.noarch 1:1.8.0.121-0.b13.el6_8 updates
java-1.8.0-openjdk-javadoc-debug.noarch 1:1.8.0.121-0.b13.el6_8 updates
java-1.8.0-openjdk-src.x86_64 1:1.8.0.121-0.b13.el6_8 updates
java-1.8.0-openjdk-src-debug.x86_64 1:1.8.0.121-0.b13.el6_8 updates
........
以yum库中java-1.7.0为例
注:
"*"
表示将java-1.7.0的全部相关Java程序都安装上。
[root@linux-node3 ~]
# yum -y install java-1.7.0-openjdk*
查看刚安装的Java版本信息。
输入:java -version 可查看Java版本;
输入:javac 可查看Java的编译器命令用法
[root@linux-node3 ~]
# java -version
java version
"1.7.0_131"
OpenJDK Runtime Environment (rhel-2.6.9.0.el6_8-x86_64 u131-b00)
OpenJDK 64-Bit Server VM (build 24.131-b00, mixed mode)
[root@linux-node3 ~]
# which java
/usr/bin/java
[root@linux-node3 ~]
# ll /usr/bin/java
lrwxrwxrwx. 1 root root 22 Feb 14 22:25
/usr/bin/java
->
/etc/alternatives/java
[root@linux-node3 ~]
# ll /etc/alternatives/java
lrwxrwxrwx. 1 root root 46 Feb 14 22:25
/etc/alternatives/java
->
/usr/lib/jvm/jre-1
.7.0-openjdk.x86_64
/bin/java
[root@linux-node3 ~]
# cd /usr/lib/jvm
[root@linux-node3 jvm]
# ll
total 4
lrwxrwxrwx. 1 root root 26 Feb 14 22:25 java ->
/etc/alternatives/java_sdk
lrwxrwxrwx. 1 root root 32 Feb 14 22:25 java-1.7.0 ->
/etc/alternatives/java_sdk_1
.7.0
drwxr-xr-x. 9 root root 4096 Feb 14 22:25 java-1.7.0-openjdk-1.7.0.131.x86_64
lrwxrwxrwx. 1 root root 35 Feb 14 22:25 java-1.7.0-openjdk.x86_64 -> java-1.7.0-openjdk-1.7.0.131.x86_64
lrwxrwxrwx. 1 root root 34 Feb 14 22:25 java-openjdk ->
/etc/alternatives/java_sdk_openjdk
lrwxrwxrwx. 1 root root 21 Feb 14 22:25 jre ->
/etc/alternatives/jre
lrwxrwxrwx. 1 root root 27 Feb 14 22:25 jre-1.7.0 ->
/etc/alternatives/jre_1
.7.0
lrwxrwxrwx. 1 root root 39 Feb 14 22:25 jre-1.7.0-openjdk.x86_64 -> java-1.7.0-openjdk-1.7.0.131.x86_64
/jre
lrwxrwxrwx. 1 root root 29 Feb 14 22:25 jre-openjdk ->
/etc/alternatives/jre_openjdk
由上可知,java的home目录是
/usr/lib/jvm/java-1
.7.0-openjdk.x86_64
设置java的环境变量
[root@115 ~]
# vim /etc/profile
.......
export
JAVA_HOME=
/usr/lib/jvm/java-1
.7.0-openjdk.x86_64
export
CLASSPATH=.:$JAVA_HOME
/jre/lib/rt
.jar:$JAVA_HOME
/lib/dt
.jar:$JAVA_HOME
/lib/tools
.jar
export
PATH=$PATH:$JAVA_HOME
/bin
[root@linux-node3 jvm]
# source /etc/profile
|
5、安装与配置tomcat
1)安装tomcat
[root@linux-node3 src]# wget http://apache.fayea.com/tomcat/tomcat-7/v7.0.75/bin/apache-tomcat-7.0.75.tar.gz
[root@linux-node3 src]# tar -zvxf apache-tomcat-7.0.75.tar.gz
[root@linux-node3 src]# mv apache-tomcat-7.0.75 /usr/local/tomcat1
2)添加memcached和msm(Memcached_Session_Manager)的依赖jar包,以下:
1
2
3
4
5
6
7
8
9
|
asm-3.2.jar
kryo-1.03.jar
kryo-serializers-0.10.jar
memcached-session-manager-1.7.0.jar
memcached-session-manager-tc7-1.7.0.jar
minlog-1.2.jar
msm-kryo-serializer-1.6.3.jar
reflectasm-0.9.jar
spymemcached-2.7.3.jar
|
注意:memcached-session-manager-tc7-1.7.0.jar中的tc7为tomcat的版本号。必定要注意:不一样版本号的tomcat,对应的msm包也不一样。此处为tomcat7的jar包
上面依赖包下载地址:https://pan.baidu.com/s/1eRRncpO
提取密码:y56i
---------------------------------------------------------------------------------------------------------------------------------
msm相关版本的jar包下载地址:http://repo1.maven.org/maven2/de/javakaffee/msm/
spymemcached相关版本下载地址:http://repo1.maven.org/maven2/net/spy/spymemcached
---------------------------------------------------------------------------------------------------------------------------------
把依赖包下载后所有上传到tomcat1和tomcat2的安装路径下的lib/ 目录下
3)配置tomcat
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
这里个人tomcat1的服务端口用的是8081,因此须要将tomcat1的server.xml中默认的8080改为8081
[root@linux-node3 ~]
# cd /usr/local/tomcat1/conf/
[root@linux-node3 conf]
# cp server.xml server.xml.bak
[root@linux-node3 conf]
# vim server.xml
.......
<Connector port=
"8081"
protocol=
"HTTP/1.1"
connectionTimeout=
"20000"
redirectPort=
"8443"
/>
......
<Engine name=
"Catalina"
defaultHost=
"localhost"
jvmRoute=
"tomcat1"
>
......
注意:启有Engine标签中的jvmRoute属性,启用的目的就是为了区分session是在哪一个节点上生成的
这个Engine name是非必选 ,只有选择了sticky模式才加入jvmRoute属性。这里为了实验效果,咱们暂且选择这个设置项。
不一样的tomcat实例jvmRoute取值不能相同。
例:8081端口的tomcat实例jvmRoute=tomcat1,8091端口的tomcat实例jvmRoute=tomcat2
|
接下来进行序列化tomcat配置,修改conf/context.xml文件。
序列化tomcat配置的方法有不少种:java默认序列化tomcat配置、javolution序列化tomcat配置、xstream序列化tomcat配置、flexjson序列化tomcat配置和kryo序列化tomcat配置。官网介绍说 使用kryo 序列化tomcat的效率最高,因此这里只介绍kryo序列化。
在No-Stick模式和Stick模式下context.xml文件配置也有所不一样(通常用的是No-Stick模式)
a)No-Stick模式(记住:多台tomcat集群或多个tomcat实例时 须要选择Non-Sticky模式,即sticky="false")
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
[root@linux-node3 ~]
# cd /usr/local/tomcat1/conf/
[root@linux-node3 conf]
# cp context.xml context.xml.bak
[root@linux-node3 conf]
# vim context.xml //在<Context>和</Context>之间添加下面内容
<Manager className=
"de.javakaffee.web.msm.MemcachedBackupSessionManager"
memcachedNodes=
"n1:192.168.1.118:11211 n2:192.168.1.118:11212"
lockingMode=
"auto"
sticky=
"false"
requestUriIgnorePattern=
".*\.(png|gif|jpg|css|js)$"
sessionBackupAsync=
"true"
sessionBackupTimeout=
"1800000"
copyCollectionsForSerialization=
"true"
transcoderFactoryClass=
"de.javakaffee.web.msm.serializer.kryo.KryoTranscoderFactory"
/>
而后将congtext.xml文件拷贝到tomcat2的相同路径下
|
b)Stick模式。故障转移配置节点(failoverNodes),不能使用在non-sticky sessions模式,多个使用空格或逗号分开,配置某个节点为备份节点,当其余节点都不可用时才会存储到备份节点,适用于sticky模式(即一台tomcat,多台memcached)。
1
2
3
4
5
6
7
8
9
10
11
12
13
|
[root@linux-node3 ~]
# cd /usr/local/tomcat1/conf/
[root@linux-node3 conf]
# cp context.xml context.xml.bak
[root@linux-node3 conf]
# vim context.xml //在<Context>和</Context>之间添加下面内容
<Manager className=
"de.javakaffee.web.msm.MemcachedBackupSessionManager"
memcachedNodes=
"n1:192.168.1.118:11211 n2:192.168.1.118:11212"
sticky=
"true"
failoverNodes=
"n2"
requestUriIgnorePattern=
".*\.(png|gif|jpg|css|js|swf|flv)$"
transcoderFactoryClass=
"de.javakaffee.web.msm.serializer.kryo.KryoTranscoderFactory"
copyCollectionsForSerialization=
"true"
/>
而后将congtext.xml文件拷贝到tomcat2的相同路径下,并将failoverNodes后面的参数改成n1
|
--------------------------------------------------------------------------------------------------------------
注意:这里实验环境是开启了两个memcached端口,若是开启一个memcached端口也能够的,好比只开启11211端口,则No-Stick模式的配置以下:
1
2
3
4
5
6
7
8
9
|
<Manager className=
"de.javakaffee.web.msm.MemcachedBackupSessionManager"
memcachedNodes=
"n1:192.168.1.118:11211"
sticky=
"false"
requestUriIgnorePattern=
".*\.(png|gif|jpg|css|js)$"
sessionBackupAsync=
"true"
sessionBackupTimeout=
"1800000"
copyCollectionsForSerialization=
"false"
transcoderFactoryClass=
"de.javakaffee.web.msm.serializer.kryo.KryoTranscoderFactory"
/>
|
--------------------------------------------------------------------------------------------------------------
6、配置tomcat集群
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
[root@linux-node3 ~]
# cd /usr/local/
[root@linux-node3
local
]
# cp -r tomcat1 tomcat2
修改server.xml文件里的相应端口,防止tomcat1和tomcat2端口冲突
[root@linux-node3
local
]
# vim tomcat2/conf/server.xml
.......
<Server port=
"8006"
shutdown
=
"SHUTDOWN"
>
//
把8005修改为8006
......
<Connector port=
"8091"
protocol=
"HTTP/1.1"
//
把8081修改为8091根据本身来配置,修改后的8090与nginx配置同样
connectionTimeout=
"20000"
redirectPort=
"8443"
/>
.....
<Connector port=
"8010"
protocol=
"AJP/1.3"
redirectPort=
"8443"
/>
//
把8009修改为8010
.....
<Engine name=
"Catalina"
defaultHost=
"localhost"
jvmRoute=
"tomcat2"
>
//
把tomcat1改成tomcat2
|
7、启动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
|
[root@linux-node3 ~]
# /usr/local/tomcat1/bin/startup.sh
Using CATALINA_BASE:
/usr/local/tomcat1
Using CATALINA_HOME:
/usr/local/tomcat1
Using CATALINA_TMPDIR:
/usr/local/tomcat1/temp
Using JRE_HOME:
/usr/lib/jvm/java-1
.7.0-openjdk.x86_64
Using CLASSPATH:
/usr/local/tomcat1/bin/bootstrap
.jar:
/usr/local/tomcat1/bin/tomcat-juli
.jar
Tomcat started.
[root@linux-node3 ~]
# /usr/local/tomcat2/bin/startup.sh
Using CATALINA_BASE:
/usr/local/tomcat2
Using CATALINA_HOME:
/usr/local/tomcat2
Using CATALINA_TMPDIR:
/usr/local/tomcat2/temp
Using JRE_HOME:
/usr/lib/jvm/java-1
.7.0-openjdk.x86_64
Using CLASSPATH:
/usr/local/tomcat2/bin/bootstrap
.jar:
/usr/local/tomcat2/bin/tomcat-juli
.jar
Tomcat started.
[root@linux-node3 ~]
# ps -ef|grep tomcat
root 29224 1 49 02:21 pts
/2
00:00:04
/usr/lib/jvm/java-1
.7.0-openjdk.x86_64
/bin/java
-Djava.util.logging.config.
file
=
/usr/local/tomcat1/conf/logging
.properties -Djava.util.logging.manager=org.apache.juli.ClassLoaderLogManager -Djdk.tls.ephemeralDHKeySize=2048 -Djava.protocol.handler.pkgs=org.apache.catalina.webresources -classpath
/usr/local/tomcat1/bin/bootstrap
.jar:
/usr/local/tomcat1/bin/tomcat-juli
.jar -Dcatalina.base=
/usr/local/tomcat1
-Dcatalina.home=
/usr/local/tomcat1
-Djava.io.tmpdir=
/usr/local/tomcat1/temp
org.apache.catalina.startup.Bootstrap start
root 29250 1 87 02:21 pts
/2
00:00:04
/usr/lib/jvm/java-1
.7.0-openjdk.x86_64
/bin/java
-Djava.util.logging.config.
file
=
/usr/local/tomcat2/conf/logging
.properties -Djava.util.logging.manager=org.apache.juli.ClassLoaderLogManager -Djdk.tls.ephemeralDHKeySize=2048 -Djava.protocol.handler.pkgs=org.apache.catalina.webresources -classpath
/usr/local/tomcat2/bin/bootstrap
.jar:
/usr/local/tomcat2/bin/tomcat-juli
.jar -Dcatalina.base=
/usr/local/tomcat2
-Dcatalina.home=
/usr/local/tomcat2
-Djava.io.tmpdir=
/usr/local/tomcat2/temp
org.apache.catalina.startup.Bootstrap start
root 29278 29157 0 02:21 pts
/2
00:00:00
grep
tomcat
[root@linux-node3 ~]
# lsof -i:8080
COMMAND PID USER FD TYPE DEVICE SIZE
/OFF
NODE NAME
java 29224 root 55u IPv6 383017 0t0 TCP *:webcache (LISTEN)
[root@linux-node3 ~]
# lsof -i:8090
COMMAND PID USER FD TYPE DEVICE SIZE
/OFF
NODE NAME
java 29250 root 55u IPv6 383056 0t0 TCP *:8090 (LISTEN)
|
8、启动nginx
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
|
[root@linux-node3 ~]
# /usr/local/nginx/sbin/nginx
[root@linux-node3 ~]
# ps -ef|grep nginx
root 29282 1 0 02:23 ? 00:00:00 nginx: master process
/usr/local/nginx/sbin/nginx
nobody 29283 29282 2 02:23 ? 00:00:00 nginx: worker process
nobody 29284 29282 1 02:23 ? 00:00:00 nginx: worker process
nobody 29285 29282 2 02:23 ? 00:00:00 nginx: worker process
nobody 29286 29282 2 02:23 ? 00:00:00 nginx: worker process
nobody 29287 29282 1 02:23 ? 00:00:00 nginx: worker process
nobody 29288 29282 2 02:23 ? 00:00:00 nginx: worker process
nobody 29289 29282 3 02:23 ? 00:00:00 nginx: worker process
nobody 29290 29282 1 02:23 ? 00:00:00 nginx: worker process
nobody 29291 29282 0 02:23 ? 00:00:00 nginx: cache manager process
nobody 29292 29282 0 02:23 ? 00:00:00 nginx: cache loader process
root 29294 29157 0 02:23 pts
/2
00:00:00
grep
nginx
[root@linux-node3 ~]
# lsof -i:80
COMMAND PID USER FD TYPE DEVICE SIZE
/OFF
NODE NAME
nginx 29282 root 6u IPv4 383819 0t0 TCP *:http (LISTEN)
nginx 29283 nobody 6u IPv4 383819 0t0 TCP *:http (LISTEN)
nginx 29284 nobody 6u IPv4 383819 0t0 TCP *:http (LISTEN)
nginx 29285 nobody 6u IPv4 383819 0t0 TCP *:http (LISTEN)
nginx 29286 nobody 6u IPv4 383819 0t0 TCP *:http (LISTEN)
nginx 29287 nobody 6u IPv4 383819 0t0 TCP *:http (LISTEN)
nginx 29288 nobody 6u IPv4 383819 0t0 TCP *:http (LISTEN)
nginx 29289 nobody 6u IPv4 383819 0t0 TCP *:http (LISTEN)
nginx 29290 nobody 6u IPv4 383819 0t0 TCP *:http (LISTEN)
|
9、测试session是否共享
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
[root@linux-node3 ~]
# cd /usr/local/tomcat1/webapps/ROOT/
[root@linux-node3 ROOT]
# mkdir tomcat-session
[root@linux-node3 ROOT]
# cd tomcat-session/
[root@linux-node3 tomcat-session]
# vim index.jsp
<%@ page contentType=
"text/html; charset=GBK"
%>
<%@ page
import
=
"java.util.*"
%>
<html><
head
><title>Cluster Test<
/title
><
/head
>
<body>
<%
//HttpSession
session = request.getSession(
true
);
System.out.println(session.getId());
out.println(
"<br> SESSION ID:"
+ session.getId()+
"<br>"
);
%>
<
/body
>
将上面的tomcat-session拷贝到tomcat2的同路径下
[root@linux-node3 tomcat-session]
# cp -r ../tomcat-session /usr/local/tomcat2/webapps/ROOT/
|
本机绑定hosts进行访问测试:
110.110.115.118 www.wangshibo.com
测试步骤(服务器上iptables防火墙开通相应web端口)
a)访问http://www.wangshibo.com/tomcat-session,显示出Session ID值,说明nginx反向代理tomcat运行正常。
b)按F5刷新屡次,看看Session ID是否会变化。若是Session ID指一直不变,说明Session ID共享成功;反之,共享不成功!
c)关闭其中一个tomcat实例,观察页面的Session ID是否有变化,若是Session ID一直不变,则表示Session ID已经共享到其余tomcat实例上)了。
响应速度:
MSM在Session管理时,Tomcat中会保持本地Session,往Memcached中的同步是异步完成的,因此访问速度和普通模式没什么区别。
惟一有区别的是,tomcat实例关闭后的首次访问时,响应速度会变慢,可是持续一小段时间后续访问速度恢复正常。
-------------------------------------------------扩展------------------------------------------------------
以上介绍了nginx+tomcat+memcached实现session共享集群的操做记录,下面再追加一些须要注意的东西:
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
|
上面采用了效率最高的kryo序列化tomcat配置,固然还有其余四种序列化tomcat的配置方法,分别是:
a)java默认序列化tomcat配置,conf
/context
.xml添加:
<Manager className=
"de.javakaffee.web.msm.MemcachedBackupSessionManager"
memcachedNodes=
"n1:192.168.100.208:11211 n2:192.168.100.208:11311"
lockingMode=
"auto"
sticky=
"false"
requestUriIgnorePattern=
".*\.(png|gif|jpg|css|js)$"
sessionBackupAsync=
"false"
sessionBackupTimeout=
"100"
transcoderFactoryClass=
"de.javakaffee.web.msm.JavaSerializationTranscoderFactory"
/>
lib下须要增长的jar包:
spymemcached-2.10.3.jar
memcached-session-manager-1.7.0.jar
memcached-session-manager-tc7-1.7.0.jar
b)javolution序列化tomcat配置,conf
/context
.xml添加:
<Manager className=
"de.javakaffee.web.msm.MemcachedBackupSessionManager"
memcachedNodes=
"n1:192.168.100.208:11211 n2:192.168.100.208:11311"
lockingMode=
"auto"
sticky=
"false"
requestUriIgnorePattern=
".*\.(png|gif|jpg|css|js)$"
sessionBackupAsync=
"false"
sessionBackupTimeout=
"100"
copyCollectionsForSerialization=
"true"
transcoderFactoryClass=
"de.javakaffee.web.msm.serializer.javolution.JavolutionTranscoderFactory"
/>
lib下须要增长的jar包:
msm-javolution-serializer-cglib-1.3.0.jar
msm-javolution-serializer-jodatime-1.3.0.jar
spymemcached-2.10.3.jar
javolution-5.4.3.1.jar
msm-javolution-serializer-1.7.0.jar
memcached-session-manager-1.7.0.jar
memcached-session-manager-tc7-1.7.0.jar
c)xstream序列化tomcat配置,conf
/context
.xml添加:
<Manager className=
"de.javakaffee.web.msm.MemcachedBackupSessionManager"
memcachedNodes=
"n1:192.168.100.208:11211 n2:192.168.100.208:11311"
lockingMode=
"auto"
sticky=
"false"
requestUriIgnorePattern=
".*\.(png|gif|jpg|css|js)$"
sessionBackupAsync=
"false"
sessionBackupTimeout=
"100"
transcoderFactoryClass=
"de.javakaffee.web.msm.serializer.xstream.XStreamTranscoderFactory"
/>
lib下须要增长的jar包:
xmlpull-1.1.3.1.jar
xpp3_min-1.1.4c.jar
xstream-1.4.6.jar
msm-xstream-serializer-1.7.0.jar
spymemcached-2.10.3.jar
memcached-session-manager-1.7.0.jar
memcached-session-manager-tc7-1.7.0.jar
d)flexjson序列化tomcat配置,conf
/context
.xml添加:
<Manager className=
"de.javakaffee.web.msm.MemcachedBackupSessionManager"
memcachedNodes=
"n1:192.168.100.208:11211 n2:192.168.100.208:11311"
lockingMode=
"auto"
sticky=
"false"
requestUriIgnorePattern=
".*\.(png|gif|jpg|css|js)$"
sessionBackupAsync=
"false"
sessionBackupTimeout=
"100"
transcoderFactoryClass=
"de.javakaffee.web.msm.serializer.json.JSONTranscoderFactory"
/>
lib增长jar包
flexjson-3.1.jar
msm-flexjson-serializer-1.7.0.jar
spymemcached-2.10.3.jar
memcached-session-manager-1.7.0.jar
memcached-session-manager-tc7-1.7.0.jar
|
序列化tomcat配置中有关Manager各参数说明:
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
|
a)className
这个是必选项。可配置为:
de.javakaffee.web.msm.MemcachedBackupSessionManager
或者
de.javakaffee.web.msm.DummyMemcachedBackupSessionManager
其中DummyMemcachedBackupSessionManager可用于测试环境,不须要真实存在memcached
b)memcachedNodes
这个是必选项。memcached的节点信息(多个节点使用空格或逗号分开),格式如:
memcachedNodes=
"n1:app01:11211,n2:app02:11211"
。
c)failoverNodes
这个是可选项,不能使用在non-sticky sessions模式。
故障转移配置节点,多个使用空格或逗号分开,配置某个节点为备份节点,当其余节点都不可用时才会存储到备份节点,官方建议配置为和tomcat同服务器的节点。
理由以下:
假若有两台服务器m1,m2,其中m1部署tomcat和memcached节点n1,m2部署memcached节点n2。
若是配置tomcat的failoverNodes值为n2或者不配置,则当服务器m1挂掉后n1和tomcat中保存的session会丢失,而n2中未保存或者只保存了部分session,这就形成
部分用户状态丢失;
若是配置tomcat的failoverNodes值为n1,则当m1挂掉后由于n2中保存了全部的session,因此重启tomcat的时候用户状态不会丢失。
为何n2中保存了全部的session? 由于failoverNodes配置的值是n1,只有当n2节点不可用时才会把session存储到n1,因此这个时候n1中是没有保存任何session的。
d)lockingMode
这个是可选项,默认none,只对non-sticky有效。
当配置成node时,表示历来不加锁
当配置成all时,表示当请求时对Session锁定,直到请求结束
当配置成auto时,表示对只读的request不加锁,对非只读的request加锁
e)requestUriIgnorePattern
这个是可选项,制定忽略那些请求的session操做,通常制定静态资源如css,js一类的。
f)sessionBackupAsync
这个是可选项,默认
true
,是否异步的方式存储到memcached。
j)sessionBackupTimeout
这个是可选项,默认100毫秒,异步存储session的超时时间。即web工程对session的修改更新到memcache上的时间。
h)copyCollectionsForSerialization
这个是可选项,默认
false
。
i)transcoderFactoryClass
这个是可选项,默认值de.javakaffee.web.msm.JavaSerializationTranscoderFactory,制定序列化和反序列化数据到memcached的工厂类。
j)operationTimeout
这个是可选项,默认1000毫秒,memcached的操做超时时间。
k)backupThreadCount
这个是可选项,默认是cpu核心数,异步存储session的线程数。
l)storageKeyPrefix
这个是可选项,默认值webappVersion,存储到memcached的前缀,主要是为了区分多个webapp共享session的状况。可选值:静态字符串、host、context、webappVersion,多个使用逗号分割。 、
m)sessionAttributeFilter
这个是可选项,经过正则表达式肯定那些session中的属性应该被存储到memcached。例子如:sessionAttributeFilter=
"^(userName|sessionHistory)$"
。
|
再说下stick和non-stick的工做流程:
1
2
3
4
5
|
Sticky 模式:
tomcat session为主session,memcached为备session。Request请求到来时,从memcached加载备session到tomcat (仅当tomcat jvmroute发生变化时,不然直接取tomcat session);Request请求结束时,将tomcat session更新至memcached,以达到主备同步之目的。
Non-Sticky模式:
tomcat session为中转session,memcached1为主session,memcached2为备session。Request请求到来时,从memcached 2加载备session到tomcat,(当容器中仍是没有session则从memcached1加载主session到tomcat, 这种状况是只有一个memcached节点,或者有memcached1出错时), Request请求结束时,将tomcat session更新至主memcached1和备memcached2,而且清除tomcat session 。以达到主备同步之目的。 多台tomcat集群时 须要选择Non-Sticky模式,即sticky=
"false"
|
须要清除的是:
1
2
|
1)若是部署后,发现调试不成功,即session不共享,通常都是因为memcached-session-manager-1.7.0.jar、memcached-session-manager-tc7-1.7.0.jar和msm-kryo-serializer-1.7.0.jar这三个jar包出问题。因此版本也很重要。
2)服务器之间的时间戳一致也很是重要,由于时间不一致将直接致使session过时。
|