Go 性能调优| 青训营笔记

这是我参与「第五届青训营 」伴学笔记创作活动的第 10 天

前言

本文主要介绍实际业务服务性能优化的案例以及对逻辑相对复杂的程序是如何进行性能调优的。

优化类型可分为:业务服务优化、基础库优化、Go语言优化。

业务服务优化

基本概念

  • 服务:能单独部署,承载一定功能的程序
  • 依赖:ServiceA的功能实现依赖ServiceB的响应结果,称之为ServiceA依赖ServiceB
  • 调用链路:能支持一个接口请求的相关服务集合及其相互之间的依赖关系
  • 基础库:公共的工具包、中间件

image.png

上图是系统部署的简单示意图,客户端请求经过网关转发,由不同的业务服务处理,业务服务可能依赖其他的服务,也可能会依赖存储、消息队列等组件。

接下来我们以业务服务优化为例,说明性能调优的流程,图中的 ServiceB 被 ServiceA依赖,同时也依赖了存储和ServiceD。

优化流程

  1. 建立服务性能评估手段
  2. 分析性能数据,定位性能瓶颈
  3. 重点优化项改造
  4. 优化效果验证

建立服务性能评估手段

  • 服务性能评估方式
    • 单独benchmark无法满足复杂逻辑分析
    • 不同负载情况下性能表现差异
  • 请求流量构造
    • 不同请求参数覆盖逻辑不同
    • 线上真实流量情况
  • 压测范围
    • 单机压测
    • 集群压测
  • 性能数据采集
    • 单机性能数据
    • 集群性能数据

因为逻辑复杂,不同的请求参数会走不同的处理逻辑,对应的性能表现也不相同,需要尽量模拟线上真实情况,分析真正的性能瓶颈。

压测会录制线上的请求流量,通过控制回放速度来对服务进行测试,测试范围可以是单个实例,也可以是整个集群,同样性能采集也会区分单机和集群。

评估手段建立后,会产生一个服务的性能指标分析报告。

实际的压测报告上会统计压测期间服务的各项监控指标,包括qps,延迟等内容,同时在压测过程中,也可以采集服务的pprof数据,使用之前的方式分析性能问题。

分析性能数据

分析性能数据,定位性能瓶颈

有了服务优化前的性能报告和一些性能采样数据,我们可以进行性能瓶颈分析了。

业务服务常见的性能问题可能是使用基础组件不规范

比如下面代码,每次使用配置时都会进行json解析,拿到配置项,实际组件内部提供了缓存机制,只有数据变更的时候才需要重新解析json。

image.png

还有可能是:高并发场景优化不足

image.png

image.png

上边是服务高峰期的火焰图,下边是低峰期的火焰图,可以发现metrics,即监控组件的CPU资源占用变化较大,主要原因是监控数据上报是同步请求,在请求量上涨,监控打点数据量增加时,达到性能瓶颈,造成阻塞,影响业务逻辑的处理,后续是改成异步上报的机制提升了性能。

重点优化项改造

定位到性能瓶颈后,修改完后能直接发布上线吗?

  • 正确性是基础
  • 响应数据diff
    • 线上请求数据录制回放
    • 新旧逻辑接口数据diff

性能优化的前提是保证正确性,在变动较大的性能优化上线之前,还需要进行正确性验证,因为线上的场景和流程太多,所以要借助自动化手段来保证优化后程序的正确性。

线上请求的录制,要包含请求参数录制、返回内容录制,重放时对比优化前后返回内容进行正确性验证。

优化效果验证

  • 重复压测验证
  • 上线评估优化效果
    • 关注服务监控
    • 逐步放量
    • 收集性能数据

改造完成后,可以进行优化效果验证了。

验证分两部分,首先依然是用同样的数据对优化后的服务进行压测。

正式上线的时候会逐步放量,记录真正的优化效果。

压测并不能保证和线上表现完全一致,有时还要通过线上的表现再进行分析改进,是个长期的过程。

进一步优化

进一步优化,服务整体链路分析

  • 规范上游服务调用接口,明确场景需求
  • 分析链路,通过业务流程优化提升服务性能

基础库优化

基础库优化使用范围更广,在实际的业务服务中,为了评估某些功能上线后的效果,经常需要进行AB实验,看看不同策略对核心指标的影响,所以公司内部多数服务都会使用AB实验的SDK,如果能优化AB组件库的性能,所有用到的服务都会有性能提升。

类似业务服务的优化流程,也会先统计下各个服务中AB组件的资源占用情况,看看AB组件的哪些逻辑更耗费资源,提取公共问题进行重点优化。

SDK优化主要包括:

  • 分析基础库核心逻辑和性能瓶颈
    • 设计完善改造方案
    • 数据按需获取
    • 数据序列化协议优化
  • 内部压测验证
  • 推广业务服务落地验证

Go语言优化

针对Go本身进行的优化,会优化编译器和运行时的内存分配策略,构建更高效的go发行版本。

Go语言优化主要是编译器和运行时的优化,主要包括:

  • 优化内存分配策略
  • 优化代码编译流程,生成更高效的程序
  • 内部压测验证
  • 推广业务服务落地验证

此优化方案接入简单,只需要调整编辑器编译配置就行,并且通用性较强。

总结

  • 性能调优原则
    • 要依靠数据而不是猜测
  • 性能分析工具
    • 熟练使用pprof工具排查性能问题并了解其基本原理
  • 性能调优
    • 保证正确性
    • 定位主要瓶颈

引用

性能调优实战案例

猜你喜欢

转载自juejin.im/post/7194236380300951609