go tool trace 通过 syscall blocking profile 和 network blocking profile 定位网络 i/o 卡点,但 network blocking profile 常为空,因其依赖 runtime 显式上报;syscall blocking profile 更可靠,能捕获 read、connect 等底层系统调用阻塞,并配合 strace 查 errno 实现闭环诊断。

go tool trace 本身不直接提供“网络阻塞分析”独立视图,但能通过 Syscall blocking profile 和 Network blocking profile 两个面板定位网络 I/O 卡点——前提是 trace 文件里真有网络事件发生。
为什么 Network blocking profile 经常为空或没数据
这个面板依赖 Go runtime 对网络 poll 的显式上报,不是所有网络操作都会触发它。常见空数据原因:
-
net/http客户端默认使用带超时的http.Transport,若请求快速完成(如本地回环、缓存命中),不会进入阻塞态,也就没事件上报 - 服务端未真正处理请求:比如
http.ListenAndServe启动后立刻退出,或 handler 里没做实际读写(如只 return 而不调用req.Body.Read) - 用了非标准网络库(如
gRPC-Go自研的http2实现)或 CGO 封装的 socket,绕过了 Go runtime 的 poller 跟踪机制 -
trace.Start()调用太晚——必须在http.Serve或net.Listener.Accept之前启动,否则连接建立、读取等关键阶段全被漏掉
Syscall blocking profile 才是查网络卡死的第一入口
只要底层调用了 read、write、accept、connect 等系统调用,不管是否走 Go netpoll,Syscall blocking profile 都会捕获。它比 Network blocking profile 更可靠:
- 看到
read长时间阻塞 → 检查conn.SetReadDeadline是否设置,或远端未发数据 - 看到
connect阻塞 → DNS 解析失败、防火墙拦截、目标端口未监听(errno=111) - 看到
epoll_wait或kqueue阻塞 → 正常,说明 netpoller 在等事件;但若持续数秒无返回,可能是文件描述符泄漏或 poller 失效 - 注意区分:阻塞在
internal/poll.runtime_pollWait是 Go 层封装的等待,而read@0x7f...是内核 syscall 级别——后者更底层、更真实
如何让网络阻塞在 trace 中“显形”
纯代码逻辑不触发网络 I/O,trace 就不会记。必须构造真实阻塞场景:
- 服务端:handler 里用
time.Sleep(5 * time.Second)模拟慢响应,或io.Copy(ioutil.Discard, req.Body)读取大 body 但不设 timeout - 客户端:用
http.DefaultClient.Timeout = 0+ 访问一个故意不响应的地址(如http://10.255.255.1),强制触发connect阻塞 - 避免用
os.Stdout接收 trace:必须os.Create("trace.out")并确保trace.Stop()执行到,否则文件为空,所有视图都失效 - 采集时间至少 10 秒:短于一次 TCP handshake + TLS 握手 + body 传输的总耗时,trace 可能只记录到一半事件
真正卡在网络上的问题,往往不在 Go 代码逻辑里,而在连接建立、证书验证、远端响应这些 runtime 不可控环节。Syscall blocking profile 显示的 connect 或 read 阻塞,配合 strace -p PID -f -ttt 查 errno,才是闭环诊断的关键组合。
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!











