Linux运维昱笔记(十一):Tomcat优化之解决session问题

Session简介

应用服务器(Tomcat)的高可用负载均衡架构设计主要服务于服务无状态这一特性(静态页面),但是事实上,绝大多数生产业务总是有状态的,例如:交易类的电子商务网站,需要有购物车记录用户的购买信息,每次购买请求都是向购物车中增加新的商品;社交网站中,需要记录用户当前的登录状态,获取用户的个人信息、最新发布的消息及好友请求状态等,用户每次刷新页面都需要更新这些信息。

​ Session是由应用服务器维持的一个服务器端的存储空间(内存中),用户在连接服务器时,会由服务器生成一个唯一的SessionID,客户端使用该Session ID 为标识符来存取服务器端的Session存储空间。而Session ID则保存到客户端,使用浏览器Cookie保存的,用户提交页面请求时,也会将 Session ID提交到服务器端,来存取Session空间的数据。服务器也通过URL重写的方式来传递Session ID的值,因此不是完全依赖Cookie。如果客户端Cookie禁用,则服务器可以自动通过重写URL的方式来保存Session的值,并且这个过程对程序员透明。

​ WEB应用中将这些多次请求修改使用的上下文对象称作会话(Session),单机情况下,Session可由部署在服务器上的WEB容器(Tomcat、Resin)进行管理。但在使用高可用负载均衡的集群环境中,由于负载均衡服务器可能会将每次请求分发到集群任何一台应用服务器(Tomcat)上,所以保证每次请求依然能够获得正确的Session比在单机上实现要复杂的多。

环境描述:

ip地址 主机名 软件包列表
192.168.6.10 nginx nginx
192.168.6.11 node1 jdk tomcat
192.168.6.12 node2 jdk tomcat

配置过程

安装前准备配置

[root@localhost ~] cat /etc/hosts
192.168.6.10 nginx
192.168.6.11 node1
192.168.6.12 node2
[root@localhost ~] iptables -F
[root@localhost ~] systemctl stop firewalld
[root@localhost ~] setenforce 0

nginx服务器配置

[root@localhost ~] hostname nginx
[root@localhost ~] bash
[root@nginx ~] yum -y install pcre-devel zlib-devel openssl-devel
[root@nginx ~] useradd -s /sbin/nologin nginx
[root@nginx ~] tar xf nginx-1.6.2.tar.gz 
[root@nginx ~] cd nginx-1.6.2
[root@nginx nginx-1.6.2] ./configure --prefix=/usr/local/nginx --user=nginx --group=nginx --with-file-aio --with-http_stub_status_module --with-http_ssl_module --with-http_flv_module --with-http_gzip_static_module && make && make install

nginx配置负载均衡

