很多开发调性能时会问:
“CPU 够用吗?”
“有没有慢 SQL?”
“Redis 热 key 吗?”
这些当然重要,但它们不是最可怕的。
真正危险的是那些 你看不见、监控也不会主动告诉你、只有在特定场景下才出现的“时间偷窃者”。
它们每次偷你一两毫秒,
但在高并发场景下,就是几百毫秒的延迟。
下面,我把这些“隐形怪物”一个个拉到台前。
🥷 1. 阻塞式日志(Blocking Logging)
很多开发不知道:
log.info("xxx {}", data);
在高峰期可能是最重的操作之一。
尤其当:
- info 级别刷盘
- 日志格式化有对象序列化
- 多线程写同一个文件(锁竞争)
你以为是打印字符串,
其实系统正在等待 IO。
真正快的系统都采用:
- 异步日志(AsyncAppender)
- JSON 序列化池化
- 降低日志粒度
🌀 2. 不可见的 GC 暂停
GC 不是造成卡顿,而是造成“瞬时冻结”。
几十毫秒、人类感觉不到,
但服务会立刻体现:
- RT 尖刺
- 调用超时
- 重试风暴
这是经典的:
“GC 不是你慢,而是你完全没反应。”
⛓ 3. 线程切换(Context Switch Overload)
线程越多越快?
错。
线程多意味着:
- 切换频繁
- CPU 花更多时间调度
- 实际执行时间减少
这就是 线程池调大反而变慢 的根本原因。
🗝 4. 悲观锁导致的“隐藏排队”
看似一个简单的锁:
synchronized (obj)
当高并发时会变成:
- 排队
- 排队
- 排队
- 所有排队的线程都在浪费 CPU 时间
这是性能黑洞。
💥 5. 热点字段的序列化开销
例如一个大 JSON 对象:
{
"user": {...},
"organization": {...},
"permissions": [...],
"history": [...]
}
每次请求都要序列化一遍?
你已经输了。
序列化是后端世界最容易被忽视的慢操作之一。
🧊 6. 并发写导致的缓存击穿
最凶险的缓存问题不是穿透、不是雪崩,而是:
大量请求同时发现缓存 miss → 全体打到 DB → 系统瞬间爆炸
一个简单的:
缓存未命中 → 加锁合并 → 回源
就能解决。
但很多系统没有。
🏎 7. 数据库连接池的抖动
连接池不是稳定的:
- 连接满了 → 阻塞
- 开新连接 → 慢
- 回收连接 → 慢
- 连接检查失败 → 更慢
你以为是 SQL 慢
其实是“没拿到连接”。
🌐 8. 跨机房延迟(跨可用区延迟)
很多系统跨可用区调用时延迟:
3ms → 15ms → 60ms
60ms * 7 个下游调用 = 420ms。
你以为:
“服务 B 慢”
实际:
“距离太远了”。
这类问题通常只有在看 trace map 时才会被发现。
🎬 尾声:性能不是某一个慢点,而是“被偷走的时间总和”
系统真正的敌人不是:
- 大对象
- 慢 SQL
- 热 key
而是:
那些你从未意识到、监控也看不到的“隐藏延迟”。
找出它们,你的系统会快到惊人。