Tomcat 调优不是把 maxThreads、maxConnections 和 acceptCount 全部调大。每多接受一个请求,都可能占用堆内存、数据库连接和远程服务配额。
参数必须服从端到端容量模型。
Table of contents
先算在途请求
容量估算样例下载使用 Little 定律的基本关系:
平均在途数量 = 每秒到达数量 × 平均停留秒数
mvn -Dtest=NetworkServerLabTest#estimatesInFlightRequests test
每秒 2,000 个请求、平均 80 毫秒,平均约有 160 个请求在途。这个数包含等待和执行,不等于需要 160 个 CPU 线程;分位数和突发流量还会让实际峰值更高。
分清四个容量位置
maxConnections:端点同时维护的最大连接;保持连接和慢客户端会占用它。maxThreads:同步请求处理的最大工作线程。acceptCount:达到连接上限后,操作系统接受队列还能容纳多少连接。- 下游池:数据库连接、HTTP 连接、消息发送并发等真实业务瓶颈。
如果 300 个请求线程争抢 50 个数据库连接,额外线程大多只是在内存里等待。更合理的做法是让入口并发接近可持续下游容量,过载时尽早拒绝。
按证据调参
先固定负载模型,采集吞吐、错误率、P50/P95/P99、活动线程、排队、连接、GC、CPU 和下游池等待。每次只改一组有关参数,再重复同样实验。
CPU 密集请求的可运行线程起点接近可用核心数;大量同步 I/O 等待可能需要更多线程,但上限由内存和下游容量决定。虚拟线程能降低线程等待成本,不能扩大数据库容量。
超时构成一条预算
代理、Tomcat、应用和下游客户端的超时应从外向内逐渐缩短,为错误编码和响应返回留时间。连接超时、请求读取超时、业务截止时间和保持连接超时职责不同, 不要用一个巨大数字代替设计。
慢客户端保护同样重要:限制请求头、正文、上传时间和响应写积压。否则少量慢连接就能持续占用连接与内存。
压测应该验证过载行为
逐步增加负载直到首次达到服务目标边界,再保持负载观察是否稳定。随后注入慢数据库、连接失败和突发请求,确认队列有界、拒绝明确、恢复后无长期积压。 “峰值 QPS 很高”不如“目标 P99 下可持续运行并能从故障恢复”有价值。
下一步
阅读Tomcat 类加载、热部署与内存泄漏,理解重新加载后旧应用为什么可能仍留在内存。