第444集Tomcat集群会话共享实战
|字数总计:6.3k|阅读时长:27分钟|阅读量:
Tomcat集群会话共享实战
1. 概述
1.1 集群会话共享的重要性
在Web应用集群部署中,会话共享(Session Sharing)是实现高可用和负载均衡的关键技术。当用户请求被分发到不同的Tomcat服务器时,必须保证用户的Session信息在所有服务器间共享,否则用户登录状态会丢失,导致用户体验问题。
会话共享的价值:
- 高可用性:单台服务器故障不影响用户会话
- 负载均衡:请求可以分发到任意服务器
- 水平扩展:可以动态增加服务器节点
- 用户体验:用户无需重复登录
1.2 会话共享方案对比
| 方案 |
优点 |
缺点 |
适用场景 |
| Session Sticky |
实现简单,性能好 |
单点故障,扩展性差 |
小规模集群 |
| Session Replication |
无单点故障 |
性能损耗大,网络开销 |
小规模集群 |
| Session集中存储 |
扩展性好,性能稳定 |
依赖外部存储 |
大规模集群(推荐) |
1.3 本文内容结构
本文将从以下几个方面详细介绍Tomcat集群会话共享:
- Redis介绍:Redis特性、与Memcached对比
- Session保持方案:三种主要方案的对比
- Nginx+Tomcat+Redis架构:完整实现方案
- Redis安装配置:Redis部署和配置
- Tomcat Session配置:Redis Session Manager配置
- 测试验证:功能测试和性能测试
- 故障排查:常见问题和解决方案
- 生产环境优化:性能优化和最佳实践
2. Redis介绍
2.1 Redis简介
Redis(Remote Dictionary Server)是一个开源的、基于内存的数据结构存储系统,可以用作数据库、缓存和消息中间件。Redis支持多种数据结构,包括字符串(string)、列表(list)、集合(set)、有序集合(sorted set)和哈希(hash)。
Redis核心特性:
- 高性能:基于内存存储,读写速度极快
- 数据结构丰富:支持多种数据结构
- 持久化:支持RDB和AOF两种持久化方式
- 主从复制:支持主从模式数据备份
- 集群模式:支持Redis Cluster集群
2.2 Redis与Memcached对比
2.2.1 网络IO模型
Memcached:
- 多线程模型:使用多线程、非阻塞IO复用
- 架构:监听主线程 + worker子线程
- 网络层:使用libevent封装的事件库
- 优势:多线程可以发挥多核CPU优势
Redis:
- 单线程模型:使用单线程的IO复用模型
- 事件框架:自己封装的AeEvent事件处理框架
- 支持:epoll、kqueue、select
- 优势:对于纯IO操作,单线程速度优势最大
- 劣势:计算操作会阻塞IO调度
对比总结:
- Memcached适合多核CPU环境
- Redis单线程模型适合IO密集型操作
- Redis的计算功能(排序、聚合)会影响整体吞吐量
2.2.2 内存管理
Memcached:
- 预分配内存池:使用slab和不同大小的chunk管理内存
- 内存分配:value根据大小选择合适的chunk存储
- 特点:内存利用率可能不高,但分配速度快
Redis:
- 现场申请内存:使用现场申请内存的方式存储数据
- 内存优化:支持内存淘汰策略(LRU、LFU等)
- 特点:内存利用率高,但可能产生内存碎片
对比总结:
- Memcached内存管理更简单,但可能浪费内存
- Redis内存管理更灵活,但需要关注内存碎片
2.2.3 存储方式
Memcached:
- 数据结构:只支持简单的key-value存储
- 持久化:不支持数据持久化
- 复制:不支持主从复制
- 特点:纯内存缓存,重启后数据丢失
Redis:
- 数据结构:支持string、list、set、zset、hash等
- 持久化:支持RDB快照和AOF日志两种方式
- 复制:支持主从复制和哨兵模式
- 集群:支持Redis Cluster集群模式
- 特点:功能丰富,可以持久化数据
对比总结:
- Memcached功能简单,适合纯缓存场景
- Redis功能丰富,适合更多业务场景
2.2.4 数据交换机制
Redis的Swap机制:
Redis并不是所有数据都一直存储在内存中。当内存使用量超过阈值时,Redis会触发swap操作:
- 计算swappability:根据公式
swappability = age * log(size_in_memory) 计算
- 选择swap对象:选择需要swap到磁盘的key对应的value
- 持久化到磁盘:将这些value持久化到磁盘
- 内存清除:在内存中清除这些数据
特点:
- 所有key信息必须保持在内存中
- 只有value会被swap到磁盘
- 读取时如果value不在内存,会从swap文件加载
2.3 Redis适用场景
适合使用Redis的场景:
- Session存储:分布式Session共享
- 缓存:热点数据缓存
- 计数器:访问量、点赞数等
- 消息队列:简单的消息队列
- 排行榜:使用有序集合实现
- 分布式锁:实现分布式锁
不适合使用Redis的场景:
- 大数据量存储:数据量超过内存容量
- 复杂查询:需要复杂SQL查询
- 事务强一致性:需要ACID特性
3. 如何保持Session会话
3.1 Session会话问题
在集群环境下,用户的请求可能被分发到不同的服务器,如果Session只存储在单台服务器上,会导致:
- 用户登录状态丢失
- 购物车信息丢失
- 用户需要重复登录
3.2 Session保持方案
3.2.1 方案一:Session Sticky(会话粘性)
原理:
- 基于访问IP的hash策略
- 将同一用户的请求都定位到同一台服务器
- 单台服务器保存用户的Session信息
实现方式:
1 2 3 4 5 6
| upstream backend_tomcat { ip_hash; server 192.168.6.241:8080; server 192.168.6.242:8080; }
|
优点:
- 实现简单,无需额外配置
- 性能好,Session存储在本地内存
- 无网络开销
缺点:
- 单点故障:服务器宕机,Session丢失
- 扩展性差:增加或减少服务器需要重新hash
- 负载不均:某些IP可能集中在某台服务器
适用场景:
- 小规模集群
- 对Session丢失不敏感的应用
- 临时方案
3.2.2 方案二:Session Replication(会话复制)
原理:
- 集群环境下,多台应用服务器之间同步Session
- 每台服务器都保存所有Session的副本
- 当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
| <Cluster className="org.apache.catalina.ha.tcp.SimpleTcpCluster"> <Channel className="org.apache.catalina.tribes.group.GroupChannel"> <Membership className="org.apache.catalina.tribes.membership.McastService" address="228.0.0.4" port="45564" frequency="500" dropTime="3000"/> <Receiver className="org.apache.catalina.tribes.transport.nio.NioReceiver" address="auto" port="4000" autoBind="100" selectorTimeout="5000" maxThreads="6"/> <Sender className="org.apache.catalina.tribes.transport.ReplicationTransmitter"> <Transport className="org.apache.catalina.tribes.transport.nio.PooledParallelSender"/> </Sender> <Interceptor className="org.apache.catalina.tribes.group.interceptors.TcpFailureDetector"/> <Interceptor className="org.apache.catalina.tribes.group.interceptors.MessageDispatch15Interceptor"/> </Channel> <Valve className="org.apache.catalina.ha.tcp.ReplicationValve" filter=""/> <Valve className="org.apache.catalina.ha.session.JvmRouteBinderValve"/> <ClusterListener className="org.apache.catalina.ha.session.JvmRouteSessionIDBinderListener"/> <ClusterListener className="org.apache.catalina.ha.session.ClusterSessionListener"/> </Cluster>
|
优点:
- 无单点故障,任何服务器都可以处理请求
- 实现相对简单,Tomcat自带支持
- 无需外部依赖
缺点:
- 性能损耗大:Session复制消耗CPU和内存
- 网络开销:广播Session数据占用网络带宽
- 扩展性差:服务器越多,复制开销越大
- 内存占用:每台服务器都保存所有Session
适用场景:
- 小规模集群(2-4台服务器)
- Session数据量小
- 对性能要求不高的应用
3.2.3 方案三:Session集中存储(推荐)
原理:
- 使用外部存储(Redis、Memcached)存储Session
- 应用服务器接受请求时,从外部存储读取Session
- Session变化时,更新到外部存储
架构图:
1 2 3 4 5 6 7
| 用户请求 ↓ Nginx(负载均衡) ↓ ├──→ Tomcat-1 → Redis(Session存储) ├──→ Tomcat-2 → Redis(Session存储) └──→ Tomcat-N → Redis(Session存储)
|
优点:
- 高可用:Redis支持主从和集群,高可用
- 扩展性好:可以动态增加Tomcat服务器
- 性能稳定:Session集中管理,性能可控
- 无单点故障:Redis集群保证高可用
缺点:
- 依赖外部存储:需要维护Redis服务
- 网络延迟:每次Session操作需要网络请求
- 配置复杂:需要配置Redis和Session Manager
适用场景:
- 大规模集群(推荐)
- 对高可用要求高的应用
- 需要水平扩展的场景
3.3 方案选择建议
选择原则:
- 小规模集群(<4台):Session Replication
- 中大规模集群(>4台):Session集中存储(Redis)
- 临时方案:Session Sticky
- 高可用要求:Session集中存储(Redis)
4. Nginx+Tomcat+Redis实现负载均衡、Session共享
4.1 实验环境
4.1.1 主机规划
| 主机 |
操作系统 |
IP地址 |
角色 |
| Nginx |
CentOS 7.4 |
192.168.6.240 |
负载均衡器 |
| Tomcat-1 |
CentOS 7.4 |
192.168.6.241 |
应用服务器1 |
| Tomcat-2 |
CentOS 7.4 |
192.168.6.242 |
应用服务器2 |
| Redis |
CentOS 7.4 |
192.168.6.244 |
Session存储 |
| MySQL |
CentOS 7.4 |
192.168.6.244 |
数据库 |
4.1.2 实验拓扑
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| Internet | ↓ [Nginx] 192.168.6.240 | ┌──────────────┴──────────────┐ ↓ ↓ [Tomcat-1] [Tomcat-2] 192.168.6.241 192.168.6.242 | | └──────────────┬──────────────┘ ↓ [Redis] 192.168.6.244 | ↓ [MySQL] 192.168.6.244
|
架构说明:
- Nginx作为反向代理,实现负载均衡
- 将静态资源直接返回,动态请求转发给Tomcat
- 两台Tomcat服务器共享Redis中的Session
- MySQL作为后端数据库
4.2 Nginx安装配置
4.2.1 安装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
| yum install pcre pcre-devel -y yum install openssl openssl-devel -y
mkdir -p /home/oldboy/tools cd /home/oldboy/tools/
wget -q http://nginx.org/download/nginx-1.6.2.tar.gz
useradd nginx -s /sbin/nologin -M
mkdir /application/ tar xf nginx-1.6.2.tar.gz cd nginx-1.6.2
./configure \ --user=nginx \ --group=nginx \ --prefix=/application/nginx1.6.2 \ --with-http_stub_status_module \ --with-http_ssl_module \ --with-http_realip_module
make && make install
ln -s /application/nginx1.6.2/ /application/nginx
|
4.2.2 配置Nginx反向代理
编辑nginx.conf:
1
| vim /application/nginx/conf/nginx.conf
|
完整配置:
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
| 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"';
upstream backend_tomcat { 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 { listen 80; server_name www.98yz.cn; charset utf-8; access_log logs/access.log main; error_log logs/error.log; 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_set_header X-Forwarded-Proto $scheme; proxy_connect_timeout 60s; proxy_send_timeout 60s; proxy_read_timeout 60s; 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 127.0.0.1; allow 192.168.6.0/24; deny all; } } }
|
配置说明:
upstream backend_tomcat:定义Tomcat服务器组
weight:权重,可以调整流量分配
max_fails:最大失败次数
fail_timeout:失败超时时间
proxy_next_upstream:错误时切换到下一台服务器
4.2.3 启动Nginx
1 2 3 4 5 6 7 8
| /application/nginx/sbin/nginx -t
/application/nginx/sbin/nginx
netstat -tunlp | grep nginx
|
4.3 安装部署Tomcat应用服务器
4.3.1 安装JDK
在Tomcat-1和Tomcat-2节点上安装JDK:
1 2 3 4 5
| yum install java-1.8.0-openjdk java-1.8.0-openjdk-devel -y
java -version
|
输出示例:
1 2 3
| openjdk version "1.8.0_201" OpenJDK Runtime Environment (build 1.8.0_201-b09) OpenJDK 64-Bit Server VM (build 25.201-b09, mixed mode)
|
方式2:手动安装JDK(推荐生产环境):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| cd /soft/src wget https://download.oracle.com/java/8/latest/jdk-8uXXX-linux-x64.tar.gz
tar xf jdk-8uXXX-linux-x64.tar.gz -C /application/
ln -s /application/jdk1.8.0_XXX /application/jdk
cat >> /etc/profile << 'EOF' export JAVA_HOME=/application/jdk export PATH=$JAVA_HOME/bin:$PATH export CLASSPATH=.:$JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jar EOF
source /etc/profile
|
4.3.2 安装Tomcat
在Tomcat-1节点:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| mkdir -p /soft/src cd /soft/src
wget https://mirrors.aliyun.com/apache/tomcat/tomcat-9/v9.0.16/bin/apache-tomcat-9.0.16.tar.gz
tar xf apache-tomcat-9.0.16.tar.gz -C /soft
cd /soft cp -r apache-tomcat-9.0.16/ tomcat-8080
cd tomcat-8080/
|
在Tomcat-2节点执行相同操作
4.3.3 配置Tomcat
编辑server.xml(Tomcat-1):
1
| vim /soft/tomcat-8080/conf/server.xml
|
修改Engine配置:
1 2
| <Engine name="Catalina" defaultHost="localhost" jvmRoute="tomcat-1">
|
修改Host配置:
1 2 3 4 5 6
| <Host name="localhost" appBase="webapps" unpackWARs="true" autoDeploy="true"> <Context docBase="/web/webapp1" path="" reloadable="true"/> </Host>
|
Tomcat-2配置类似,但jvmRoute不同:
1
| <Engine name="Catalina" defaultHost="localhost" jvmRoute="tomcat-2">
|
4.3.4 创建测试应用
在Tomcat-1节点:
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
| mkdir -p /web/webapp1 cd /web/webapp1
cat > index.jsp << 'EOF' <%@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-1</font></h1> <table align="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> <tr> <td>Server Info</td> <td>tomcat-1 (192.168.6.241)</td> </tr> </table> </body> </html> EOF
|
在Tomcat-2节点:
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
| mkdir -p /web/webapp1 cd /web/webapp1
cat > index.jsp << 'EOF' <%@page language="java" import="java.util.*" pageEncoding="UTF-8"%> <html> <head> <title>tomcat-2</title> </head> <body> <h1><font color="blue">Session serviced by tomcat-2</font></h1> <table align="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> <tr> <td>Server Info</td> <td>tomcat-2 (192.168.6.242)</td> </tr> </table> </body> </html> EOF
|
4.3.5 启动Tomcat
1 2 3 4 5 6 7 8 9
| /soft/tomcat-8080/bin/startup.sh
netstat -tunlp | grep java ps -ef | grep [j]ava
tail -f /soft/tomcat-8080/logs/catalina.out
|
4.3.6 验证负载均衡
访问测试:
- 访问:
http://192.168.6.240/
- 多次刷新,观察Session ID和服务器信息
预期结果:
- 请求会分发到不同的Tomcat服务器
- Session ID每次可能不同(因为还没有配置Session共享)
5. 安装Redis
5.1 Redis安装方式
5.1.1 方式一:YUM安装(简单)
1 2 3 4 5 6 7 8 9 10 11 12 13
| yum install epel-release -y
yum install redis -y
systemctl start redis systemctl enable redis
redis-cli ping
|
5.1.2 方式二:源码编译安装(推荐生产环境)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| yum install gcc gcc-c++ -y
cd /soft/src wget http://download.redis.io/releases/redis-6.2.6.tar.gz
tar xf redis-6.2.6.tar.gz cd redis-6.2.6
make && make install PREFIX=/application/redis
ln -s /application/redis /application/redis-6.2.6
mkdir -p /application/redis/conf mkdir -p /application/redis/data mkdir -p /application/redis/logs
|
5.1.3 方式三:使用宝塔面板安装
5.2 Redis配置
5.2.1 基本配置
编辑redis.conf:
1
| vim /application/redis/conf/redis.conf
|
关键配置:
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
| # 绑定IP(0.0.0.0表示监听所有IP) bind 0.0.0.0
# 端口 port 6379
# 守护进程模式 daemonize yes
# PID文件 pidfile /var/run/redis_6379.pid
# 日志文件 logfile /application/redis/logs/redis.log
# 数据目录 dir /application/redis/data
# 持久化配置 save 900 1 save 300 10 save 60 10000
# 密码配置(重要) requirepass pwd@123
# 最大内存 maxmemory 2gb maxmemory-policy allkeys-lru
|
5.2.2 启动Redis
1 2 3 4 5 6 7 8 9 10
| /application/redis/bin/redis-server /application/redis/conf/redis.conf
systemctl start redis systemctl enable redis
redis-cli -a pwd@123 ping
|
5.2.3 测试Redis
1 2 3 4 5 6 7 8 9
| redis-cli -a pwd@123
127.0.0.1:6379> set test "hello" OK 127.0.0.1:6379> get test "hello" 127.0.0.1:6379> exit
|
6. 配置Tomcat Session Redis同步
6.1 下载Tomcat Redis Session Manager
6.1.1 下载地址
GitHub地址:
6.1.2 下载和安装
在Tomcat-1节点:
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| cd /soft/tomcat-8080/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/
|
在Tomcat-2节点执行相同操作
6.2 配置Redis连接
6.2.1 编辑Redis配置文件
编辑redis-data-cache.properties:
1
| vim /soft/tomcat-8080/conf/redis-data-cache.properties
|
配置内容:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
|
redis.hosts=192.168.6.244:6379
redis.password=pwd@123
redis.cluster.enabled=false
redis.database=0
redis.timeout=2000
|
集群模式配置(如果使用Redis Cluster):
1 2 3 4 5 6 7 8
| redis.cluster.enabled=true
redis.hosts=192.168.6.244:6379,192.168.6.245:6379,192.168.6.246:6379
|
6.3 配置Tomcat Context
6.3.1 编辑context.xml
编辑context.xml:
1
| vim /soft/tomcat-8080/conf/context.xml
|
添加Redis Session Manager配置:
1 2 3 4 5 6 7 8
| <?xml version="1.0" encoding="UTF-8"?> <Context> <Valve className="tomcat.request.session.redis.SessionHandlerValve" /> <Manager className="tomcat.request.session.redis.SessionManager" /> </Context>
|
完整context.xml示例:
1 2 3 4 5 6 7 8 9 10 11 12 13
| <?xml version="1.0" encoding="UTF-8"?> <Context> <Resource name="jdbc/TestDB" auth="Container" type="javax.sql.DataSource" maxTotal="100" maxIdle="30" maxWaitMillis="10000" username="root" password="password" driverClassName="com.mysql.jdbc.Driver" url="jdbc:mysql://192.168.6.244:3306/testdb"/> <Valve className="tomcat.request.session.redis.SessionHandlerValve" /> <Manager className="tomcat.request.session.redis.SessionManager" /> </Context>
|
6.4 配置Session超时时间
6.4.1 编辑web.xml
编辑web.xml:
1
| vim /soft/tomcat-8080/conf/web.xml
|
添加Session配置:
1 2 3 4 5 6 7 8 9 10
| <session-config> <session-timeout>60</session-timeout> <cookie-config> <http-only>true</http-only> <secure>false</secure> </cookie-config> </session-config>
|
6.5 启动Tomcat并验证
6.5.1 启动Tomcat
1 2 3 4 5
| /soft/tomcat-8080/bin/startup.sh
tail -f /soft/tomcat-8080/logs/catalina.out
|
检查日志中是否有Redis连接信息:
1 2
| INFO: Redis Session Manager initialized INFO: Connected to Redis at 192.168.6.244:6379
|
6.5.2 验证Session共享
测试步骤:
访问应用:
- 访问:
http://192.168.6.240/
- 记录Session ID
多次刷新:
- 多次刷新页面
- 观察Session ID是否一致
- 观察服务器信息是否变化
验证结果:
- Session ID应该一致:说明Session共享成功
- 服务器信息可能变化:说明负载均衡正常
6.5.3 验证Redis中的Session
1 2 3 4 5 6 7 8 9 10 11
| redis-cli -a pwd@123
127.0.0.1:6379> KEYS *session*
127.0.0.1:6379> GET "session:xxxxx"
127.0.0.1:6379> TTL "session:xxxxx"
|
7. 测试验证
7.1 功能测试
7.1.1 Session一致性测试
测试脚本:
1 2 3 4 5 6
| for i in {1..10}; do echo "Request $i:" curl -s -c /tmp/cookies.txt -b /tmp/cookies.txt http://192.168.6.240/ | grep "Session ID" sleep 1 done
|
预期结果:
- 所有请求的Session ID应该相同
- 说明Session共享成功
7.1.2 负载均衡测试
测试脚本:
1 2 3 4
| for i in {1..20}; do curl -s http://192.168.6.240/ | grep "Server Info" done | sort | uniq -c
|
预期结果:
- 请求应该分发到不同的Tomcat服务器
- 说明负载均衡正常
7.1.3 故障转移测试
测试步骤:
停止一台Tomcat:
1
| /soft/tomcat-8080/bin/shutdown.sh
|
继续访问:
恢复Tomcat:
1
| /soft/tomcat-8080/bin/startup.sh
|
7.2 性能测试
7.2.1 使用Apache Bench测试
1 2 3 4 5 6 7 8 9 10
| yum install httpd-tools -y
ab -n 1000 -c 100 -C "JSESSIONID=xxx" http://192.168.6.240/
|
7.2.2 监控指标
监控项:
- 响应时间:平均响应时间、最大响应时间
- 吞吐量:每秒请求数(QPS)
- 错误率:4xx、5xx错误比例
- Redis性能:Redis连接数、命令执行时间
8. 故障排查
8.1 常见问题
8.1.1 Redis连接失败
问题现象:
排查步骤:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| redis-cli -a pwd@123 ping
telnet 192.168.6.244 6379
firewall-cmd --list-ports iptables -L -n
grep -E "bind|requirepass" /application/redis/conf/redis.conf
cat /soft/tomcat-8080/conf/redis-data-cache.properties
|
解决方案:
- 确保Redis服务运行
- 检查防火墙规则
- 验证密码配置
- 检查网络连通性
8.1.2 Session不共享
问题现象:
排查步骤:
1 2 3 4 5 6 7 8 9 10 11 12
| redis-cli -a pwd@123 KEYS *session*
tail -f /soft/tomcat-8080/logs/catalina.out | grep -i session
cat /soft/tomcat-8080/conf/context.xml | grep -i session
ls -lh /soft/tomcat-8080/lib/ | grep redis
|
解决方案:
- 确保JAR包正确安装
- 检查context.xml配置
- 验证Redis连接
- 检查Session Manager配置
8.1.3 性能问题
问题现象:
排查步骤:
1 2 3 4 5 6 7 8 9 10 11
| redis-cli -a pwd@123 --latency
redis-cli -a pwd@123 INFO clients
redis-cli -a pwd@123 INFO memory
jstack <pid> | grep -i thread
|
解决方案:
- 优化Redis配置
- 增加连接池大小
- 优化Session数据大小
- 考虑使用Redis集群
9. 生产环境优化
9.1 Redis优化
9.1.1 内存优化
1 2 3 4 5 6 7 8 9 10
| # redis.conf # 设置最大内存 maxmemory 4gb
# 内存淘汰策略 maxmemory-policy allkeys-lru
# 启用内存压缩 hash-max-ziplist-entries 512 hash-max-ziplist-value 64
|
9.1.2 持久化优化
1 2 3 4 5 6 7 8
| # RDB配置 save 900 1 save 300 10 save 60 10000
# AOF配置 appendonly yes appendfsync everysec
|
9.1.3 连接池优化
1 2 3 4 5 6
|
redis.maxTotal=200 redis.maxIdle=50 redis.minIdle=10 redis.maxWaitMillis=5000
|
9.2 Tomcat优化
9.2.1 Session优化
1 2 3 4 5
| <session-config> <session-timeout>30</session-timeout> </session-config>
|
9.2.2 JVM优化
1 2 3 4 5 6 7
| JAVA_OPTS="$JAVA_OPTS \ -server \ -Xms2g \ -Xmx2g \ -XX:+UseG1GC \ -XX:MaxGCPauseMillis=200"
|
9.3 高可用方案
9.3.1 Redis主从复制
1 2 3
| # 从服务器配置 slaveof 192.168.6.244 6379 masterauth pwd@123
|
9.3.2 Redis哨兵模式
1 2 3
| # sentinel.conf sentinel monitor mymaster 192.168.6.244 6379 2 sentinel auth-pass mymaster pwd@123
|
9.3.3 Redis集群模式
1 2 3
| redis.cluster.enabled=true redis.hosts=192.168.6.244:6379,192.168.6.245:6379,192.168.6.246:6379
|
10. 总结
10.1 核心要点
- Session共享方案:Session Sticky、Session Replication、Session集中存储
- Redis优势:高性能、数据结构丰富、支持持久化
- 架构设计:Nginx负载均衡 + Tomcat集群 + Redis Session存储
- 配置要点:Redis连接配置、Tomcat Context配置
- 高可用:Redis主从、哨兵、集群模式
10.2 架构师建议
方案选择:
- 小规模集群:Session Replication
- 大规模集群:Redis Session存储(推荐)
高可用设计:
- Redis主从复制
- Redis哨兵模式
- Redis集群模式
性能优化:
- Redis内存优化
- 连接池优化
- Session数据优化
10.3 最佳实践
- 安全配置:Redis密码、防火墙规则
- 监控告警:Redis性能监控、Session监控
- 备份恢复:Redis数据备份、Session恢复
- 容量规划:根据用户量规划Redis容量
相关文章: