第十章-Tomcat性能测试与实战案例

🚀 第十章:Tomcat 性能测试与实战案例

目录

  • [10.1 压测工具使用](#10.1 压测工具使用)
  • [10.2 性能对比测试](#10.2 性能对比测试)
  • [10.3 高并发场景模拟](#10.3 高并发场景模拟)
  • [10.4 多节点集群配置](#10.4 多节点集群配置)
  • [10.5 生产环境调优模板](#10.5 生产环境调优模板)
  • [10.6 实战案例分析](#10.6 实战案例分析)
  • [10.7 本章小结](#10.7 本章小结)

10.1 压测工具使用

10.1.1 JMeter 压测工具

JMeter 安装与配置
bash 复制代码
# 下载 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 测试计划配置
xml 复制代码
<!-- 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 命令行执行
bash 复制代码
# 命令行执行测试
./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 安装与使用
bash 复制代码
# 安装 wrk
git clone https://github.com/wg/wrk.git
cd wrk
make

# 基本使用
./wrk -t12 -c400 -d30s http://localhost:8080/myapp

# 参数说明
# -t: 线程数
# -c: 连接数
# -d: 持续时间
wrk 脚本测试
lua 复制代码
-- 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 then
        print("Error: " .. status)
    end
end

10.1.3 Apache Bench (ab) 压测

ab 工具使用
bash 复制代码
# 基本压测
ab -n 1000 -c 10 http://localhost:8080/myapp

# 参数说明
# -n: 请求总数
# -c: 并发数
# -t: 测试时间
# -p: POST 数据文件
# -T: Content-Type
ab 高级配置
bash 复制代码
# 高级压测配置
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 模式性能对比

测试环境配置
bash 复制代码
# 测试环境
CPU: Intel i7-8700K (6 cores, 12 threads)
Memory: 16GB DDR4
OS: Ubuntu 20.04 LTS
Java: OpenJDK 11
Tomcat: 9.0.65
测试脚本
bash 复制代码
#!/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.txt

echo "测试完成,结果已保存到各模式结果文件中"
性能对比结果
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 线程池配置对比

线程池配置测试
xml 复制代码
<!-- 配置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:突发流量测试
bash 复制代码
#!/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/myapp

echo "突发流量测试完成"
场景2:持续高并发测试
bash 复制代码
#!/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.txt

echo "持续高并发测试完成"

10.3.2 内存压力测试

内存压力测试脚本
java 复制代码
// 内存压力测试 Servlet
@WebServlet("/memory-test")
public class MemoryTestServlet extends HttpServlet {
    
    private final List<byte[]> memoryBlocks = new ArrayList<>();
    
    @Override
    protected 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]; // KB
        Arrays.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()
        ));
    }
}
内存压力测试执行
bash 复制代码
#!/bin/bash
# memory_pressure_test.sh

echo "开始内存压力测试..."

# 测试不同内存分配大小
for size in 1 10 100 1000; do
    echo "测试内存分配大小: ${size}KB"
    
    # 执行测试
    ./wrk -t50 -c100 -d60s \
          "http://localhost:8080/memory-test?size=$size" \
          > memory_test_${size}kb.txt
    
    # 等待内存回收
    sleep 10
done

echo "内存压力测试完成"

10.4 多节点集群配置

10.4.1 集群架构设计

集群架构图

数据层 Tomcat 集群 负载均衡层 Redis 集群 MySQL 主从 Tomcat 1 Tomcat 2 Tomcat 3 Nginx

集群配置
xml 复制代码
<!-- 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 复制代码
# 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 复制实现
java 复制代码
// Session 复制监听器
public class SessionReplicationListener implements HttpSessionListener {
    
    @Override
    public 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());
    }
    
    @Override
    public 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 复制测试
bash 复制代码
#!/bin/bash
# session_replication_test.sh

echo "开始 Session 复制测试..."

# 测试 Session 复制
for i in {1..10}; do
    echo "测试轮次: $i"
    
    # 创建 Session
    SESSION_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; do
        echo "验证服务器: $server"
        curl -s -b cookies.txt http://$server/myapp/session-test
    done
    
    sleep 5
done

echo "Session 复制测试完成"

10.5 生产环境调优模板

10.5.1 生产环境配置模板

server.xml 生产配置
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 &quot;%r&quot; %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 参数
bash 复制代码
#!/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 系统调优模板

系统参数优化
bash 复制代码
#!/bin/bash
# system_optimization.sh

echo "开始系统参数优化..."

# 文件句柄数优化
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 -p

echo "系统参数优化完成"

10.6 实战案例分析

10.6.1 电商系统性能优化案例

案例背景
  • 系统规模:日活用户 100万,峰值 QPS 10万
  • 技术栈:Spring Boot + Tomcat + MySQL + Redis
  • 性能问题:高峰期响应时间超过 2秒,系统不稳定
问题分析
java 复制代码
// 性能问题分析
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");
    }
}
优化方案
xml 复制代码
<!-- 优化后的 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分钟
高可用架构
yaml 复制代码
# docker-compose.yml
version: '3.8'
services:
  # 负载均衡器
  nginx:
    image: nginx:1.20
    ports:
      - "80:80"
      - "443:443"
    volumes:
      - ./nginx.conf:/etc/nginx/nginx.conf
    depends_on:
      - tomcat1
      - tomcat2
      - tomcat3
  
  # Tomcat 集群
  tomcat1:
    image: tomcat:9.0
    ports:
      - "8081:8080"
    environment:
      - SERVER_ID=tomcat1
      - CLUSTER_ADDRESS=228.0.0.4
      - CLUSTER_PORT=45564
    volumes:
      - ./server1.xml:/usr/local/tomcat/conf/server.xml
      - ./app.war:/usr/local/tomcat/webapps/app.war
  
  tomcat2:
    image: tomcat:9.0
    ports:
      - "8082:8080"
    environment:
      - SERVER_ID=tomcat2
      - CLUSTER_ADDRESS=228.0.0.4
      - CLUSTER_PORT=45564
    volumes:
      - ./server2.xml:/usr/local/tomcat/conf/server.xml
      - ./app.war:/usr/local/tomcat/webapps/app.war
  
  tomcat3:
    image: tomcat:9.0
    ports:
      - "8083:8080"
    environment:
      - SERVER_ID=tomcat3
      - CLUSTER_ADDRESS=228.0.0.4
      - CLUSTER_PORT=45564
    volumes:
      - ./server3.xml:/usr/local/tomcat/conf/server.xml
      - ./app.war:/usr/local/tomcat/webapps/app.war
  
  # Redis 集群
  redis-master:
    image: redis:6.0
    ports:
      - "6379:6379"
    command: redis-server --appendonly yes
  
  redis-slave1:
    image: redis:6.0
    ports:
      - "6380:6379"
    command: redis-server --slaveof redis-master 6379 --appendonly yes
  
  redis-slave2:
    image: redis:6.0
    ports:
      - "6381:6379"
    command: redis-server --slaveof redis-master 6379 --appendonly yes
