交互式服务必须优先保障延迟,STW停顿是核心目标;Web API、网关等用户敏感场景中,P99.9延迟超200ms将致投诉陡增,吞吐让位于低延迟。

先看服务类型,再定目标——延迟和吞吐不是选择题,是约束条件
交互式服务必须优先保延迟,哪怕牺牲吞吐
Web API、网关、实时推荐、游戏服务器这类服务,用户感知直接绑定单次响应。P99.9延迟一旦超过200ms,投诉率会陡增;卡顿一次,用户就可能刷新或退出。这时候吞吐量再高也没用——没人愿意等。
- 目标明确:STW停顿
- 监控重点:用
jstat -gc看G1 Evacuation Pause或ZGC Pauses的耗时分布,配合-Xlog:gc*,safepoint确认是否真无长停顿 - 典型错误:把
-XX:MaxGCPauseMillis=100设给Parallel GC——它根本不支持该参数,只会静默忽略
批处理任务优先保吞吐,延迟可让步
离线计算、日志归档、报表生成、ETL清洗这些任务不直面用户,更在意“单位时间完成多少工作”。一次跑5分钟但CPU打满85%,比每分钟跑一次、每次卡2秒更优。
- 目标明确:GC总耗时占应用运行时间比例
- 关键动作:固定堆大小(
-Xms=-Xmx),用-XX:+UseParallelGC,调-XX:ParallelGCThreads匹配物理核数 - 容易踩的坑:在批处理里强行上ZGC——ZGC并发线程开销大,小堆(
同一服务不同模块,目标可能不一致
比如一个风控系统,实时决策路径要求P99.9
- 务实做法:拆JVM——决策服务用ZGC+4g堆,训练模块单独起进程,用Parallel GC+16g堆
- 替代方案(不推荐):用G1 +
-XX:G1HeapRegionSize=4m+-XX:MaxGCPauseMillis=200折中,但P99.9稳定性不如ZGC - 被忽略的关键点:ZGC从JDK 17起才默认启用,OpenJDK 11/15需显式加
-XX:+UnlockExperimentalVMOptions,否则启动失败报错Unrecognized VM option 'UseZGC'
真正难的不是选参数,是识别哪些模块真的对延迟敏感——有时候你以为的“实时接口”,背后调了三次慢SQL或一次同步HTTP外调,再好的GC也救不回来。


















