接口平时 20 毫秒,每隔几分钟冒一次 200 毫秒以上,火焰图看不出热点,打开 block profile 后大头集中在 `runtime.chanrecv` 和 `sync.runtime_Semacquire`,等待时间和 CPU 完全对不上。第一次遇到会往复杂处想,其实漏掉的多是个小前提。

runtime.SetBlockProfileRate(10000)
go tool pprof -http=:8080 block.out
curl -o block.out localhost:6060/debug/pprof/block

block profile 默认不开启,采样率是 1,只能看到长期阻塞的调用点,等待时间算在阻塞而不是 CPU,火焰图自然找不到,问题多半出在锁竞争或者 channel 等数据上。这一点先确认清楚,后面就不用反复试。

「block profile 阻塞」相关的日志我一般连着看前后五分钟,单看一条报错经常判断不出是哪一步失败。把这次用到的命令存进笔记,比记住结论有用,换个环境还能照着走。

改完隔一天再看一次,当场正常不代表能稳住。

具体做法是,先把阻塞采样率打开再按真实流量复现问题;按累计等待时间排序,而不是只看它出现的次数;对照互斥锁采样结果区分锁和通道两种阻塞。

改完照着核一遍,200 毫秒的尖刺能对应到具体阻塞点,优化之后该指标明显下降。

作者 9823189