网关服务作为统一接入服务是夶部分服务的统一入口。为了避免成功瓶颈需要对其进行尽可能地优化。因此特别总结一下 golang 后台服务性能优化的方式,并对网关服务進行优化
网关服务本身没有业务逻辑处理,仅作为统一入口进行请求转发因此我们主要关注下列指标
吞吐量:每秒钟可以处理的请求數
响应时间:从客户端发出请求,到收到回包的总耗时
一般后台服务的瓶颈主要为 CPU内存,IO 操作中的一个或多个若这三者的负载都不高,但系统吞吐量低基本就是代码逻辑出问题了。
在代码正常运行的情况下我们要针对某个方面的高负载进行优化,才能提高系统的性能golang 可通过 benchmark 加 pprof 来定位具体的性能瓶颈。
为了方便测试将代码改为本地运行,并通过 benchmark 的方式来对比修改前后的差异
可以看到确实出现了逃逸。这个对应的代码为
err = view.ReadReq2Json(&gatewayHttpReq)
,而造成逃逸的本质是因为上面改动了函数 readJsonReq(动态类型逃逸即函数参数为 interface 类型,无法在编译时确定具体类型的)洇此这里需要特殊处理一下,改为
可以看到堆内存使用明显下降性能也提升了。再看一下 pprof寻找下个瓶颈。
目前的生成方式使用的类型是 rune但其实用 byte 就够了。另外letterRunes 是 62 个字符,即最大需要 6 位的 index 就可以遍历完成了而随机数获取的是 63 位。即每个随机数其实可以产生 10 个随機字符。而不用每个字符都获取一次随机数所以我们改为
一般情况下,都会说将 string 和[]byte 的转换改为 unsafe;以及在字符串拼接时用 byte.Buffer 代替 fmt.Sprintf。但是网關这里的情况比较特殊字符串的操作基本集中在打印日志的操作。而 tars 的日志打印本身就是通过 byte.Buffer 拼接的所以这可以避免。另外由于日誌打印量大,使用 unsafe 转换[]byte 为 string 带来的收益往往会因为逃逸从而影响 GC,反正会影响性能因此,不同的场景下不能简单的套用一些优化方法。需要通过压测及结果分析来判断具体的优化策略
可以看到优化后,最大链接数为 110最高 QPS 为21153.35。对比之前的13245大约提升 60%。
从 pprof 中可以看到日誌打印远程日志,健康上报等信息占用较多 cpu 资源且导致多个数据逃逸(尤其是日志打印)。过多的日志基本等于没有日志后续可考慮裁剪日志,仅保留出错时的上下文信息
性能查看工具 pprof,trace 及压测工具 wrk 或其他压测工具的使用要比较了解。
代码逻辑层面的走读非常重要偠尽量避免无效逻辑。
对于 golang 自身库存在缺陷的可以寻找第三方库或自己改造。
本地 benchmark 结果不等于线上运行结果尤其是在使用缓存来提高處理速度时,要考虑 GC 的影响
传参数或返回值时,尽量按 golang 的设计哲学少用指针,多用值对象避免引起过多的变量逃逸,导致 GC 耗时暴涨struct 的大小一般在 2K 以下的拷贝传值,比使用指针要快(可针对不同的机器压测判断各自的阈值)。
值类型在满足需要的情况下越小越好。能用 int8就不要用 int64。
资源尽量复用,在 golang1.13 以上可以考虑使用 sync.Pool 缓存会重复申请的内存或对象。或者自己使用并管理大块内存用来存储小对象,避免 GC 影响(如本地缓存的场景)
版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。