golang入门笔记——pprof性能分析

2023-09-18 16:39:57

简介

golang性能分析工具pprof的8个指标

1.性能分析的5个方面:CPU、内存、I/O、goroutine(协程使用情况和泄漏检查)、死锁检测以及数据竟态分析

	runtime.SetMutexProfileFraction(1) //开启对锁调用的跟踪 mutex
	runtime.SetBlockProfileRate(1)     //开启对阻塞操作的跟踪

2.两种程序性能指标采集

runtime/pprof:采集工具型应用运行数据进行分析
net/http/pprof:采集服务型应用运行时数据进行分析

pprof开启后,每隔一段时间(10ms)就会收集下当前的堆栈信息,获取各个函数占用的CPU以及内存资源;最后通过对这些采样数据进行分析,形成一个性能分析报告。

3.交互式终端性能分析

不管是工具型应用还是服务型应用,我们使用相应的pprof库获取数据之后,下一步的都要对这些数据进行分析,我们可以使用go tool pprof命令行工具。

go tool pprof [binary] [source]
#binary是应用的二进制文件,用来解析各种符号
#source标识profile数据的来源,可以是本地的文件,也可以是http地址

4.web网页性能分析

如果你的应用程序是一直运行的,比如 web 应用,那么可以使用net/http/pprof库,它能够在提供   HTTP 服务进行分
析。
如果使用了默认的http.DefaultServeMux(通常是代码直接使用 http.ListenAndServe(“0.0.0.0:8000”,  nil)),只需要
在你的web server端代码中按如下方式导入net/http/pprof

如果你使用自定义的 Mux,则需要手动注册一些路由规则:

r.HandleFunc("/debug/pprof/", pprof.Index)
r.HandleFunc("/debug/pprof/cmdline", pprof.Cmdline)
r.HandleFunc("/debug/pprof/profile", pprof.Profile)
r.HandleFunc("/debug/pprof/symbol", pprof.Symbol)
r.HandleFunc("/debug/pprof/trace", pprof.Trace)

如果你使用的是gin框架,那么推荐使用github.com/gin-contrib/pprof,在代码中通过以下命令注册pprof相关路由。

pprof.Register(router)

访问地址:http://host:port/debug/pprof会出现性能分析的网页

这个路径下还有几个子页面:

/debug/pprof/profile:访问这个链接会自动进行 CPU profiling,持续 30s,并生成一个文件供下载
/debug/pprof/heap: Memory Profiling 的路径,访问这个链接会得到一个内存 Profiling 结果的文件
/debug/pprof/block:block Profiling 的路径
/debug/pprof/goroutines:运行的 goroutines 列表,以及调用关系

runtime/pprof的使用

代码:

package main

import (
	"flag"
	"fmt"
	"os"
	"runtime/pprof"
	"time"
)

func logicCode() {
	var c chan int
	for {
		select {
		case v := <-c:
			fmt.Printf("recv from chan, value:%v\n", v)
		default:

		}
	}
}

func main() {
	var isCPUPprof bool
	var isMemPprof bool

	flag.BoolVar(&isCPUPprof, "cpu", false, "turn cpu pprof on")
	flag.BoolVar(&isMemPprof, "mem", false, "turn mem pprof on")
	flag.Parse()

	if isCPUPprof {
		file, err := os.Create("./cpu.pprof")
		if err != nil {
			fmt.Println("create cpu pprof failed,err:", err)
			return
		}
		pprof.StartCPUProfile(file) 
		defer file.Close()
		defer pprof.StopCPUProfile()
	}
	for i := 0; i < 8; i++ {
		go logicCode()
	}
	time.Sleep(20 * time.Second)
	if isMemPprof {
		file, err := os.Create("./mem.pprof")
		if err != nil {
			fmt.Println("create mem pprof failed,err:", err)
			return
		}
		pprof.WriteHeapProfile(file)
		file.Close()
	}
}

命令行交互

使用go工具链里的pprof来进行分析

go tool pprof cpu.pprof
#go tool pprof http://127.0.0.1:8000/debug/pprof/profile

在这里插入图片描述

topN来获取占用CPU前几位的函数:

top3 #获取占用CPU前3位的函数

在这里插入图片描述
flat:当前函数占用CPU的耗时
flat%:当前函数占用CPU耗时占总CPU耗时的百分比
sum%:函数占用CPU的耗时累计百分比
cum:当前函数加上当前函数调用函数占用CPU的总耗时
cum %:当前函数加上当前函数调用函数占用CPU总耗时百分比
最后一列:函数的名称

list 函数名,查看具体的函数分析

list logicCode

在这里插入图片描述
可以看出函数的所有耗时都在 case v:=<-c这条语句的执行中。

