Go语言性能优化实战|青训营

68 阅读4分钟

一、性能优化工具-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… 

package main

import (
	"log"
	"net/http"
	_ "net/http/pprof"// 自动注册pprof的handler到http server
	"os"
	"runtime"
	"time"
	"github.com/wolfogre/go-pprof-practice/animal"
)

func main() {
	log.SetFlags(log.Lshortfile | log.LstdFlags)
	log.SetOutput(os.Stdout)

	runtime.GOMAXPROCS(1)//限制 CPU 使用数
	runtime.SetMutexProfileFraction(1)//开启锁调用跟踪
	runtime.SetBlockProfileRate(1)// 开启阻塞调用跟踪

	go func() {
		//启动http server
		if err := http.ListenAndServe(":6060", nil); err != nil {
			log.Fatal(err)
		}
		os.Exit(0)
	}()

	for {
		for _, v := range animal.AllAnimals {
			v.Live()
		}
		time.Sleep(time.Second)
	}
}

打开浏览器,输入地址 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

​编辑

 ​编辑