Tomcat 和 Nginx 作为 Java Web 应用和反向代理的黄金组合,在生产环境中承载着海量的用户请求。然而,大多数开发者往往采用默认配置直接上线,导致在高并发场景下出现响应缓慢、连接超时、CPU 飙升等问题。通过科学的参数调优,可以在不增加硬件成本的情况下,将系统吞吐量显著提升,从而改善用户体验。本文将深入探讨两者的核心配置,并提供可直接用于生产的示例与压测验证方法。本文的优化思路与讨论,也欢迎你在 云栈社区 与我们交流。
一、概述
1.1 适用场景
- 场景一:电商大促、秒杀活动等高并发峰值场景,需要承载数十万QPS。
- 场景二:微服务架构下的 API 网关,需要高效转发大量后端请求。
- 场景三:静态资源密集型站点,需要优化缓存和传输效率。
- 场景四:长连接场景(WebSocket、SSE),需要支持海量并发连接。
1.2 环境要求
| 组件 |
版本要求 |
说明 |
| 操作系统 |
CentOS 7+/Ubuntu 20.04+ |
Linux 内核 3.10+ |
| Tomcat |
9.0+/10.0+ |
推荐最新稳定版 |
| Nginx |
1.20+ |
建议使用 Tengine 或 OpenResty |
| JDK |
OpenJDK 11/17 |
LTS 版本 |
| 硬件配置 |
4核8GB+ |
建议 SSD,万兆网卡 |
二、详细步骤
2.1 Tomcat 核心参数调优
2.1.1 Connector 连接器优化
Tomcat 的 Connector 决定了如何接收和处理请求,是性能调优的第一关。
<!-- conf/server.xml -->
<Connector port="8080"
protocol="org.apache.coyote.http11.Http11NioProtocol"
maxThreads="800"
minSpareThreads="50"
maxConnections="10000"
acceptCount="1000"
connectionTimeout="20000"
keepAliveTimeout="60000"
maxKeepAliveRequests="100"
compression="on"
compressionMinSize="2048"
compressibleMimeType="text/html,text/xml,text/plain,text/css,text/javascript,application/javascript,application/json"
URIEncoding="UTF-8"
enableLookups="false"
disableUploadTimeout="true"
maxHttpHeaderSize="8192"
redirectPort="8443" />
参数说明:
protocol:协议类型
Http11NioProtocol:NIO 模式(推荐),适合高并发。
Http11Nio2Protocol:NIO2 模式,适合长连接场景。
Http11AprProtocol:APR 模式,性能最佳但需要安装 native 库。
maxThreads:最大工作线程数
- 默认值:200。
- 推荐值:CPU核心数 × 100~200(4核配置400~800)。
- 计算公式:
maxThreads = (QPS × 响应时间) / 1000。
- 注意:过大会增加线程切换开销,需结合实际压测。
minSpareThreads:最小空闲线程数
- 推荐值:maxThreads 的 10%~20%。
- 作用:预热线程池,减少冷启动时的延迟。
maxConnections:最大连接数
- 默认值:10000(NIO模式)。
- 推荐值:maxThreads 的 10~20 倍。
- 原理:连接数 > 线程数时,多余连接等待线程释放。
acceptCount:等待队列长度
- 默认值:100。
- 推荐值:1000~2000。
- 注意:达到 maxConnections 后,新连接进入此队列等待。
connectionTimeout:连接超时时间(毫秒)
- 默认值:20000(20秒)。
- 推荐值:20000~60000。
- 说明:客户端建立连接后,必须在此时间内发送数据。
keepAliveTimeout:Keep-Alive 超时时间(毫秒)
- 默认值:connectionTimeout。
- 推荐值:60000~120000。
- 优化点:启用 Keep-Alive 可复用连接,减少握手开销。
compression:是否开启 gzip 压缩
- 推荐值:on。
- 效果:可将文本内容压缩至原大小的 20%~30%。
- 注意:仅压缩指定 MIME 类型,图片视频等已压缩内容无需再压缩。
2.1.2 Executor 线程池配置
独立配置线程池,提供更精细的控制:
<!-- conf/server.xml -->
<Executor name="tomcatThreadPool"
namePrefix="catalina-exec-"
maxThreads="800"
minSpareThreads="50"
maxIdleTime="60000"
prestartminSpareThreads="true"
maxQueueSize="1000" />
<Connector port="8080"
protocol="org.apache.coyote.http11.Http11NioProtocol"
executor="tomcatThreadPool"
... />
参数说明:
maxQueueSize:任务队列长度,超出则拒绝请求。
prestartminSpareThreads:启动时预创建最小线程数。
maxIdleTime:线程空闲超时时间,超时则回收。
2.1.3 JVM 参数优化
JVM 的配置直接关系到应用的内存管理与垃圾回收效率,是不容忽视的优化环节。
# catalina.sh 或 setenv.sh
JAVA_OPTS="$JAVA_OPTS -Xms4g -Xmx4g"
JAVA_OPTS="$JAVA_OPTS -XX:MetaspaceSize=256m -XX:MaxMetaspaceSize=512m"
JAVA_OPTS="$JAVA_OPTS -XX:+UseG1GC -XX:MaxGCPauseMillis=200"
JAVA_OPTS="$JAVA_OPTS -XX:+ParallelRefProcEnabled"
JAVA_OPTS="$JAVA_OPTS -XX:+HeapDumpOnOutOfMemoryError"
JAVA_OPTS="$JAVA_OPTS -XX:HeapDumpPath=/var/log/tomcat/heap_dump.hprof"
JAVA_OPTS="$JAVA_OPTS -Xloggc:/var/log/tomcat/gc.log"
JAVA_OPTS="$JAVA_OPTS -XX:+PrintGCDetails -XX:+PrintGCDateStamps"
JAVA_OPTS="$JAVA_OPTS -Djava.security.egd=file:/dev/./urandom"
JAVA_OPTS="$JAVA_OPTS -Duser.timezone=Asia/Shanghai"
参数说明:
-Xms/-Xmx:堆内存大小
- 推荐值:物理内存的 50%~70%。
- 4核8GB:设置 4g。
- 8核16GB:设置 10g~12g。
- 建议:设置相同值,避免动态扩容。
-XX:+UseG1GC:使用 G1 垃圾回收器(JDK 9+ 默认)
- 优点:低延迟,适合大堆内存场景。
- 替代方案:ZGC(JDK 15+),适合超大堆(>100GB)。
-Djava.security.egd=file:/dev/./urandom:使用非阻塞随机数生成器
- 问题:Linux 默认
/dev/random 在熵池不足时会阻塞。
- 效果:避免 Tomcat 启动时卡在 SecureRandom 初始化。
2.2 Nginx 核心参数调优
作为反向代理网关,Nginx的优化关乎整个请求链路的效率。其配置的很多概念,在理解 后端与架构设计 时是相通的。
2.2.1 全局配置优化
# nginx.conf
user nginx;
worker_processes auto; # 自动检测CPU核心数
worker_cpu_affinity auto; # CPU亲和性绑定
worker_rlimit_nofile 65535; # 单个worker进程最大文件描述符
error_log /var/log/nginx/error.log warn;
pid /var/run/nginx.pid;
events {
use epoll; # Linux下使用高性能epoll模型
worker_connections 10240; # 单个worker进程最大连接数
multi_accept on; # 一次接受多个新连接
accept_mutex off; # 关闭accept互斥锁(多核推荐)
}
http {
include /etc/nginx/mime.types;
default_type application/octet-stream;
# 日志格式
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for" '
'rt=$request_time uct="$upstream_connect_time" '
'uht="$upstream_header_time" urt="$upstream_response_time"';
access_log /var/log/nginx/access.log main buffer=64k flush=5s;
# 性能优化
sendfile on; # 零拷贝传输文件
tcp_nopush on; # sendfile开启时生效,减少网络报文段数量
tcp_nodelay on; # keepalive开启时生效,禁用Nagle算法
keepalive_timeout 65; # 长连接超时时间
keepalive_requests 1000; # 单个连接最大请求数
types_hash_max_size 2048;
server_tokens off; # 隐藏Nginx版本号
# 文件缓存
open_file_cache max=10000 inactive=60s;
open_file_cache_valid 30s;
open_file_cache_min_uses 2;
open_file_cache_errors on;
# Gzip压缩
gzip on;
gzip_vary on;
gzip_proxied any;
gzip_comp_level 6;
gzip_types text/plain text/css text/xml text/javascript
application/json application/javascript application/xml+rss
application/rss+xml font/truetype font/opentype
application/vnd.ms-fontobject image/svg+xml;
gzip_disable "msie6";
gzip_min_length 1024; # 小于1KB不压缩
# 缓冲区设置
client_body_buffer_size 128k;
client_max_body_size 100m;
client_header_buffer_size 4k;
large_client_header_buffers 4 32k;
output_buffers 4 32k;
postpone_output 1460;
# 超时设置
client_header_timeout 60s;
client_body_timeout 60s;
send_timeout 60s;
# 连接池
upstream backend {
server 127.0.0.1:8080 weight=1 max_fails=3 fail_timeout=30s;
keepalive 256; # 保持256个空闲连接到后端
keepalive_requests 1000;
keepalive_timeout 60s;
}
include /etc/nginx/conf.d/*.conf;
}
参数说明:
worker_processes auto:工作进程数
- 推荐值:auto(自动检测CPU核心数)。
- 手动设置:等于CPU核心数,避免进程切换。
worker_connections:单个进程最大连接数
- 默认值:1024。
- 推荐值:10240~65535。
- 理论最大并发:
worker_processes × worker_connections / 2。
- 注意:需同时调整系统 ulimit。
use epoll:I/O 多路复用模型
- Linux:epoll(自动检测,无需手动指定)。
- FreeBSD:kqueue。
- Windows:不支持,使用默认 select。
sendfile on:零拷贝技术
- 原理:文件直接从磁盘发送到网卡,跳过用户空间。
- 效果:静态文件传输性能提升 2~3 倍。
keepalive:后端连接池
- 作用:复用到 Tomcat 的连接,减少 TCP 握手。
- 推荐值:256~512。
- 注意:需配合
proxy_http_version 1.1 和 proxy_set_header Connection ""。
2.2.2 反向代理配置
# conf.d/backend.conf
server {
listen 80;
server_name example.com;
# 访问日志(高并发可关闭)
access_log /var/log/nginx/backend_access.log main buffer=64k;
location / {
proxy_pass http://backend;
# 代理头设置
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;
# 启用HTTP/1.1和长连接
proxy_http_version 1.1;
proxy_set_header Connection "";
# 超时设置
proxy_connect_timeout 10s;
proxy_send_timeout 60s;
proxy_read_timeout 60s;
# 缓冲设置
proxy_buffering on;
proxy_buffer_size 8k;
proxy_buffers 32 8k;
proxy_busy_buffers_size 64k;
# 错误处理
proxy_next_upstream error timeout invalid_header http_500 http_502 http_503;
proxy_next_upstream_tries 2;
proxy_next_upstream_timeout 5s;
}
# 静态资源缓存
location ~* \.(jpg|jpeg|png|gif|ico|css|js|woff|woff2)$ {
expires 30d;
add_header Cache-Control "public, immutable";
access_log off;
# 如果后端有静态文件
proxy_pass http://backend;
proxy_cache static_cache;
proxy_cache_valid 200 30d;
proxy_cache_use_stale error timeout updating http_500 http_502 http_503 http_504;
}
# API接口限流
location /api/ {
limit_req zone=api_limit burst=20 nodelay;
limit_conn addr 10;
proxy_pass http://backend;
include proxy_params;
}
}
# 缓存配置
proxy_cache_path /var/cache/nginx/static
levels=1:2
keys_zone=static_cache:100m
max_size=10g
inactive=7d
use_temp_path=off;
# 限流配置
limit_req_zone $binary_remote_addr zone=api_limit:10m rate=100r/s;
limit_conn_zone $binary_remote_addr zone=addr:10m;
2.2.3 系统内核优化
Nginx性能的上限往往受限于操作系统内核参数,以下优化对于支撑高并发至关重要。
# /etc/sysctl.conf
# 文件描述符
fs.file-max = 1000000
# 网络优化
net.core.somaxconn = 65535
net.core.netdev_max_backlog = 65535
net.ipv4.tcp_max_syn_backlog = 65535
net.ipv4.tcp_fin_timeout = 30
net.ipv4.tcp_tw_reuse = 1
net.ipv4.tcp_keepalive_time = 600
net.ipv4.tcp_keepalive_probes = 3
net.ipv4.tcp_keepalive_intvl = 15
# TCP缓冲区
net.ipv4.tcp_rmem = 4096 87380 16777216
net.ipv4.tcp_wmem = 4096 65536 16777216
net.core.rmem_max = 16777216
net.core.wmem_max = 16777216
# 应用生效
sysctl -p
# /etc/security/limits.conf
* soft nofile 65535
* hard nofile 65535
* soft nproc 65535
* hard nproc 65535
2.3 监控和压力测试
2.3.1 安装监控工具
# Nginx状态监控
# 在nginx.conf中添加
location /nginx_status {
stub_status on;
access_log off;
allow 127.0.0.1;
deny all;
}
# Tomcat JMX监控
# catalina.sh中添加
JAVA_OPTS="$JAVA_OPTS -Dcom.sun.management.jmxremote"
JAVA_OPTS="$JAVA_OPTS -Dcom.sun.management.jmxremote.port=9999"
JAVA_OPTS="$JAVA_OPTS -Dcom.sun.management.jmxremote.authenticate=false"
JAVA_OPTS="$JAVA_OPTS -Dcom.sun.management.jmxremote.ssl=false"
2.3.2 压力测试
# 使用 wrk 进行压测
wrk -t8 -c1000 -d60s --latency http://example.com/
# 参数说明:
# -t8: 8个线程
# -c1000: 1000个并发连接
# -d60s: 持续60秒
# --latency: 显示延迟分布
# 预期结果:
# Requests/sec: 20000+ (QPS)
# Latency: avg<50ms, p99<200ms
三、示例代码和配置
3.1 完整配置示例
3.1.1 Tomcat 生产环境配置
<!-- /opt/tomcat/conf/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">
<!-- 线程池配置 -->
<Executor name="tomcatThreadPool"
namePrefix="catalina-exec-"
maxThreads="800"
minSpareThreads="100"
maxIdleTime="60000"
prestartminSpareThreads="true"
maxQueueSize="1000" />
<!-- HTTP连接器 -->
<Connector port="8080"
protocol="org.apache.coyote.http11.Http11NioProtocol"
executor="tomcatThreadPool"
maxConnections="10000"
acceptCount="1000"
connectionTimeout="20000"
keepAliveTimeout="60000"
maxKeepAliveRequests="100"
compression="on"
compressionMinSize="2048"
compressibleMimeType="text/html,text/xml,text/plain,text/css,text/javascript,application/javascript,application/json,application/xml"
URIEncoding="UTF-8"
enableLookups="false"
disableUploadTimeout="true"
maxHttpHeaderSize="8192"
redirectPort="8443"
server="Apache" />
<!-- AJP连接器(如果使用Apache httpd) -->
<!-- <Connector port="8009" protocol="AJP/1.3" redirectPort="8443" /> -->
<Engine name="Catalina" defaultHost="localhost">
<Realm className="org.apache.catalina.realm.LockOutRealm">
<Realm className="org.apache.catalina.realm.UserDatabaseRealm"
resourceName="UserDatabase"/>
</Realm>
<Host name="localhost" appBase="webapps"
unpackWARs="true" autoDeploy="false">
<!-- 访问日志配置 -->
<Valve className="org.apache.catalina.valves.AccessLogValve" directory="logs"
prefix="localhost_access_log" suffix=".txt"
pattern="%h %l %u %t "%r" %s %b %D" />
<!-- 启用远程IP获取 -->
<Valve className="org.apache.catalina.valves.RemoteIpValve"
remoteIpHeader="X-Forwarded-For"
protocolHeader="X-Forwarded-Proto" />
</Host>
</Engine>
</Service>
</Server>
# /opt/tomcat/bin/setenv.sh
#!/bin/bash
# JVM内存设置
JAVA_OPTS="$JAVA_OPTS -Xms4g -Xmx4g"
JAVA_OPTS="$JAVA_OPTS -XX:MetaspaceSize=256m -XX:MaxMetaspaceSize=512m"
JAVA_OPTS="$JAVA_OPTS -Xss512k"
# GC设置
JAVA_OPTS="$JAVA_OPTS -XX:+UseG1GC"
JAVA_OPTS="$JAVA_OPTS -XX:MaxGCPauseMillis=200"
JAVA_OPTS="$JAVA_OPTS -XX:ParallelGCThreads=4"
JAVA_OPTS="$JAVA_OPTS -XX:ConcGCThreads=1"
JAVA_OPTS="$JAVA_OPTS -XX:InitiatingHeapOccupancyPercent=45"
# GC日志
JAVA_OPTS="$JAVA_OPTS -Xloggc:/opt/tomcat/logs/gc_%t.log"
JAVA_OPTS="$JAVA_OPTS -XX:+PrintGCDetails"
JAVA_OPTS="$JAVA_OPTS -XX:+PrintGCDateStamps"
JAVA_OPTS="$JAVA_OPTS -XX:+UseGCLogFileRotation"
JAVA_OPTS="$JAVA_OPTS -XX:NumberOfGCLogFiles=10"
JAVA_OPTS="$JAVA_OPTS -XX:GCLogFileSize=100M"
# OOM处理
JAVA_OPTS="$JAVA_OPTS -XX:+HeapDumpOnOutOfMemoryError"
JAVA_OPTS="$JAVA_OPTS -XX:HeapDumpPath=/opt/tomcat/logs/heap_dump_%p.hprof"
JAVA_OPTS="$JAVA_OPTS -XX:ErrorFile=/opt/tomcat/logs/hs_err_pid%p.log"
# 性能优化
JAVA_OPTS="$JAVA_OPTS -Djava.security.egd=file:/dev/./urandom"
JAVA_OPTS="$JAVA_OPTS -Djava.awt.headless=true"
JAVA_OPTS="$JAVA_OPTS -Duser.timezone=Asia/Shanghai"
JAVA_OPTS="$JAVA_OPTS -Dfile.encoding=UTF-8"
# JMX监控
JAVA_OPTS="$JAVA_OPTS -Dcom.sun.management.jmxremote"
JAVA_OPTS="$JAVA_OPTS -Dcom.sun.management.jmxremote.port=9999"
JAVA_OPTS="$JAVA_OPTS -Dcom.sun.management.jmxremote.authenticate=false"
JAVA_OPTS="$JAVA_OPTS -Dcom.sun.management.jmxremote.ssl=false"
JAVA_OPTS="$JAVA_OPTS -Djava.rmi.server.hostname=192.168.1.100"
export JAVA_OPTS
3.1.2 Nginx 完整配置
由于篇幅限制,完整的Nginx配置已在2.2节中展示,这里补充一个自动化部署脚本:
#!/bin/bash
# 文件名: deploy_nginx_tomcat.sh
# 功能: 一键部署和优化Nginx+Tomcat环境
set -e
echo "========== 开始部署 Nginx + Tomcat =========="
# 1. 安装依赖
yum install -y gcc gcc-c++ make zlib-devel pcre-devel openssl-devel
# 2. 编译安装Nginx
cd /tmp
wget http://nginx.org/download/nginx-1.24.0.tar.gz
tar -xzf nginx-1.24.0.tar.gz
cd nginx-1.24.0
./configure --prefix=/usr/local/nginx \
--with-http_ssl_module \
--with-http_v2_module \
--with-http_realip_module \
--with-http_stub_status_module \
--with-http_gzip_static_module \
--with-threads \
--with-file-aio
make && make install
# 3. 配置Nginx
cat > /usr/local/nginx/conf/nginx.conf << 'EOF'
# 此处粘贴2.2.1节的配置
EOF
# 4. 创建systemd服务
cat > /etc/systemd/system/nginx.service << 'EOF'
[Unit]
Description=Nginx HTTP Server
After=network.target
[Service]
Type=forking
PIDFile=/usr/local/nginx/logs/nginx.pid
ExecStartPre=/usr/local/nginx/sbin/nginx -t
ExecStart=/usr/local/nginx/sbin/nginx
ExecReload=/bin/kill -s HUP $MAINPID
ExecStop=/bin/kill -s QUIT $MAINPID
PrivateTmp=true
[Install]
WantedBy=multi-user.target
EOF
# 5. 系统优化
cat >> /etc/sysctl.conf << 'EOF'
fs.file-max = 1000000
net.core.somaxconn = 65535
net.ipv4.tcp_tw_reuse = 1
net.ipv4.tcp_fin_timeout = 30
EOF
sysctl -p
cat >> /etc/security/limits.conf << 'EOF'
* soft nofile 65535
* hard nofile 65535
EOF
# 6. 启动Nginx
systemctl daemon-reload
systemctl enable nginx
systemctl start nginx
# 7. 安装Tomcat
cd /opt
wget https://dlcdn.apache.org/tomcat/tomcat-9/v9.0.80/bin/apache-tomcat-9.0.80.tar.gz
tar -xzf apache-tomcat-9.0.80.tar.gz
ln -s apache-tomcat-9.0.80 tomcat
# 8. 配置Tomcat (使用之前的server.xml和setenv.sh)
# 9. 启动Tomcat
/opt/tomcat/bin/startup.sh
echo "========== 部署完成 =========="
echo "Nginx: http://your-ip"
echo "Tomcat: http://your-ip:8080"
echo "请根据实际情况调整配置文件"
3.2 实际应用案例
案例一:电商大促高并发场景
场景描述:某电商平台双11大促,预计峰值QPS达到 50000,需要保证商品详情页和下单接口的稳定性。
架构方案:
用户 -> CDN -> Nginx(4台) -> Tomcat集群(20台) -> Redis/MySQL
Nginx 配置要点:
upstream product_backend {
least_conn; # 最少连接数算法
server 10.0.1.101:8080 weight=1 max_fails=2 fail_timeout=10s;
server 10.0.1.102:8080 weight=1 max_fails=2 fail_timeout=10s;
# ... 其他18台
keepalive 512;
}
server {
listen 80;
server_name m.shop.com;
# 商品详情页缓存
location ~ ^/product/(\d+)$ {
proxy_pass http://product_backend;
proxy_cache product_cache;
proxy_cache_valid 200 5m; # 缓存5分钟
proxy_cache_key "$scheme$request_method$host$request_uri";
proxy_cache_use_stale updating error timeout;
add_header X-Cache-Status $upstream_cache_status;
}
# 下单接口不缓存
location /order/create {
limit_req zone=order_limit burst=50 nodelay;
proxy_pass http://product_backend;
proxy_next_upstream off; # 下单不重试
}
}
# 订单接口限流:每个IP每秒最多20个请求
limit_req_zone $binary_remote_addr zone=order_limit:10m rate=20r/s;
# 缓存配置
proxy_cache_path /data/nginx/cache/product
levels=1:2
keys_zone=product_cache:500m
max_size=50g
inactive=10m;
压测结果:
# 优化前
wrk -t8 -c2000 -d60s http://m.shop.com/product/12345
Requests/sec: 8,523.42
Latency: avg 234ms, p99 1.2s
# 优化后
Requests/sec: 52,341.18 (提升 6.1 倍)
Latency: avg 38ms, p99 156ms (降低 85%)
案例二:微服务 API 网关
场景描述:作为微服务网关,需要高效转发数万后端服务请求,且支持灰度发布和流量染色。
Nginx 配置:
# 根据Cookie进行灰度发布
map $cookie_version $backend_pool {
"beta" backend_beta;
default backend_stable;
}
upstream backend_stable {
server 10.0.2.101:8080;
server 10.0.2.102:8080;
keepalive 256;
}
upstream backend_beta {
server 10.0.2.201:8080; # 灰度服务器
keepalive 64;
}
server {
listen 80;
server_name api.example.com;
location / {
# 动态选择后端池
proxy_pass http://$backend_pool;
# 长连接优化
proxy_http_version 1.1;
proxy_set_header Connection "";
# 超时优化
proxy_connect_timeout 5s;
proxy_read_timeout 30s;
# 流量染色
add_header X-Backend-Pool $backend_pool;
}
}
Tomcat 线程池配置:
<!-- API网关后端建议较大的线程池 -->
<Executor name="apiThreadPool"
maxThreads="1000"
minSpareThreads="200"
prestartminSpareThreads="true" />
四、最佳实践和注意事项
4.1 最佳实践
4.1.1 性能优化
- 优化点一:静态资源分离
# Nginx直接处理静态资源,不转发给Tomcat
location ~* \.(jpg|jpeg|png|gif|ico|css|js|woff|woff2|ttf|svg)$ {
root /data/static;
expires 30d;
access_log off;
}
效果:Nginx 处理静态文件的性能是 Tomcat 的 10 倍以上。
- 优化点二:启用 HTTP/2
server {
listen 443 ssl http2; # 启用HTTP/2
ssl_certificate /path/to/cert.pem;
ssl_certificate_key /path/to/key.pem;
}
效果:多路复用,减少连接数,提升加载速度 30%~50%。
-
优化点三:连接池复用
upstream backend {
server 127.0.0.1:8080;
keepalive 256; # 关键配置
keepalive_requests 10000;
keepalive_timeout 60s;
}
location / {
proxy_pass http://backend;
proxy_http_version 1.1; # 必须
proxy_set_header Connection ""; # 必须
}
效果:减少 TCP 握手,QPS 提升 30%~40%。
4.1.2 安全加固
-
安全措施一:限制请求速率
# 全局限流
limit_req_zone $binary_remote_addr zone=global_limit:10m rate=100r/s;
limit_conn_zone $binary_remote_addr zone=conn_limit:10m;
server {
limit_req zone=global_limit burst=200 nodelay;
limit_conn conn_limit 20; # 单IP最多20个并发连接
}
-
安全措施二:防止慢速攻击
# Nginx配置
client_body_timeout 10s;
client_header_timeout 10s;
send_timeout 10s;
# Tomcat配置
<Connector connectionTimeout="20000" # 20秒超时
connectionUploadTimeout="300000" # 上传文件5分钟超时
disableUploadTimeout="false" />
-
安全措施三:隐藏版本信息
# Nginx
server_tokens off;
# Tomcat server.xml
<Connector server="Apache" /> # 伪装成Apache
# 或在web.xml中添加
<error-page>
<error-code>404</error-code>
<location>/error/404.html</location>
</error-page>
4.2 注意事项
⚠️ 警告:参数调优需结合实际业务压测,避免盲目调大参数。
- ❗ 注意事项一:线程数不是越大越好
- 错误示例:
maxThreads="5000" 导致线程切换开销巨大。
- 正确做法:从 200 开始,每次增加 100,压测找到最佳值。
- 判断标准:CPU 使用率 70%~80%,响应时间稳定。
- ❗ 注意事项二:Keep-Alive 超时时间需前后端一致
- 问题:Nginx
keepalive_timeout > Tomcat keepAliveTimeout。
- 后果:Nginx 认为连接还活着,但 Tomcat 已关闭,导致 502 错误。
- 解决:Tomcat 超时时间应略大于 Nginx(如 Nginx 60s,Tomcat 65s)。
- ❗ 注意事项三:压缩会增加 CPU 负载
- 场景:如果前端有 CDN 压缩,Nginx/Tomcat 可关闭压缩。
- 建议:
gzip_comp_level 设置 5~6 即可,不要设置 9。
五、故障排查和监控
5.1 故障排查
5.1.1 日志查看
# Nginx日志实时查看
tail -f /var/log/nginx/access.log | grep "502\|503\|504"
# Tomcat日志
tail -f /opt/tomcat/logs/catalina.out
# 分析响应时间慢的请求
awk '{if($NF>1000)print $0}' /var/log/nginx/access.log | tail -20
5.1.2 常见问题排查
问题一:Nginx 502 错误
# 1. 检查Tomcat是否正常
curl -I http://127.0.0.1:8080
# 2. 查看Nginx错误日志
tail -f /var/log/nginx/error.log
# 常见原因: connect() failed (111: Connection refused)
# 3. 检查防火墙
iptables -L -n | grep 8080
# 4. 检查SELinux
getenforce
# 如果是Enforcing,临时关闭: setenforce 0
问题二:连接数打满
# 查看当前连接数
ss -ant | grep :80 | wc -l
# 查看各状态连接数
ss -ant | awk '{print $1}' | sort | uniq -c
# 查看Tomcat线程状态
curl http://localhost:8080/manager/status/all | grep "currentThreadsBusy"
# 解决方案:
# 1. 增大 maxThreads 和 maxConnections
# 2. 优化慢接口,减少响应时间
# 3. 启用连接池复用
5.2 性能监控
5.2.1 Prometheus + Grafana 监控
# prometheus.yml
scrape_configs:
# Nginx监控
- job_name: 'nginx'
static_configs:
- targets: ['localhost:9113'] # nginx-prometheus-exporter
# Tomcat JMX监控
- job_name: 'tomcat'
static_configs:
- targets: ['localhost:9404'] # jmx_exporter
5.2.2 告警规则
# prometheus_rules.yml
groups:
- name: nginx_alerts
rules:
- alert: NginxHighConnections
expr: nginx_connections_active > 5000
for: 5m
labels:
severity: warning
annotations:
summary: "Nginx连接数过高"
description: "当前连接数: {{ $value }}"
- alert: Nginx5xxErrors
expr: rate(nginx_http_requests_total{status=~"5.."}[5m]) > 10
for: 2m
labels:
severity: critical
annotations:
summary: "Nginx 5xx错误率过高"
- name: tomcat_alerts
rules:
- alert: TomcatThreadPoolExhausted
expr: tomcat_threads_busy / tomcat_threads_max > 0.9
for: 5m
labels:
severity: critical
annotations:
summary: "Tomcat线程池即将耗尽"
- alert: TomcatHighHeapUsage
expr: jvm_memory_bytes_used{area="heap"} / jvm_memory_bytes_max{area="heap"} > 0.85
for: 10m
labels:
severity: warning
annotations:
summary: "Tomcat堆内存使用率过高"
六、总结
6.1 技术要点回顾
- 要点一:Tomcat 调优核心在于线程池配置、JVM 参数和连接器优化,需结合实际 QPS 和响应时间计算合理的
maxThreads。对于 Java 应用的性能调优,JVM是核心。
- 要点二:Nginx 调优重点是
worker_connections、keepalive 连接池、gzip 压缩和缓存策略,静态资源分离可显著提升性能。当涉及到缓存、限流等配置时,可以参考 数据库与中间件 中的相关设计理念。
- 要点三:系统内核参数(
ulimit、tcp_tw_reuse 等)是性能瓶颈的隐形杀手,必须同步优化。
- 要点四:建立完善的监控体系(Prometheus + Grafana)和压测流程,持续优化才能保证长期稳定。这部分工作属于 运维与测试 的范畴,是保障系统稳定性的关键。
6.2 参数速查表
| 参数类别 |
Nginx 关键参数 |
Tomcat 关键参数 |
推荐值 |
| 并发连接 |
worker_connections |
maxConnections |
10000 |
| 工作线程 |
worker_processes |
maxThreads |
auto / 800 |
| 长连接超时 |
keepalive_timeout |
keepAliveTimeout |
60s |
| 连接池 |
keepalive |
- |
256 |
| 请求体大小限制 |
client_max_body_size |
maxPostSize |
100m |
| 连接超时 |
proxy_connect_timeout |
connectionTimeout |
10s / 20s |
| 读取超时 |
proxy_read_timeout |
- |
60s |