网络服务性能分析

package main

import (
	"fmt"
	"net/http"
	_ "net/http/pprof"
	"strings"
)

func main() {
	http.HandleFunc("/hello", func(w http.ResponseWriter, r *http.Request) {
		r.ParseForm()
		fmt.Println(r.Form)
		fmt.Println("path:", r.URL.Path)
		fmt.Println("scheme:", r.URL.Scheme)
		for k, v := range r.Form {
			fmt.Println("key:", k)
			fmt.Println("val:", strings.Join(v, ""))
		}
		w.Write([]byte("hello world"))
	})
	http.ListenAndServe("127.0.0.1:8080", nil)
}

第一种方式:

#分析5s内对应服务的性能
go tool pprof -seconds=5 http://127.0.0.1:8080/debug/pprof/profile 
#go tool pprof -seconds=5 http://127.0.0.1:8080/debug/pprof/heap

第二种方式:

下载原始数据文件到XXX-X.out目录,对于一些需要累计到一些时间才能采集的指标,我们可以使用?seconds=X来设置
curl -o XXX-X.out http://127.0.0.1:8080/debug/pprof/XXX?seconds=X

#获取10s内内存的使用情况
curl -o profile.out http://127.0.0.1:8080/debug/pprof/heap?seconds=10
go tool pprof profile.out

在这里插入图片描述

对gin服务进行性能分析

package main

import (
	"fmt"
	"github.com/gin-contrib/pprof"
	"github.com/gin-gonic/gin"
)

func main() {
	r := gin.Default()
	r.GET("/hello", func(c *gin.Context) {
		var ch chan int
		select {
		case v := <-ch:
			fmt.Println(v)
		default:

		}
	})
	pprof.Register(r)
	r.Run()
}

访问网址:http://localhost:8080/debug/pprof
在这里插入图片描述
3 allocs:表示过去进行过3次内存分配
0 block:表示0个阻塞
0 cmdline:执行的命令行
4 goroutine:创建的goroutine数量
3 heap:3个活动中的对象内存分配情况
0 mutex:当前锁竞争的数量
0 profile:cpu使用情况进行采用,默认采样30s,后面加参数seconds=60来指定时间
5 threadcreate:线程的创建数
0 trace:整个程序的运行过程的跟踪

pprof与性能测试结合

go test命令有两个参数和pprof相关,它们分别指定生成的CPU和Memory profiling保存的文件

-cpuprofile: cpu profiling数据要保存的文件地址
-memprofile:memory profiling数据要保存的文件地址
go test -bench . -cpuprofile=cpu.prof

go test -bench . -memprofile=./mem.prof


go test -bench . -blockprofile=./block.prof

压测工具go-wrk

go-wrk的包的下载

go get github.com/adeven/go-wrk

go-wrk的使用格式

go-wrk [flags] url

常用参数:

-H="User-Agent: go-wrk 0.1 bechmark\nContent-Type: text/html;":'\n'分隔的请求头
-c=100: 使用的最大连接数
-k=true: 是否禁用keep-alives
-i=false: if TLS security checks are disabled
-m="GET": HTTP请求方法
-n=1000: 请求总数
-t=1: 使用的线程数
-b="" HTTP请求体
-s="" 如果指定,它将计算响应中包含搜索到的字符串s的频率
go-wrk -t=8 -c=100 -n=10000 "http://127.0.0.1:8080/api/v1/posts?size=10"

输出结果


==========================BENCHMARK==========================
URL:                            http://127.0.0.1:8080/api/v1/posts?size=10

Used Connections:               100
Used Threads:                   8
Total number of calls:          10000

===========================TIMINGS===========================
Total time passed:              2.74s
Avg time per request:           27.11ms
Requests per second:            3644.53
Median time per request:        26.88ms
99th percentile time:           39.16ms
Slowest time for request:       45.00ms

=============================DATA=============================
Total response body sizes:              340000
Avg response body per request:          34.00 Byte
Transfer rate per second:               123914.11 Byte/s (0.12 MByte/s)
==========================RESPONSES==========================
20X Responses:          10000   (100.00%)
30X Responses:          0       (0.00%)
40X Responses:          0       (0.00%)
50X Responses:          0       (0.00%)
Errors:                 0       (0.00%)
更多推荐

2023/09/15 qt day2

完善登录框点击登录按钮后,判断账号(admin)和密码(123456)是否一致,如果匹配失败,则弹出错误对话框,文本内容"账号密码不匹配,是否重新登录”,给定两个按钮ok和cancel,点击ok后,会清除密码框中的内容,继续进行登录;如果点击cancel按钮,则关闭界面。如果账号和密码匹配,则弹出信息对话框,给出提示信