[root@nginx ~] cd /usr/local/nginx/conf/nginx.conf
	upstream tomcat_pool {
	server 192.168.6.11:8080;
	server 192.168.6.12:8080;
    }
    server {
	listen 80;
        server_name 192.168.200.101:80;
        location / {
		proxy_pass http://tomcat_pool;
		proxy_set_header X-Real-IP $remote_addr;
	}

两台tomcat配置

[root@localhost ~] hostname node1  另外一台机器配置为node2
[root@localhost ~] bash
[root@node1 ~] rpm -qa | grep -i openjdk
java-1.8.0-openjdk-1.8.0.181-7.b13.el7.x86_64
java-1.8.0-openjdk-headless-1.8.0.181-7.b13.el7.x86_64
[root@node1 ~] rpm -e java-1.8.0-openjdk --nodeps
[root@node1 ~] rpm -e java-1.8.0-openjdk-headless
[root@node1 ~] tar xf jdk-8u91-linux-x64.tar.gz
[root@node1 ~] mv jdk1.8.0_91/ /usr/local/java
[root@node1 ~] vim /etc/profile    //最后一行添加
export JAVA_HOME=/usr/local/java   #设置java根目录
export PATH=$PATH:$JAVA_HOME/bin #在path环境变量中添加java根目录的bin子目录
[root@node1 ~] source /etc/profile
[root@node1 ~] java -version
java version "1.8.0_91"
Java(TM) SE Runtime Environment (build 1.8.0_91-b14)
Java HotSpot(TM) 64-Bit Server VM (build 25.91-b14, mixed mode)
[root@node1 ~] tar xf apache-tomcat-7.0.54.tar.gz 
[root@node1 ~] mv apache-tomcat-7.0.54 /usr/local/tomcat7
[root@node1 ~] /usr/local/tomcat7/startup.sh

编辑测试页面

[root@node1 ~] vim /usr/local/tomcat7/webapps/ROOT/session.jsp
Session ID:<%= session.getId() %><BR>
SessionPort:<%= request.getServerPort() %>
<% out.println("This tomcat server 192.168.6.11");%>
[root@node2 ~] vim /usr/local/tomcat7/webapps/ROOT/session.jsp
Session ID:<%= session.getId() %><BR>
SessionPort:<%= request.getServerPort() %>
<% out.println("This tomcat server 192.168.6.12");%>

方案一:Session绑定

​ Session绑定可以利用负载均衡的源地址Hash (ip hash) 算法实现。负载均衡服务器总是将来源于同一个IP的请求分发到同一台服务器上,也可以根据Cookie信息将同一个用户的请求总是分发到同一台服务器上。当然这时负载均衡服务器必须工作在HTTP 协议层上。这样整个会话期间,用户所有的请求都在同一-台服务器上处理,即Session绑定在某台特定服务器上,保证Session总能在这台服务器上获取。这种方法又被称为会话黏滞。

​ 但是session绑定的方案显然不符合我们对系统高可用的需求,因为一旦某台服务器宕机,那么该机器上的session也就不复存在了,用户请求切换到其他机器后因为没有session而无法完成业务处理,因此大部分负载均衡服务器都能提供源地址负载均衡算法,但很少用网站利用这个算法。

[root@nginx~] vim /usr/local/nginx/conf/nginx.conf
	upstream tomcat_pool {
		ip_hash;
		server 192.168.6.11:8080 weight=1 max_fails=1  fail_timeout=10s;
		server 192.168.6.12:8080 weight=1 max_fails=1  fail_timeout=10s;
	}
[root@nginx~] killall -HUP nginx

方案二:Session复制

​ Session复制是小型架构使用较多的一种服务器集群Session管理机制。应用服务器开启Web容器的Session复制功能,在集群中的几台服务器之间同步Session对象,使每台服务器上都保存了所有用户的Session信息,这样任何一台机器宕机都不会导致Session数据的丢失,而服务器使用Session时,也只需要在本机获取即可。
Linux运维昱笔记(十一):Tomcat优化之解决session问题_第1张图片
​ 这种方案实现简单,从本机读取Session信息也很快速,但只能应用在集群规模比较小的环境下。当集群规模较大时,集群服务器间需要大量的通信进行Session复制,占用服务器和网络的大量资源,系统不堪负担。而且由于所有用户的Session信息在每台服务器上都有备份,在大量用户访问的情况下,甚至会出现服务器内存不够Session使用的情况。

​ 而大型网站的核心应用集群就是数千台服务器,同时在线用户可达千万,因此并不适用这种方案。

修改tomcat配置文件(两台都要配置)

[root@node1 tomcat] vim /usr/local/tomcat/conf/server.xml
将Engine这一行修改为:
	<Engine name="Catalina" defaultHost="localhost">
	<Engine name="Catalina" defaultHost="localhost" jvmRoute="node1">	#tomcat2 配置为jvmRoute="node2"

	<Cluster className="org.apache.catalina.ha.tcp.SimpleTcpCluster"/> 	#去掉注释
	
[root@node1 ~] vim /usr/local/tomcat/webapps/ROOT/WEB-INF/web.xml 
<distributable/>   #添加内容
</web-app>
[root@node1 ~] /usr/local/tomcat7/bin/shutdown.sh
[root@node1 ~] /usr/local/tomcat7/bin/startup.sh
[root@node1 ~] netstat -anpt | grep -E ":(8080|4000)"
tcp        0      0 ::ffff:192.168.200.102:4000 :::*                        LISTEN      2149/java          tcp        0      0 :::8080                     :::*                        LISTEN      2149/java  

session组播地址设置

[root@node1 ~] route add -net 224.0.0.0 netmask 240.0.0.0 dev ens32
[root@node2 ~] route add -net 224.0.0.0 netmask 240.0.0.0 dev ens32

方案三:Session服务器之memcached

两台tomcat上安装memcached

[root@node1 ~] yum -y install libevent memcached
[root@node1 ~] memcached -u root -m 512M -n 10 -f 2 -d -vvv -c 512

选项

-h  #查看帮助信息
-p	#指定memcached监听的端口号默认11211
-l	#memcached服务器的ip地址
-u	#memcached程序运行时使用的用户身份必须是root用户
-m	#指定使用本机的多少物理内存存数据默认64M
-c	#memcached服务的最大连接数
-vvv	#显示详细信息
-n	#chunk size 的最小空间是多少单位字节
-f	#chunk size	大小正的倍数 默认1.25倍
-d	#在后台运行

查看是否启动(过滤11211端口)

[root@node1 ~] netstat -anpt |grep 11211
tcp        0      0 0.0.0.0:11211           0.0.0.0:*               LISTEN      17854/memcached     
tcp6       0      0 :::11211                :::*                    LISTEN      17854/memcached     

测试memcached能否存取数据

[root@node1 ~] yum -y install telnet
[root@node1 ~] telnet 192.168.6.12 11211
Trying 192.168.6.12...
Connected to 192.168.6.12.
Escape character is '^]'.
set username 0 0 8         #指定测试
zhangsan					#输入测试内容
STORED
get username 			#获取测试内容
VALUE username 0 8
zhangsan				#得到结果
END
quit			#退出
Connection closed by foreign host.

最后执行让 tomcat1 tomcat2 通过(msm)连接到Memcached

上传Tomcat7-Memcached_JAR包

将session包中的“*.jar复制到/usr/local/tomcat/lib/”

[root@node1 ~] mkdir session
[root@node1 ~] cd session/
[root@node1 session] rz

[root@node1 session] ls
javolution-5.5.1.jar                     minlog-1.2.jar
kryo-1.03.jar                            msm-javolution-serializer-1.5.1.jar
kryo-serializers-0.10.jar                msm-kryo-serializer-1.6.4.jar
memcached-2.5.jar                        reflectasm-0.9.jar
memcached-session-manager-1.5.1.jar      spymemcached-2.7.3.jar
memcached-session-manager-tc7-1.5.1.jar
[root@node1 ~] cp session/* /usr/local/tomcat7/lib/

编辑tomcat配置文件连接指定的memcached服务器,两台tomcat配置一样

[root@node1 ~] vim /usr/local/tomcat7/conf/context.xml  (倒数第二行添加)
<Context>
<Manager className="de.javakaffee.web.msm.MemcachedBackupSessionManager" memcachedNodes="memA:192.168.6.11:11211 memB:192.168.6.12:11211" requestUrilgnorePattern=".*\(ico|png|gif|jpg|css|js)$" transcoderFactoryClass="de.javakaffee.web.msm.serializer.kryo.KryoTranscoderFactory"/>
</Context>

如果成功,tomcat与Memcached端口会连在一起,前后有变化

tomcat1与tomcat2

[root@node1 ~] netstat -anpt | grep java
tcp6       0      0 :::8009                 :::*                    LISTEN      18353/java          
tcp6       0      0 :::8080                 :::*                    LISTEN      18353/java          
tcp6       0      0 192.168.6.11:33196      192.168.6.11:11211      ESTABLISHED 18353/java          
tcp6       0      0 192.168.6.11:45260      192.168.6.12:11211      ESTABLISHED 18353/java          
tcp6       0      0 192.168.6.11:33192      192.168.6.11:11211      ESTABLISHED 18353/java          
tcp6       0      0 192.168.6.11:45264      192.168.6.12:11211      ESTABLISHED 18353/java

验证

访问192.168.6.10 session id 不变 tomcat服务器变

方案四:session服务器之Redis

redis与memcached的区别

  • 内存利用率:使用简单的key-value(键值对)存储的话,memcached的内存利用率更高,而如果redis采用hash结构来做key-vlaus存储,由于其组合的压缩,其内存利用率会高于memcached。
  • 性能对比:由于redis只使用单核,而memcached可以使用多核,**所以平均每一个核上redis在存储小数据时memcached性能更高。而在100k以上的数据中,memcached性能要高于redis。**虽然redis最近也在存储大数据的性能上进行优化,但是比起memcached还是稍有逊色.
  • redis支持数据的持久化,可以将内存中的数据保持在磁盘中,重启时候可以再次加载进行使用。
  • redis支持数据备份,既master-slave模式的数据备份。
  • redis不仅仅支持简单的key-value类型的数据,同时还提供list,st,zset,hash等数据结构的存储。

将之前从session中复制到/usr/local/tomcat/lib中的文件删除

[root@localhost ~] ls session/ | while read line;do rm -rf /usr/local/tomcat7/lib/$line;done

安装部署redis

[root@localhost ~] tar xf redis-4.0.6.tar.gz -C /usr/src/
[root@localhost ~] cd /usr/src/redis-4.0.6
[root@localhost redis-4.0.6] make

如果安装出现问题报错测需要安装tcl

[root@localhost ~] wget http://downloads.sourceforge.net/tcl/tcl8.5.9-src.tar.gz
[root@localhost ~] cd /tcl8.5.9-src/unix
[[email protected] ~] ./configure && make && make install

接着make就没报错了

配置相关文件

[root@node1 ~] mkdir -p /usr/local/redis/{bin,etc,var}
[root@node1 ~] cd /usr/src/redis-4.0.6/src

src目录下这些文件的作用

edis-server: Redis服务器的daemon启动程序
redis-cli: Redis命令行操作工具你也可以用telnet根据其纯文本协议来操作

redis-benchmark: Redis 性能测试工具,测试Redis在你的系统及你的配置下的读写性能

redis-stat: Redis 状态检测工具,可以检测Redis当前状态参数及延迟状况

[root@node1 src] cp redis-benchmark redis-check-aof redis-cli redis-server  /usr/local/redis/bin/
[root@node1 src] cp ../redis.conf  /usr/local/redis/etc/
[root@node1 src] vim /usr/local/redis/etc/redis.conf   //修改配置文件
bind 127.0.0.0改为bind0.0.0.0                       #改成监听到本机的任意IP
daemonize no改为daemonize yes                 #以进程的方式启动

关闭redis

[root@node1 ~] kill -9 redis-server

开启redis

[root@node1 ~] /usr/local/redis/bin/redis-server /usr/local/redis/etc/redis.conf

查看是否启动

[root@node1 ~] netstat -anpt | grep redis
tcp        0      0 0.0.0.0:6379            0.0.0.0:*               LISTEN      21064/redis-server

监控redis共享session:

[root@node1 ~] /usr/local/redis/bin/redis-cli -p 6379 monitor
OK

将tomcat需要调用redis的jar包放入tomcat/lib

[root@node1 ~] mkdir redis
[root@node1 ~] cd redis
[root@node1 redis] rz

[root@node1 redis] cp tomcat-redis-session-manage-tomcat7.jar tomcat-juli.jar commons-logging-1.1.3.jar commons-pool2-2.2.jar jedis-2.5.2.jar /usr/local/tomcat7/lib/

修改tomcat相关文件

[root@node1 redis-3.2.5] vim /usr/local/tomcat7/conf/context.xml
在Context段中加入以下内容
<Valve className="com.orangefunction.tomcat.redissessions.RedisSessionHandlerValve" /> <Manager className="com.orangefunction.tomcat.redissessions.RedisSessionManager"  
host="192.168.6.11"   //redis的ip地址 (注意node2也写node1的ip)
port="6379"   //redis的端口
database="0"  
maxInactiveInterval="60" />
[root@node1 ~] /usr/local/tomcat7/bin/shutudown.sh
[root@node1 ~] /usr/local/tomcat7/bin/startup.sh

验证

192.168.6.10 sessionid不变 ip改变

你可能感兴趣的:(Linux)