事件经过:
- 收到反馈测试环境某个服务打开 swagger ,进程会卡死
- 根据经验,初步判定是有死循环。
- 在本地启动该服务,打开 swagger ,发现 CPU 单核100%,确认有死循环
- pprof 抓取 cpu profile
- 在 marshal 前后打断点,对于特定链接,marshal 没结束(没看到 done 日志)
- 更换为官方 json 库,恢复正常。确认是 json-iterator 导致
- 在其他项目做同样操作,未能复现问题。对比jsoniter 版本,初步判定是版本过老导致。
- 通过 debug,确认是下面这个循环走不出来
- 升级 jsoniter ,恢复正常
- 到官方一看,这个bug 很早就解决了。但是出事的服务还在依赖 2017-8-9 的版本。(修复链接:https://github.com/json-iterator/go/commit/f7063353029dd177a959dbf6b29f48746441fbfa#diff-34ab17b5ece86461ae47905134a8d94c)
回到初始问题,为什么有 for{} 进程会假死
原因在于 非抢占式调度+Full GC,导致 stw 停不下来。
暴露的问题
- 对 Go 底层完全 hold 不住
- 第三方包管理不规范
参考链接
- Goroutine调度实例简要分析 https://tonybai.com/2017/11/23/the-simple-analysis-of-goroutine-schedule-examples/
- 关于for{}的抢占式讨论 https://github.com/golang/go/issues/10958
- 滴滴大佬如何定位 golang 进程 hang 死的 bug https://gocn.vip/article/441