Go高级工程师实战营-深度Go语言大厂真实项目性能优化

发布时间 2023-11-03 15:22:41作者: 天使angl

Go高级工程师实战营-深度Go语言大厂真实项目性能优化

 

一、性能优化工具-pprof

1. 简介

性能调优原则。

  • 要依靠数据不是猜测。
  • 要定位最大瓶颈而不是细枝末节。
  • 不要过早优化。
  • 不要过度优化。

2. 性能分析工具 pprof

熟练使用 pprof 工具排查性能问题并了解其基本原理。

pprof是golang的内置可视化性能分析工具,性能分析工具 pprof 是一个能够帮助用户分析并定位程序运行时性能瓶颈的工具。pprof 能够捕获和分析 CPU 、 Memory 、 Networx 和 Function 的性能信息,这些信息可以用来了解程序的运行状况并进行优化。

以下是 pprof 的详细介绍:

  1. 生成火焰图:pprof 可以生成 SVG 或者 PNG 格式的火焰图。火焰图是一个可视化工具,用于分析性能问题。它将性能数据可视化为水平柱状图,每一个柱子代表一个函数,宽度表示执行的时间,高度表示时间复杂度或调用次数。火焰图可以清晰地展示程序的运行情况,帮助用户快速定位性能瓶颈。
  2. 收集性能数据:pprof 通过向程序中添加代理来收集性能数据。这些代理会捕获程序执行时的性能数据,并将其保存在特定的文件中。然后,用户可以使用 pprof 工具分析这些文件并获得有关程序性能的信息。
  3. 分析数据:pprof 提供了丰富的命令行选项,可以帮助用户分析性能数据。常用的命令包括 topgoroutinemutexheapcallgrind 等。这些命令可以用于分析程序的 CPU 、 Memory 、 Networx 和 Function 的性能。
  4. 可视化界面:pprof 提供了基于 web 的可视化界面,可以帮助用户更方便地分析和展示性能数据。用户可以通过 http://localhost:6060/debug/pprof/ 访问可视化界面。
  5. 自定义性能分析:pprof 提供了丰富的自定义选项,可以帮助用户根据具体需求进行性能分析。例如,用户可以通过 go tool pprof 命令自定义分析程序中的某个函数,或者通过配置文件自定义分析选项。
  6. 社区支持:pprof 有一个活跃的社区,用户可以在社区中寻求帮助,学习新的性能分析技巧,分享自己的经验。

 pprof 是当程序占用资源异常时才需要启用的工具

3.搭建pprof项目

 先要下载图形化依赖安装

Download | Graphviz

通过链接找适合自己操作系统的安装方法

运行该项目会占用1CPU核心和超过1GB的内存。

开源项目地址:github.com/wolfogre/go… 

  1.  
    package main
  2.  
     
  3.  
    import (
  4.  
    "log"
  5.  
    "net/http"
  6.  
    _ "net/http/pprof"// 自动注册pprof的handler到http server
  7.  
    "os"
  8.  
    "runtime"
  9.  
    "time"
  10.  
    "github.com/wolfogre/go-pprof-practice/animal"
  11.  
    )
  12.  
     
  13.  
    func main() {
  14.  
    log.SetFlags(log.Lshortfile | log.LstdFlags)
  15.  
    log.SetOutput(os.Stdout)
  16.  
     
  17.  
    runtime.GOMAXPROCS(1)//限制 CPU 使用数
  18.  
    runtime.SetMutexProfileFraction(1)//开启锁调用跟踪
  19.  
    runtime.SetBlockProfileRate(1)// 开启阻塞调用跟踪
  20.  
     
  21.  
    go func() {
  22.  
    //启动http server
  23.  
    if err := http.ListenAndServe(":6060", nil); err != nil {
  24.  
    log.Fatal(err)
  25.  
    }
  26.  
    os.Exit(0)
  27.  
    }()
  28.  
     
  29.  
    for {
  30.  
    for _, v := range animal.AllAnimals {
  31.  
    v.Live()
  32.  
    }
  33.  
    time.Sleep(time.Second)
  34.  
    }
  35.  
    }

打开浏览器,输入地址 Download | Graphviz 即可,

 4.浏览器查看指标

 

 

 

5.cpu占用过高

打开活动监视器发现cpu占有过高,在终端输入

go tool pprof "http://localhost:6060/debug/pprof/profile?seconds=10"
 

使用 go tool pprof 来采集 10 秒 CPU 数据排查下问题

 

输入

top
 

查看cpu占用高的原因

 

 我们观察到Eat的方法CPU占用过高,,输入

list Eat
 

检查具体在代码哪个位置?

 我们看到具体的代码行为24行的100亿次for循环导致的问题

在终端继续输入

web
 

 生成一个.svg文件,系统默认打开

修改eat函数,问题旁有箭头显示

 

发现问题已修复

 

6.内存占用过高(Heap-堆内存)

我们发现内存使用还是很高

 

输入以下命令可以看到堆内存的占用情况:

go tool pprof -http=:8080 "http://localhost:6060/debug/pprof/heap"
 

 

 

 7、协程(groutine)

goroutine 泄露也会导致内存泄露

我们看到debug页面协程数有106条,虽然不多,但是显然不正常

 

查看堆内存占用情况:

go tool pprof -http=:8080 "http://localhost:6060/debug/pprof/goroutine"
 

 

 

新的:

 

旧的:

我们在火焰图中可以看到 wolf.(*Wolf).Drink.func1 这个函数占了总 goroutine 最多 

我们可以看到Drink 方法每次会起 10 个协程,每个协程会 sleep 30 秒再推出,而 Drink 函数又被反复的调用,这才导致了大量的协程泄漏。 

之后就是的过程就熟悉了

7.Mutex(锁)

接着检查性能问题,首先检查不合理的锁争用问题(加锁太长等等),我们发现有一个 mutex 争用问题:

go tool pprof -http=:8080 http://localhost:6060/debug/pprof/mutex