高质量编程与性能调优实战|青训营

88 阅读4分钟

一.简介

​ 在满足正确可靠、简洁清晰的代码质量的前提下需要提高程序性能,所以需要进行性能调优。性能调优原则如下:要依靠数据不是猜测,要定位最大瓶颈而不是细枝末节,不要过早优化,不要过度优化。在这里我们使用到一个性能分析工具pprof,该工具能够可视化查询到什么地方所耗费的CPU、Memory。

二.性能分析工具 pprof

1.pprof功能简介

​ pprof是golang内置的性能分析工具,在进行性能问题分析(入内存泄露,goroutine泄露,cpu资源占用较高等分析)时使用,其可成为我们进行golang开发时,调试应用性能的常用工具。它主要用于网页、可视化终端分析;可以展示调用图、火焰图,反汇编;有runtime、net/http工具,可以获取采样CPU、堆内存、协程、锁、阻塞、线程数据。

2.pprof项目实战

​ 搭建pprof实战项目。首先导入log、net/http、net/http/pprof包,实现自动注册 pprof 的 handler 到 http server,接着使用runtime的GOMAXPROCS限制CPU使用的数为1, 使用runtime的SetMutexProfileFracton开启锁调用跟踪,使用runtime的SetBlockProfileRate开启阻塞调用跟踪。最后,启动http服务器,监听的端口号为6060,即可打开浏览器地址栏输入localhost:6060/debug/pprof,便可查看相应指标。

import (
    "log"
    "net/http"
    "net/http/pprof” 
    
func main() {
    log.SetFlags(log.Lshortfile|log.LstdFlags)
    log.SetOutput(os.Stdout)
    //限制cpu使用数
    runtime.GOMAXPROCS(1)  
    //开启锁调用跟踪
    runtime.SetMutexProfileFracton(1) 
     //开启阻塞调用跟踪
    runtime.SetBlockProfileRate(1) 
    go func() {
        // 启动 http server
        if err := http.ListenAndServe(":6060", nil); err != nil{
            log.Fatal(err)
        }
        os.Exit(0)
    }()
    //...
}

浏览器查看指标

pprof01.png

3.pprof采样过程和原理

​ 对于CPU,要采样的是函数调用和它们占用的时间,采样率100次/秒,采样时间从手动启动到手动结束。开始采样由设定信号处理再到开启定时器,停止采样由取消信号设定函数再到关闭定时器。

操作系统每10ms向进程发送一次SIGPROF信号;进程每次接收到SIGPROF会记录调用堆栈;写缓冲每100ms读取已经记录的调用栈并写入输出流。

对于Heap堆内存,它的采样则是由内存分配器在堆上分配和释放的内存,记录分配/释放的大小和数量。采样率是每分配512KB记录一次,可在运行开头修改,1为每次分配均记录。采样时间从程序运行开始到采样时。

Goroutine协程记录所有用户发起且在运行中的协程,并非刚开始运行时,runtime中main 的调用栈信息。ThreadCreate线程来记录程序创建的所有系统线程的信息。

Block阻塞的采样率阻塞耗时超过闯值的才会被记录,1为每次阻塞均记录。Mutex锁会产生竞争,采样争抢锁的次数和耗时。采样率只记录固定比例的锁操作,1为每次加锁均记录。

4.性能调优案例

对实际业务服务性能优化的案例,对逻辑相对复杂的程序如何进行性能调优。服务能单独部署,承载一定功能的程序。依赖Service A的功能实现依赖Service B 的响应结果,称为 Service A依赖 Service B。调用链路能支持一个接口请求的相关服务集合及其相互之间的依赖关系。基础库公共的工具包、中间件。

性能调优流程首先建立服务性能评估手段,由于 benchmark 无法满足复杂逻辑分析,还需结合不同负载情况下性能表现差异。接着分析性能数据,定位性能瓶颈,重点优化项改造,要注意不同请求参数覆盖逻辑不同,线上真实流量情况。最后对优化效果验证。

三.总结

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