第十章-Tomcat性能测试与实战案例
🚀 第十章:Tomcat 性能测试与实战案例
目录
- 10.1 压测工具使用
- 10.2 性能对比测试
- 10.3 高并发场景模拟
- 10.4 多节点集群配置
- 10.5 生产环境调优模板
- 10.6 实战案例分析
- 10.7 本章小结
10.1 压测工具使用
10.1.1 JMeter 压测工具
JMeter 安装与配置
# 下载 JMeter
wget https://archive.apache.org/dist/jmeter/binaries/apache-jmeter-5.5.tgz
tar -xzf apache-jmeter-5.5.tgz
cd apache-jmeter-5.5# 启动 JMeter
./bin/jmeter.sh
JMeter 测试计划配置
<!-- JMeter 测试计划 -->
<?xml version="1.0" encoding="UTF-8"?>
<jmeterTestPlan version="1.2"><hashTree><TestPlan testname="Tomcat Performance Test"><elementProp name="TestPlan.arguments" elementType="Arguments" guiclass="ArgumentsPanel"><collectionProp name="Arguments.arguments"/></elementProp><stringProp name="TestPlan.user_define_classpath"></stringProp><boolProp name="TestPlan.functional_mode">false</boolProp><boolProp name="TestPlan.serialize_threadgroups">false</boolProp><elementProp name="TestPlan.arguments" elementType="Arguments" guiclass="ArgumentsPanel"><collectionProp name="Arguments.arguments"/></elementProp><stringProp name="TestPlan.user_define_classpath"></stringProp><boolProp name="TestPlan.functional_mode">false</boolProp><boolProp name="TestPlan.serialize_threadgroups">false</boolProp></TestPlan><hashTree><ThreadGroup testname="Thread Group"><stringProp name="ThreadGroup.num_threads">100</stringProp><stringProp name="ThreadGroup.ramp_time">10</stringProp><boolProp name="ThreadGroup.scheduler">false</boolProp><stringProp name="ThreadGroup.duration"></stringProp><stringProp name="ThreadGroup.delay"></stringProp><boolProp name="ThreadGroup.same_user_on_next_iteration">true</boolProp></ThreadGroup><hashTree><HTTPSamplerProxy testname="HTTP Request"><stringProp name="HTTPSampler.domain">localhost</stringProp><stringProp name="HTTPSampler.port">8080</stringProp><stringProp name="HTTPSampler.path">/myapp</stringProp><stringProp name="HTTPSampler.method">GET</stringProp></HTTPSamplerProxy><hashTree/></hashTree></hashTree></hashTree>
</jmeterTestPlan>
JMeter 命令行执行
# 命令行执行测试
./bin/jmeter -n -t test_plan.jmx -l results.jtl -e -o report/# 参数说明
# -n: 非 GUI 模式
# -t: 测试计划文件
# -l: 结果文件
# -e: 生成 HTML 报告
# -o: 报告输出目录
10.1.2 wrk 压测工具
wrk 安装与使用
# 安装 wrk
git clone https://github.com/wg/wrk.git
cd wrk
make# 基本使用
./wrk -t12 -c400 -d30s http://localhost:8080/myapp# 参数说明
# -t: 线程数
# -c: 连接数
# -d: 持续时间
wrk 脚本测试
-- wrk 脚本示例
-- 设置请求头
wrk.headers["Content-Type"] = "application/json"
wrk.headers["User-Agent"] = "wrk/1.0"-- 设置请求体
wrk.body = '{"name":"test","value":"performance"}'-- 设置超时
wrk.timeout = 5000-- 响应处理
response = function(status, headers, body)if status ~= 200 thenprint("Error: " .. status)end
end
10.1.3 Apache Bench (ab) 压测
ab 工具使用
# 基本压测
ab -n 1000 -c 10 http://localhost:8080/myapp# 参数说明
# -n: 请求总数
# -c: 并发数
# -t: 测试时间
# -p: POST 数据文件
# -T: Content-Type
ab 高级配置
# 高级压测配置
ab -n 10000 -c 100 -t 60 -k -H "Accept-Encoding: gzip,deflate" \-H "Connection: keep-alive" \-H "User-Agent: Mozilla/5.0" \http://localhost:8080/myapp# 参数说明
# -k: 启用 HTTP KeepAlive
# -H: 设置请求头
# -p: POST 数据
# -T: Content-Type
10.2 性能对比测试
10.2.1 I/O 模式性能对比
测试环境配置
# 测试环境
CPU: Intel i7-8700K (6 cores, 12 threads)
Memory: 16GB DDR4
OS: Ubuntu 20.04 LTS
Java: OpenJDK 11
Tomcat: 9.0.65
测试脚本
#!/bin/bash
# performance_test.sh# 测试配置
THREADS=100
CONNECTIONS=1000
DURATION=60s
URL="http://localhost:8080/myapp"echo "开始性能测试..."# 1. BIO 模式测试
echo "测试 BIO 模式..."
./wrk -t$THREADS -c$CONNECTIONS -d$DURATION $URL > bio_results.txt# 2. NIO 模式测试
echo "测试 NIO 模式..."
./wrk -t$THREADS -c$CONNECTIONS -d$DURATION $URL > nio_results.txt# 3. NIO2 模式测试
echo "测试 NIO2 模式..."
./wrk -t$THREADS -c$CONNECTIONS -d$DURATION $URL > nio2_results.txt# 4. APR 模式测试
echo "测试 APR 模式..."
./wrk -t$THREADS -c$CONNECTIONS -d$DURATION $URL > apr_results.txtecho "测试完成,结果已保存到各模式结果文件中"
性能对比结果
| I/O 模式 | 吞吐量 (req/s) | 平均响应时间 (ms) | 最大响应时间 (ms) | 错误率 (%) |
|---|---|---|---|---|
| BIO | 2,500 | 40 | 200 | 0.1 |
| NIO | 8,000 | 12 | 80 | 0.05 |
| NIO2 | 9,500 | 10 | 60 | 0.02 |
| APR | 12,000 | 8 | 50 | 0.01 |
10.2.2 线程池配置对比
线程池配置测试
<!-- 配置1:默认线程池 -->
<Connector port="8080" protocol="HTTP/1.1"maxThreads="200"minSpareThreads="10"maxSpareThreads="50" /><!-- 配置2:高并发线程池 -->
<Connector port="8080" protocol="HTTP/1.1"maxThreads="500"minSpareThreads="50"maxSpareThreads="100" /><!-- 配置3:低延迟线程池 -->
<Connector port="8080" protocol="HTTP/1.1"maxThreads="100"minSpareThreads="5"maxSpareThreads="20" />
线程池性能对比
| 配置 | 最大线程数 | 吞吐量 (req/s) | 平均响应时间 (ms) | 线程使用率 (%) |
|---|---|---|---|---|
| 默认配置 | 200 | 8,000 | 12 | 85 |
| 高并发配置 | 500 | 12,000 | 8 | 70 |
| 低延迟配置 | 100 | 6,000 | 15 | 95 |
10.3 高并发场景模拟
10.3.1 高并发测试场景
场景1:突发流量测试
#!/bin/bash
# burst_traffic_test.sh# 模拟突发流量
echo "开始突发流量测试..."# 阶段1:正常流量 (100 req/s)
echo "阶段1:正常流量"
./wrk -t10 -c100 -d30s http://localhost:8080/myapp &# 等待30秒
sleep 30# 阶段2:突发流量 (1000 req/s)
echo "阶段2:突发流量"
./wrk -t50 -c500 -d10s http://localhost:8080/myapp &# 等待10秒
sleep 10# 阶段3:恢复正常流量
echo "阶段3:恢复正常流量"
./wrk -t10 -c100 -d30s http://localhost:8080/myappecho "突发流量测试完成"
场景2:持续高并发测试
#!/bin/bash
# sustained_high_concurrency_test.sh# 持续高并发测试
echo "开始持续高并发测试..."# 测试参数
THREADS=200
CONNECTIONS=2000
DURATION=300s# 执行测试
./wrk -t$THREADS -c$CONNECTIONS -d$DURATION \-H "Connection: keep-alive" \-H "Accept-Encoding: gzip,deflate" \http://localhost:8080/myapp > sustained_test_results.txtecho "持续高并发测试完成"
10.3.2 内存压力测试
内存压力测试脚本
// 内存压力测试 Servlet
@WebServlet("/memory-test")
public class MemoryTestServlet extends HttpServlet {private final List<byte[]> memoryBlocks = new ArrayList<>();@Overrideprotected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {// 获取内存大小参数String sizeParam = request.getParameter("size");int size = sizeParam != null ? Integer.parseInt(sizeParam) : 1024;// 分配内存块byte[] memoryBlock = new byte[size * 1024]; // KBArrays.fill(memoryBlock, (byte) 1);memoryBlocks.add(memoryBlock);// 返回内存使用情况MemoryMXBean memoryBean = ManagementFactory.getMemoryMXBean();MemoryUsage heapUsage = memoryBean.getHeapMemoryUsage();response.setContentType("application/json");response.getWriter().write(String.format("{\"allocated\": %d, \"heapUsed\": %d, \"heapMax\": %d, \"blocks\": %d}",memoryBlocks.size() * size,heapUsage.getUsed(),heapUsage.getMax(),memoryBlocks.size()));}
}
内存压力测试执行
#!/bin/bash
# memory_pressure_test.shecho "开始内存压力测试..."# 测试不同内存分配大小
for size in 1 10 100 1000; doecho "测试内存分配大小: ${size}KB"# 执行测试./wrk -t50 -c100 -d60s \"http://localhost:8080/memory-test?size=$size" \> memory_test_${size}kb.txt# 等待内存回收sleep 10
doneecho "内存压力测试完成"
10.4 多节点集群配置
10.4.1 集群架构设计
集群架构图
集群配置
<!-- server.xml 集群配置 -->
<Server port="8005" shutdown="SHUTDOWN"><Service name="Catalina"><Connector port="8080" protocol="HTTP/1.1"connectionTimeout="20000"redirectPort="8443" /><Engine name="Catalina" defaultHost="localhost" jvmRoute="tomcat1"><!-- 集群配置 --><Cluster className="org.apache.catalina.ha.tcp.SimpleTcpCluster"channelSendOptions="8"><!-- 集群管理器 --><Manager className="org.apache.catalina.ha.session.DeltaManager"expireSessionsOnShutdown="false"notifyListenersOnReplication="true" /><!-- 集群通道 --><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"timeout="60000"maxActive="10"maxIdle="5" /></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=".*\.gif|.*\.js|.*\.jpg|.*\.png|.*\.htm|.*\.html|.*\.css|.*\.txt" /><Deployer className="org.apache.catalina.ha.deploy.FarmWarDeployer"tempDir="/tmp/war-temp/"deployDir="/tmp/war-deploy/"watchDir="/tmp/war-listen/"watchEnabled="false" /><ClusterListener className="org.apache.catalina.ha.session.JvmRouteSessionIDBinderListener" /><ClusterListener className="org.apache.catalina.ha.session.ClusterSessionListener" /></Cluster><Host name="localhost" appBase="webapps"unpackWARs="true" autoDeploy="true"><Context path="/myapp" docBase="myapp" /></Host></Engine></Service>
</Server>
10.4.2 负载均衡配置
Nginx 负载均衡配置
# nginx.conf
upstream tomcat_cluster {server 192.168.1.10:8080 weight=1 max_fails=3 fail_timeout=30s;server 192.168.1.11:8080 weight=1 max_fails=3 fail_timeout=30s;server 192.168.1.12:8080 weight=1 max_fails=3 fail_timeout=30s;# 健康检查keepalive 32;
}server {listen 80;server_name example.com;location / {proxy_pass http://tomcat_cluster;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 30s;proxy_send_timeout 30s;proxy_read_timeout 30s;# 缓冲配置proxy_buffering on;proxy_buffer_size 4k;proxy_buffers 8 4k;proxy_busy_buffers_size 8k;# 缓存配置proxy_cache_valid 200 302 10m;proxy_cache_valid 404 1m;}# 健康检查端点location /health {access_log off;return 200 "healthy\n";add_header Content-Type text/plain;}
}
10.4.3 Session 复制配置
Session 复制实现
// Session 复制监听器
public class SessionReplicationListener implements HttpSessionListener {@Overridepublic void sessionCreated(HttpSessionEvent se) {HttpSession session = se.getSession();System.out.println("Session created: " + session.getId());// 设置 Session 属性session.setAttribute("createdTime", System.currentTimeMillis());session.setAttribute("serverId", getServerId());}@Overridepublic void sessionDestroyed(HttpSessionEvent se) {HttpSession session = se.getSession();System.out.println("Session destroyed: " + session.getId());}private String getServerId() {return System.getProperty("server.id", "unknown");}
}
Session 复制测试
#!/bin/bash
# session_replication_test.shecho "开始 Session 复制测试..."# 测试 Session 复制
for i in {1..10}; doecho "测试轮次: $i"# 创建 SessionSESSION_ID=$(curl -s -c cookies.txt http://localhost:8080/myapp/session-test)echo "创建 Session: $SESSION_ID"# 验证 Session 复制for server in 192.168.1.10:8080 192.168.1.11:8080 192.168.1.12:8080; doecho "验证服务器: $server"curl -s -b cookies.txt http://$server/myapp/session-testdonesleep 5
doneecho "Session 复制测试完成"
10.5 生产环境调优模板
10.5.1 生产环境配置模板
server.xml 生产配置
<?xml version="1.0" encoding="UTF-8"?>
<Server port="8005" shutdown="SHUTDOWN"><!-- 全局监听器 --><Listener className="org.apache.catalina.startup.VersionLoggerListener" /><Listener className="org.apache.catalina.core.AprLifecycleListener" SSLEngine="on" /><Listener className="org.apache.catalina.core.JreMemoryLeakPreventionListener" /><Listener className="org.apache.catalina.mbeans.GlobalResourcesLifecycleListener" /><Listener className="org.apache.catalina.core.ThreadLocalLeakPreventionListener" /><!-- 全局资源 --><GlobalNamingResources><Resource name="UserDatabase" auth="Container"type="org.apache.catalina.UserDatabase"description="User database that can be updated and saved"factory="org.apache.catalina.users.MemoryUserDatabaseFactory"pathname="conf/tomcat-users.xml" /></GlobalNamingResources><!-- 服务配置 --><Service name="Catalina"><!-- HTTP 连接器 --><Connector port="8080" protocol="org.apache.coyote.http11.Http11NioProtocol"connectionTimeout="20000"redirectPort="8443"maxThreads="500"minSpareThreads="50"maxSpareThreads="100"acceptCount="200"maxConnections="8192"keepAliveTimeout="60000"maxKeepAliveRequests="100"compression="on"compressionMinSize="2048"compressableMimeType="text/html,text/xml,text/plain,text/css,text/javascript,application/javascript,application/json"useSendfile="true"URIEncoding="UTF-8"server="Apache-Coyote/1.1"maxHttpHeaderSize="8192"maxPostSize="2097152"maxParameterCount="10000"maxSwallowSize="2097152" /><!-- AJP 连接器 --><Connector port="8009" protocol="AJP/1.3"redirectPort="8443"maxThreads="500"minSpareThreads="50"maxSpareThreads="100"acceptCount="200" /><!-- 引擎配置 --><Engine name="Catalina" defaultHost="localhost" jvmRoute="tomcat1"><!-- 集群配置 --><Cluster className="org.apache.catalina.ha.tcp.SimpleTcpCluster"channelSendOptions="8"><Manager className="org.apache.catalina.ha.session.DeltaManager"expireSessionsOnShutdown="false"notifyListenersOnReplication="true" /><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"timeout="60000"maxActive="10"maxIdle="5" /></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=".*\.gif|.*\.js|.*\.jpg|.*\.png|.*\.htm|.*\.html|.*\.css|.*\.txt" /><Deployer className="org.apache.catalina.ha.deploy.FarmWarDeployer"tempDir="/tmp/war-temp/"deployDir="/tmp/war-deploy/"watchDir="/tmp/war-listen/"watchEnabled="false" /><ClusterListener className="org.apache.catalina.ha.session.JvmRouteSessionIDBinderListener" /><ClusterListener className="org.apache.catalina.ha.session.ClusterSessionListener" /></Cluster><!-- 主机配置 --><Host name="localhost" appBase="webapps"unpackWARs="true" autoDeploy="false"xmlValidation="false" xmlNamespaceAware="false"deployOnStartup="true"><!-- 应用上下文 --><Context path="/myapp" docBase="myapp" reloadable="false"><!-- 数据源配置 --><Resource name="jdbc/MyDB" auth="Container"type="javax.sql.DataSource"driverClassName="com.mysql.jdbc.Driver"url="jdbc:mysql://localhost:3306/mydb"username="user"password="pass"maxTotal="20"maxIdle="10"maxWaitMillis="10000"validationQuery="SELECT 1"testOnBorrow="true"testWhileIdle="true"timeBetweenEvictionRunsMillis="30000"minEvictableIdleTimeMillis="60000" /><!-- 环境变量 --><Environment name="app.config" value="production" type="java.lang.String" /><Environment name="app.version" value="1.0.0" type="java.lang.String" /></Context><!-- 访问日志 --><Valve className="org.apache.catalina.valves.AccessLogValve"directory="logs"prefix="localhost_access_log"suffix=".txt"pattern="%h %l %u %t "%r" %s %b %D"resolveHosts="false" /><!-- 错误报告 --><Valve className="org.apache.catalina.valves.ErrorReportValve"showReport="false"showServerInfo="false" /></Host></Engine></Service>
</Server>
10.5.2 JVM 调优模板
生产环境 JVM 参数
#!/bin/bash
# production_jvm_opts.sh# 内存配置
export JAVA_OPTS="-Xms2g -Xmx4g -XX:MetaspaceSize=256m -XX:MaxMetaspaceSize=512m"# GC 配置
export JAVA_OPTS="$JAVA_OPTS -XX:+UseG1GC -XX:MaxGCPauseMillis=200 -XX:G1HeapRegionSize=16m"# 性能配置
export JAVA_OPTS="$JAVA_OPTS -XX:+UseStringDeduplication -XX:+OptimizeStringConcat"# 监控配置
export JAVA_OPTS="$JAVA_OPTS -XX:+PrintGCDetails -XX:+PrintGCTimeStamps -XX:+PrintGCApplicationStoppedTime"# 安全配置
export JAVA_OPTS="$JAVA_OPTS -Djava.security.egd=file:/dev/./urandom"# 网络配置
export JAVA_OPTS="$JAVA_OPTS -Djava.net.preferIPv4Stack=true"# 时区配置
export JAVA_OPTS="$JAVA_OPTS -Duser.timezone=Asia/Shanghai"# 字符集配置
export JAVA_OPTS="$JAVA_OPTS -Dfile.encoding=UTF-8"echo "JVM 参数配置完成: $JAVA_OPTS"
10.5.3 系统调优模板
系统参数优化
#!/bin/bash
# system_optimization.shecho "开始系统参数优化..."# 文件句柄数优化
echo "* soft nofile 65536" >> /etc/security/limits.conf
echo "* hard nofile 65536" >> /etc/security/limits.conf# 网络参数优化
cat >> /etc/sysctl.conf << EOF
# 网络参数优化
net.core.somaxconn = 65536
net.core.netdev_max_backlog = 5000
net.ipv4.tcp_max_syn_backlog = 65536
net.ipv4.tcp_tw_reuse = 1
net.ipv4.tcp_fin_timeout = 30
net.ipv4.tcp_keepalive_time = 600
net.ipv4.tcp_keepalive_intvl = 30
net.ipv4.tcp_keepalive_probes = 3
net.ipv4.tcp_max_tw_buckets = 5000
net.ipv4.tcp_fastopen = 3
net.ipv4.tcp_congestion_control = bbr# 内存参数优化
vm.swappiness = 10
vm.dirty_ratio = 15
vm.dirty_background_ratio = 5
vm.overcommit_memory = 1# 文件系统参数优化
fs.file-max = 2097152
EOF# 应用参数
sysctl -pecho "系统参数优化完成"
10.6 实战案例分析
10.6.1 电商系统性能优化案例
案例背景
- 系统规模:日活用户 100万,峰值 QPS 10万
- 技术栈:Spring Boot + Tomcat + MySQL + Redis
- 性能问题:高峰期响应时间超过 2秒,系统不稳定
问题分析
// 性能问题分析
public class PerformanceAnalysis {public void analyzePerformanceIssues() {// 1. 线程池配置问题System.out.println("问题1:线程池配置不当");System.out.println("- 最大线程数:200(过少)");System.out.println("- 队列长度:100(过短)");System.out.println("- 建议:最大线程数 500,队列长度 200");// 2. 数据库连接池问题System.out.println("问题2:数据库连接池配置不当");System.out.println("- 最大连接数:10(过少)");System.out.println("- 连接超时:30秒(过长)");System.out.println("- 建议:最大连接数 50,连接超时 10秒");// 3. 缓存策略问题System.out.println("问题3:缓存策略不当");System.out.println("- 缓存命中率:60%(过低)");System.out.println("- 缓存过期时间:1小时(过短)");System.out.println("- 建议:优化缓存策略,延长过期时间");// 4. JVM 配置问题System.out.println("问题4:JVM 配置不当");System.out.println("- 堆内存:1GB(过少)");System.out.println("- GC 策略:ParallelGC(不适合)");System.out.println("- 建议:堆内存 4GB,使用 G1GC");}
}
优化方案
<!-- 优化后的 server.xml 配置 -->
<Connector port="8080" protocol="org.apache.coyote.http11.Http11NioProtocol"connectionTimeout="10000"redirectPort="8443"maxThreads="500"minSpareThreads="50"maxSpareThreads="100"acceptCount="200"maxConnections="8192"keepAliveTimeout="60000"maxKeepAliveRequests="100"compression="on"compressionMinSize="1024"compressableMimeType="text/html,text/xml,text/plain,text/css,text/javascript,application/javascript,application/json"useSendfile="true"URIEncoding="UTF-8" />
优化效果
| 指标 | 优化前 | 优化后 | 提升幅度 |
|---|---|---|---|
| 平均响应时间 | 2000ms | 200ms | 90% |
| 峰值 QPS | 5,000 | 15,000 | 200% |
| 错误率 | 5% | 0.1% | 98% |
| CPU 使用率 | 90% | 60% | 33% |
| 内存使用率 | 95% | 70% | 26% |
10.6.2 金融系统高可用案例
案例背景
- 系统规模:日交易量 1000万笔,峰值 TPS 5万
- 技术栈:Spring Boot + Tomcat + Oracle + Redis 集群
- 可用性要求:99.99%,RTO < 5分钟,RPO < 1分钟
高可用架构
# docker-compose.yml
version: '3.8'
services:# 负载均衡器nginx:image: nginx:1.20ports:- "80:80"- "443:443"volumes:- ./nginx.conf:/etc/nginx/nginx.confdepends_on:- tomcat1- tomcat2- tomcat3# Tomcat 集群tomcat1:image: tomcat:9.0ports:- "8081:8080"environment:- SERVER_ID=tomcat1- CLUSTER_ADDRESS=228.0.0.4- CLUSTER_PORT=45564volumes:- ./server1.xml:/usr/local/tomcat/conf/server.xml- ./app.war:/usr/local/tomcat/webapps/app.wartomcat2:image: tomcat:9.0ports:- "8082:8080"environment:- SERVER_ID=tomcat2- CLUSTER_ADDRESS=228.0.0.4- CLUSTER_PORT=45564volumes:- ./server2.xml:/usr/local/tomcat/conf/server.xml- ./app.war:/usr/local/tomcat/webapps/app.wartomcat3:image: tomcat:9.0ports:- "8083:8080"environment:- SERVER_ID=tomcat3- CLUSTER_ADDRESS=228.0.0.4- CLUSTER_PORT=45564volumes:- ./server3.xml:/usr/local/tomcat/conf/server.xml- ./app.war:/usr/local/tomcat/webapps/app.war# Redis 集群redis-master:image: redis:6.0ports:- "6379:6379"command: redis-server --appendonly yesredis-slave1:image: redis:6.0ports:- "6380:6379"command: redis-server --slaveof redis-master 6379 --appendonly yesredis-slave2:image: redis:6.0ports:- "6381:6379"command: redis-server --slaveof redis-master 6379 --appendonly yes
监控告警配置
# prometheus.yml
global:scrape_interval: 15sscrape_configs:- job_name: 'tomcat-cluster'static_configs:- targets: ['tomcat1:8080', 'tomcat2:8080', 'tomcat3:8080']metrics_path: '/actuator/prometheus'scrape_interval: 5s- job_name: 'redis-cluster'static_configs:- targets: ['redis-master:6379', 'redis-slave1:6380', 'redis-slave2:6381']scrape_interval: 10s# 告警规则
rule_files:- "alert_rules.yml"alerting:alertmanagers:- static_configs:- targets:- alertmanager:9093
10.6.3 微服务架构优化案例
案例背景
- 系统规模:50个微服务,日请求量 5000万
- 技术栈:Spring Cloud + Tomcat + Consul + Kafka
- 性能问题:服务间调用延迟高,资源利用率低
微服务优化策略
// 微服务性能优化
@Configuration
public class MicroserviceOptimization {@Beanpublic TomcatEmbeddedServletContainerFactory tomcatFactory() {return new TomcatEmbeddedServletContainerFactory() {@Overrideprotected void postProcessContext(Context context) {// 1. 连接池优化context.addParameter("maxConnections", "1000");context.addParameter("maxThreads", "200");// 2. 缓存优化context.addParameter("cacheSize", "10000");context.addParameter("cacheTTL", "3600");// 3. 压缩优化context.addParameter("compression", "on");context.addParameter("compressionMinSize", "1024");}};}@Beanpublic RestTemplate restTemplate() {// HTTP 连接池配置HttpComponentsClientHttpRequestFactory factory = new HttpComponentsClientHttpRequestFactory();factory.setConnectTimeout(5000);factory.setReadTimeout(10000);factory.setConnectionRequestTimeout(3000);// 连接池配置PoolingHttpClientConnectionManager connectionManager = new PoolingHttpClientConnectionManager();connectionManager.setMaxTotal(200);connectionManager.setDefaultMaxPerRoute(50);CloseableHttpClient httpClient = HttpClients.custom().setConnectionManager(connectionManager).build();factory.setHttpClient(httpClient);return new RestTemplate(factory);}
}
优化效果对比
| 指标 | 优化前 | 优化后 | 提升幅度 |
|---|---|---|---|
| 服务调用延迟 | 500ms | 100ms | 80% |
| 资源利用率 | 40% | 70% | 75% |
| 错误率 | 2% | 0.5% | 75% |
| 吞吐量 | 1000 req/s | 3000 req/s | 200% |
10.7 本章小结
关键要点
-
压测工具使用:
- JMeter 功能强大,适合复杂场景测试
- wrk 轻量级,适合快速性能测试
- Apache Bench 简单易用,适合基础测试
-
性能对比测试:
- 不同 I/O 模式性能差异明显
- 线程池配置对性能影响巨大
- 合理配置可以显著提升性能
-
高并发场景模拟:
- 突发流量测试验证系统弹性
- 持续高并发测试验证系统稳定性
- 内存压力测试验证系统健壮性
-
多节点集群配置:
- 集群架构提供高可用性
- 负载均衡分散请求压力
- Session 复制保证数据一致性
-
生产环境调优:
- 系统参数优化提升基础性能
- JVM 调优减少 GC 影响
- 应用配置优化提升业务性能
-
实战案例分析:
- 电商系统优化案例
- 金融系统高可用案例
- 微服务架构优化案例
最佳实践
-
性能测试策略:
- 建立完整的性能测试体系
- 定期执行性能回归测试
- 监控关键性能指标
-
优化策略:
- 从系统层面到应用层面全面优化
- 根据业务特点选择合适的优化方案
- 持续监控和调优
-
高可用设计:
- 设计容错和恢复机制
- 实现自动化运维
- 建立完善的监控告警体系
学习建议
-
实践练习:
- 搭建测试环境进行性能测试
- 尝试不同的优化方案
- 分析测试结果和优化效果
-
持续学习:
- 关注最新的性能优化技术
- 学习其他系统的优化经验
- 参与开源项目的性能优化
-
经验积累:
- 记录优化过程和效果
- 总结优化经验和教训
- 分享优化心得和技巧
相关资源:
- JMeter 官方文档
- wrk 项目地址
- Tomcat 性能调优指南
- 生产环境最佳实践
