作者:trumanyan,腾讯 CSIG 后台开发工程师
项目背景
网关服务作为统一接入服务,是大部分服务的统一入口。为了避免成功瓶颈,需要对其进行尽可能地优化。因此,特别总结一下 golang 后台服务性能优化的方式,并对网关服务进行优化。
技术背景:
基于 tarsgo 框架的 http 接入服务,下游服务使用 tarsgo 协议进行交互
性能指标
网关服务本身没有业务逻辑处理,仅作为统一入口进行请求转发,因此我们主要关注下列指标
吞吐量:每秒钟可以处理的请求数
响应时间:从客户端发出请求,到收到回包的总耗时
定位瓶颈
一般后台服务的瓶颈主要为 CPU,内存,IO 操作中的一个或多个。若这三者的负载都不高,但系统吞吐量低,基本就是代码逻辑出问题了。
在代码正常运行的情况下,我们要针对某个方面的高负载进行优化,才能提高系统的性能。golang 可通过 benchmark 加 pprof 来定位具体的性能瓶颈。
benchmark 简介
go test -v gate_test.go -run=none -bench=. -benchtime=3s -cpuprofile cpu.prof -memprofile mem.prof
-run 知道单次测试,一般用于代码逻辑验证
-bench=. 执行所有 Benchmark,也可以通过用例函数名来指定部分测试用例
-benchtime 指定测试执行时长
-cpuprofile 输出 cpu 的 pprof 信息文件
-memprofile 输出 heap 的 pprof 信息文件。
-blockprofile 阻塞分析,记录 goroutine 阻塞等待同步(包括定时器通道)的位置
-mutexprofile 互斥锁分析,报告互斥锁的竞争情况
benchmark 测试用例常用函数
b.ReportAllocs() 输出单次循环使用的内存数量和对象 allocs 信息
b.RunParallel() 使用协程并发测试
b.SetBytes(n int64) 设置单次循环使用的内存数量
pprof 简介
生成方式
runtime/pprof: 手动调用如
runtime.StartCPUProfile
或者runtime.StopCPUProfile
等 API 来生成和写入采样文件,灵活性高。主要用于本地测试。net/http/pprof: 通过 http 服务获取 Profile 采样文件,简单易用,适用于对应用程序的整体监控。通过 runtime/pprof 实现。主要用于服务器端测试。
go test: 通过
go test -bench . -cpuprofile cpuprofile.out
生成采样文件,主要用于本地基准测试。可用于重点测试某些函数。
查看方式
go tool pprof [options][binary] ...
-
--text 纯文本
--web 生成 svg 并用浏览器打开(如果 svg 的默认打开方式是浏览器)
--svg 只生成 svg
--list funcname 筛选出正则匹配 funcname 的函数的信息
-http=":port" 直接本地浏览器打开 profile 查看(包括 top,graph,火焰图等)
go tool pprof -base profile1 profile2
-
对比查看 2 个 profile,一般用于代码修改前后对比,定位差异点。
通过命令行方式查看 profile 时,可以在命令行对话中,使用下列命令,查看相关信息
-
flat flat% sum% cum cum% 5.95s 27.56% 27.56% 5.95s 27.56% runtime.usleep 4.97s 23.02% 50.58% 5.08s 23.53% sync.(*RWMutex).RLock 4.46s 20.66% 71.24% 4.46s 20.66% sync.(*RWMutex).RUnlock 2.69s 12.46% 83.70% 2.69s 12.46% runtime.pthread_cond_wait 1.50s 6.95% 90.64% 1.50s 6.95% runtime.pthread_cond_signal
flat: 采样时,该函数正在运行的次数*采样频率(10ms),即得到估算的函数运行”采样时间”。这里不包括函数等待子函数返回。
flat%: flat / 总采样时间值
sum%: 前面所有行的 flat% 的累加值,如第三行 sum% = 71.24% = 27.56% + 50.58%
cum: 采样时,该函数出现在调用堆栈的采样时间,包括函数等待子函数返回。因此 flat <= cum
cum%: cum / 总采样时间值
topN [-cum] 查看前 N 个数据:
list ncname 查看某个函数的详细信息,可以明确具体的资源(cpu,内存等)是由哪一行触发的。
pprof 接入 tarsgo
服务中 main 方法插入代码
cfg := tars.GetServerConfig() profMux := &tars.TarsHttpMux{} profMux.HandleFunc("/debug/pprof/", pprof.Index) profMux.HandleFunc("/debug/pprof/cmdline", pprof.Cmdline) profMux.HandleFunc("/debug/pprof/profile", pprof.Profile) profMux.HandleFunc("/debug/pprof/symbol", pprof.Symbol) profMux.HandleFunc("/debug/pprof/trace", pprof.Trace) tars.AddHttpServant(profMux, cfg.App+"."+cfg.Server+".ProfObj")
taf 管理平台中,添加 servant:ProfObj (名字可自己修改)
发布服务
查看 tasrgo 服务的 pprof
保证开发机能直接访问到 tarsgo 节点部署的 ip 和 port。
查看 profile(http 地址中的 ip,port 为 ProfObj 的 ip 和 port)
# 下载cpu profile go tool pprof http://ip:port/debug/pprof/profile?seconds=120 # 等待120s,不带此参数时等待30s # 下载heap profile go tool pprof http://ip:port/debug/pprof/heap # 下载goroutine profile go tool pprof http://ip:port/debug/pprof/goroutine # 下载block profile go tool pprof http://ip:port/debug/pprof/block # 下载mutex profile go tool pprof http://ip:port/debug/pprof/mutex # 下载20秒的trace记录(遇到棘手问题时,查看trace会比较容易定位) curl http://