正文
背景
业务上量以后,对程序进行 profiling 性能诊断对很多后端程序员来说就是家常便饭。一个趁手的工具往往能让这个事情做起来事半功倍。
在这方面,go 有着天然的优势:继承
Google’s pprof C++ profiler
的衣钵,从出生就有
go tool pprof
工具。并且,标准库里面提供
runtime/pprof
和
net/http/pprof
两个package, 使得 profiling 可编程化。
在非容器环境下,我们的研发同学喜欢使用
net/http/pprof
来提供http接口供
go tool pprof
工具进行 profiling:
import _ "net/http/pprof"
func main(){
...
go func() {
log.Println(http.ListenAndServe("localhost:6060", nil))
}()
...
}
获取 CPU profile 数据:
go tool pprof http://localhost:6060/debug/pprof/profile
但是,当架构逐步演进为微服务架构并使用k8s等容器化技术进行部署以后,这种这种方式面临的问题也越来越多:
-
我们生产环境使用k8s进行容器编排和部署。service类型是 NodePort. 因此研发同学无法直接对某个 service 的特定 pod 进行 profiling. 之前的解决方式是:
-
如果要诊断的问题是这个service普遍存在的问题,则直接进行 profiling。
-
如果要诊断的问题只出现在这个service的某个特定的pod上,则由运维同学定位到该pod所处的宿主机后登录到该容器中进行profiling。耗时耗力,效率低。
-
架构微服务化以后,服务数量呈量级增加。以前那种出现问题再去诊断服务现场的方式越来越难满足频率和数量越来越多的profiling需求(很多情况下,我们才做好profiling的准备,问题可能已经过去了……)。我们迫切的需要一种能够在程序出问题时,自动对程序进行profiling的方案,最大可能获取程序现场数据。
-
同时,我们希望这种自动profiling机制对程序性能影响尽可能小,并且可以与现有告警系统集成,直接将诊断结果通知到程序的owner.
方案设计与实现