监控告警配置
yaml 复制代码
# prometheus.yml
global:
  scrape_interval: 15s

scrape_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
  • 性能问题:服务间调用延迟高,资源利用率低
微服务优化策略
java 复制代码
// 微服务性能优化
@Configuration
public class MicroserviceOptimization {
    
    @Bean
    public TomcatEmbeddedServletContainerFactory tomcatFactory() {
        return new TomcatEmbeddedServletContainerFactory() {
            @Override
            protected 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");
            }
        };
    }
    
    @Bean
    public 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 本章小结

关键要点

  1. 压测工具使用

    • JMeter 功能强大,适合复杂场景测试
    • wrk 轻量级,适合快速性能测试
    • Apache Bench 简单易用,适合基础测试
  2. 性能对比测试

    • 不同 I/O 模式性能差异明显
    • 线程池配置对性能影响巨大
    • 合理配置可以显著提升性能
  3. 高并发场景模拟

    • 突发流量测试验证系统弹性
    • 持续高并发测试验证系统稳定性
    • 内存压力测试验证系统健壮性
  4. 多节点集群配置

    • 集群架构提供高可用性
    • 负载均衡分散请求压力
    • Session 复制保证数据一致性
  5. 生产环境调优

    • 系统参数优化提升基础性能
    • JVM 调优减少 GC 影响
    • 应用配置优化提升业务性能
  6. 实战案例分析

    • 电商系统优化案例
    • 金融系统高可用案例
    • 微服务架构优化案例

最佳实践

  1. 性能测试策略

    • 建立完整的性能测试体系
    • 定期执行性能回归测试
    • 监控关键性能指标
  2. 优化策略

    • 从系统层面到应用层面全面优化
    • 根据业务特点选择合适的优化方案
    • 持续监控和调优
  3. 高可用设计

    • 设计容错和恢复机制
    • 实现自动化运维
    • 建立完善的监控告警体系

学习建议

  1. 实践练习

    • 搭建测试环境进行性能测试
    • 尝试不同的优化方案
    • 分析测试结果和优化效果
  2. 持续学习

    • 关注最新的性能优化技术
    • 学习其他系统的优化经验
    • 参与开源项目的性能优化
  3. 经验积累

    • 记录优化过程和效果
    • 总结优化经验和教训
    • 分享优化心得和技巧

相关资源

相关推荐
lpfasd1233 小时前
第二章-Tomcat核心架构拆解
1024程序员节
IT古董3 小时前
【第五章:计算机视觉-项目实战之推荐/广告系统】2.粗排算法-(4)粗排算法模型多目标算法(Multi Task Learning)及目标融合
人工智能·算法·1024程序员节
RainSky_3 小时前
LNMP 一键安装包部署 Django 项目
后端·django·1024程序员节
newxtc4 小时前
【江苏政务服务网-注册_登录安全分析报告】
人工智能·安全·yolo·政务·1024程序员节·安全爆破
上去我就QWER4 小时前
Python下常用开源库
python·1024程序员节
Bryce李小白4 小时前
Flutter中Key的作用以及应用场景
1024程序员节
黄思搏4 小时前
红黑树 - Red-Black Tree 原理与 C# 实现
数据结构·1024程序员节
云边有个稻草人4 小时前
KingbaseES数据库:异构多活构建极致容灾
1024程序员节