【总结】javascript中的同步与异步

概念同步模式简单的理解就是后一个任务等待前一个任务的结束才能执行,程序的执行顺序与任务的排列顺序是一致的、同步的;同步任务进入主线程异步模式异步的每一个任务有一个或多个回调函数,前一个任务执行结束后,并不会执行后一个任务,而是执行它的回调函数。而后一个任务不会等待前一个任务结束才执行,所以程序的执行顺序与任务的排列顺序

【Java 基础篇】Java线程异常处理详解

在多线程编程中,异常处理是一个至关重要的方面,它决定了你的多线程应用程序的稳定性和可靠性。在本篇博客中,我们将深入探讨Java中的线程异常处理,包括线程抛出的异常类型、如何捕获和处理异常以及最佳实践。异常类型在多线程应用中,线程可能会抛出不同类型的异常。了解这些异常的类型对于有效的异常处理至关重要。以下是一些常见的线程

C/C++简单计算器 2019年12月电子学会青少年软件编程(C/C++)等级考试一级真题答案解析

目录C/C++简单计算器一、题目要求1、编程实现2、输入输出二、解题思路1、案例分析三、程序代码四、程序说明五、运行结果六、考点分析C/C++简单计算器2019年12月C/C++编程等级考试一级编程题一、题目要求1、编程实现一个最简单的计算器,支持+,-,,/四种运算。仅需考虑输入输出为整数的情况,数据和运算结果不会超

森林防火可视化智能监管与风险预警系统解决方案

一、方案背景森林火灾是世界八大自然灾害之一,具有发生面广、突发性强、破坏性大、危险性高、处置扑救特别困难等特点,严重危及人民生命财产和森林资源安全,甚至引发生态灾难。有效预防和及时控制森林火灾是保护国家生态建设成果、推进生态文明建设的重要措施。监管痛点:1)现有的森林防火监测系统落后,以人工地面巡护、瞭望塔高点巡查为主

Mysql基本命令操作

Mysql基本命令操作一、基本概念1.1、数据库分类1.1.1、关系型数据库(二代数据库)1.1.2、非关系型数据库(三代数据库)1.2、库和表1.3、SQL语句1.3.1、SQL语言分类1.3.2、常用数据类型二、查看数据库2.1、查看mysql版本2.2、查看数据库2.3、查看数据库中包含的表2.4、查看表结构三、

驱动开发 linux内核GPIO子系统、及其新版API的概念和使用,linux内核定时器

1、GPIO子系统概述:每一个芯片厂商生产出芯片后会给linux提供一个当前芯片中gpio外设的驱动,我们只需要调用对应的厂商驱动就可以完成硬件的控制。而linux内核源码中的gpio厂商驱动有很多,linux内核个会对厂商驱动做一些封装,会提供一系列的API,我们在自己编写设备驱动中只需要调用这些API即可访问对应厂

【微服务】六. Nacos配置管理

6.1Nacos实现配置管理配置更改热更新在nacos左侧新建配置管理DataID:就是配置文件名称一般命名规则:服务名称-环境名称.yaml配置内容填写:需要热更新需求的配置配置文件的id:[服务名称]-[profile].[后缀名]分组,默认即可格式,目前支持yaml和properties6.2微服务配置拉取配置获

iOS应用闪退或崩溃的解决方法

iOS应用的闪退(Crash)通常是应用在运行过程中发生了异常或错误,导致应用崩溃的情况。解决iOS应用的闪退问题需要一些工具和方法,以下是一些建议,希望对大家有所帮助。北京木奇移动技术有限公司,专业的软件外包开发公司,欢迎交流合作。1.使用Xcode进行调试:Xcode是苹果官方的开发工具,提供了强大的调试功能。你可

专访西藏药业CEO郭远东:数字化转型核心是驱动业务战略实现丨爱分析访谈

[图片]近日,爱分析联合创始人、首席分析师张扬与西藏药业CEO郭远东进行了一次深度对话,就西藏药业整体数字化规划布局、数字化转型过程中面临的痛点及落地实践展开交流。爱分析将通过对各家医药企业数字化转型的探讨和洞悉,为行业提供更多的借鉴。创始于1999年的西藏药业,已成长为产品涵盖生物制药、现代藏药、中药和化学药领域,业

Jetpack:在数据变化时如何优雅更新Views数据

本文讲的是关于Jetpack的架构组件LiveData,LiveData是Lifecycle-aware组件的一个应用,这意味着LiveData遵守Activity、Fragment和Service等组件的生命周期,在它们生命周期处于活跃状态(CREATED和RESUMED)才进行更新Views。使用LiveData步

热文推荐