Golang的trace性能分析

一、trace概述

      上一篇是pprof的性能分析通过pprof找到我们服务中的瓶颈点来进行优化。Golang的pprof性能分析

      一般我们使用pprofprofile来分析服务的性能主要是CPU方面的耗时和调用链路等。但是光靠profile是不够的细节方面还是要使用trace分析并发和阻塞事件,goroutine的调度和GC情况。

相比profile通过trace我们能看到什么呢

1、程序运行中的goroutine数量分布
2、GC的频率和Heap的占比
3、goroutine的调度和运行阻塞情况

二、trace的使用方式

代码中trace采集

import (
    "os"
    "runtime/trace"
)

func main() {
    trace.Start(os.Stderr)
    defer trace.Stop()
}

// 生成trace
go run main.go 2> trace.out

通过pprof采集

// trace采样
浏览器下载 http://127.0.0.1:6060/debug/pprof/trace?seconds=20
命令行采样 curl http://127.0.0.1:6060/debug/pprof/trace\?seconds\=20 > trace.out

// 运行采样的trace文件,会自动打开浏览器页面
go tool trace trace.out

三、trace分析细节

trace的web界面

参考Go 大杀器之跟踪剖析 trace

https://eddycjy.gitbook.io/golang/di-9-ke-gong-ju/go-tool-trace

View trace查看跟踪
Goroutine analysisGoroutine 分析
Network blocking profile网络阻塞概况
Synchronization blocking profile同步阻塞概况
Syscall blocking profile系统调用阻塞概况
Scheduler latency profile调度延迟概况
User defined tasks用户自定义任务
User defined regions用户自定义区域
Minimum mutator utilization最低 Mutator 利用率

trace中需要关注的

关注GC的频率

在这里插入图片描述

      GC的频率过大会导致大量的资源用于GC阶段影响程序性能。另外要关注Heap的释放情况Heap经过GC之后不释放那就需要关注内存泄漏问题了。内存泄漏大部分是查看goroutine释放和服务占用内存情况可以参考Golang的pprof性能分析

关注goroutine调度情况

鼠标放着不动w是放大s是缩小。一直放大可以查看具体goroutine的执行细节
在这里插入图片描述

关注goroutine的数量

在这里插入图片描述

理想情况

1、GC次数适中要多或者太小都不行
2、goutinue数量不会突增或者持续增加
3、goroutine的调度密集且有规律

      下面这个就是GC过于频繁的例子。goroutine的调度还是不错的有规律且密集
在这里插入图片描述

四、GC分析

当前服务GC情况

在这里插入图片描述

可以看到GC很频繁。查看监控发现服务内存只用到了几十M.
在这里插入图片描述

这种情况只能手动改动GC的阈值了。

GOGC 变量设置初始垃圾收集目标百分比。当新分配的数据与上次收集后剩余
的实时数据的比率达到此百分比时将触发收集。
默认值为 GOGC=100。

比如上次gc之后剩余10M,那么下次GC的阈值就是10M+10*100% = 20M

设置GOGC

// 调整gc阈值的源码
func readGOGC() int32 {
	p := gogetenv("GOGC")
	if p == "off" {
		return -1
	}
	if n, ok := atoi32(p); ok {
		return n
	}
	return 100
}

设置环境变量GOGC然后查看trace:
在这里插入图片描述

设置GOMEMLIMIT

程序中GOGC设置成3000实际上内存利用率还是很低只有200M,服务给定的资源是4G
在这里插入图片描述

GOMEMLIMIT  设置GC的阈值(go 1.19提供)设置为服务限定资源的一半
GOGC=off : 关闭自动GC。

效果如下
在这里插入图片描述

GC阈值的讨论

参考官方对于GC的详细解释

GC的特点

1、当 GC 在标记和清除阶段之间转换时短暂的 stop-the-world 暂停
2、调度延迟因为在标记阶段GC占用了25%的CPU资源
3、用户 goroutines 协助 GC 响应高分配率
4、当 GC 处于标记阶段时指针写入需要额外的工作并且
5、运行的 goroutines 必须暂停以扫描它们的根。

      过多的GC会占用CPUgoroutine的资源。但是过少的GC会导致每次GCstw时间变长因为要标记和清楚的内存过多。因此GC阈值设置多大也是个选择题。

五、goroutinue分析

参考Golang GC核心要点和度量方法

goroutine概览

      通过放大可以看到goroutine的状态有Dedicated的有Idle的。还有处于mark标记状态的有sweep的。
在这里插入图片描述

      GC的三个主要阶段mark标记、sweep清扫和 scan扫描。好了跟八股文完美对上了。
红框中还有大名鼎鼎的STW

在这里插入图片描述

标记阶段会将大概25%(gcBackgroundUtilization)的P用于标记对象
逐个扫描所有G的堆栈执行三色标记在这个过程中所有新分配的对象
都是黑色被扫描的G会被暂停扫描完成后恢复这部分工作叫
后台标记(gcBgMarkWorker)。
这会降低系统大概25%的吞吐量比如MAXPROCS=6那么GC 
P期望使用率为6*0.25=1.5这150%P会通过专职(Dedicated)/
兼职(Fractional)/懒散(Idle)三种工作模式的Worker共同来完成。

Sync block耗时分析

      从tracegoroutine analysis 点进去查看主要的goroutine列表。
在这里插入图片描述

点进去就可以查看具体的goroutine执行情况。
在这里插入图片描述

点击查看goroutine发现trace如下
在这里插入图片描述

      看起来146210这个goroutine进入了专职Dedicated GC处理工作模式。查看几个Sync block耗时比较长的发现都是在GC的时候goroutine开始处理GC而暂停处理业务等GC结束才会继续执行业务。 在优化过GC之后Sync block耗时大幅度下降。

Scheduler wait耗时分析

大量的Scheduler wait如下
在这里插入图片描述

      关于调度我们都知道GoGMP模型的调度那么P的大小和goroutine的数量都会影响到调度性能。推荐使用uber的自动设置GOMAXPROCS的库。
uber开源的自动设置maxprocs的库
注意 在服务分配的CPU不足1核的情况下使用automaxprocs没什么提升。反而在多核的情况下需要通过这个库来设置最佳的GOMAXPROCS

end

阿里云国内75折 回扣 微信号:monov8
阿里云国际,腾讯云国际,低至75折。AWS 93折 免费开户实名账号 代冲值 优惠多多 微信号:monov8 飞机:@monov6
标签: go