Profiling Golang
Go 内置了性能分析 (Profiling) 工具 pprof,可以采集程序运行中的性能数据,可通过以下两种方式使用:
runtime/pprof: 通过编程方式,自定义采集运行数据,然后保存分析net/http/pprof: 调用runtime/pprof,封装成接口,通过 HTTP Server 的方式对外提供性能数据
性能数据主要包括如下:
goroutine: 运行的 Goroutine 的调用栈分析heap: 活跃对象的内存分配情况allocs: 所有对象的内存分配情况threadcreate: OS 线程创建分析block: 阻塞分析mutex: 互斥锁分析
收集到的数据,可以通过官方 pprof 工具进行分析。
DataKit 可通过主动拉取 (pull) 或被动推送 (push) 的方式来获取这些数据。
push 方式¶
DataKit 配置¶
DataKit 开启 profile 采集器,注册 profile http 服务。
[[inputs.profile]]
## profile Agent endpoints register by version respectively.
## Endpoints can be skipped listen by remove them from the list.
## Default value set as below. DO NOT MODIFY THESE ENDPOINTS if not necessary.
endpoints = ["/profiling/v1/input"]
Go 应用配置¶
集成 dd-trace-go,采集应用性能数据并发送至 DataKit。 代码参考如下:
package main
import (
"log"
"time"
"gopkg.in/DataDog/dd-trace-go.v1/profiler"
)
func main() {
err := profiler.Start(
profiler.WithService("dd-service"),
profiler.WithEnv("dd-env"),
profiler.WithVersion("dd-1.0.0"),
profiler.WithTags("k:1", "k:2"),
profiler.WithAgentAddr("localhost:9529"), // DataKit url
profiler.WithProfileTypes(
profiler.CPUProfile,
profiler.HeapProfile,
// The profiles below are disabled by default to keep overhead
// low, but can be enabled as needed.
// profiler.BlockProfile,
// profiler.MutexProfile,
// profiler.GoroutineProfile,
),
)
if err != nil {
log.Fatal(err)
}
defer profiler.Stop()
// your code here
demo()
}
func demo() {
for {
time.Sleep(100 * time.Millisecond)
go func() {
buf := make([]byte, 100000)
_ = len(buf)
time.Sleep(1 * time.Hour)
}()
}
}
运行该程序后,DDTrace 会定期(默认 1 分钟一次)将数据推送给 DataKit。
生成性能指标¶
DataKit 自 Version-1.39.0 开始支持从 dd-trace-go 的输出中抽取一组 Go 运行时的相关指标,该组指标被置于 profiling_metrics 指标集下,下面列举其中部分指标加以说明:
| Tags & Fields | Description |
|---|---|
language( tag) |
Language of current profile |
host( tag) |
Hostname of current profile |
service( tag) |
Service name of current profile |
env( tag) |
Env settings of current profile |
version( tag) |
Version of current profile |
prof_go_cpu_cores |
Number of CPU cores consumed Unit: core |
prof_go_cpu_cores_gc_overhead |
Number of CPU cores used for garbage collection Unit: core |
prof_go_alloc_bytes_per_sec |
Memory allocation rate per second Unit: byte |
prof_go_frees_per_sec |
Number of objects freed by GC per second Unit: count |
prof_go_heap_growth_bytes_per_sec |
Heap memory growth rate per second Unit: byte |
prof_go_allocs_per_sec |
Memory allocation operations per second Unit: count |
prof_go_alloc_bytes_total |
Total memory allocated during a single profiling period (dd-trace defaults to 60-second collection cycles) Unit: byte |
prof_go_blocked_time |
Total time goroutines were blocked during a single profiling period Unit: nanosecond |
prof_go_mutex_delay_time |
Total time spent waiting for locks during a single profiling period Unit: nanosecond |
prof_go_gcs_per_sec |
Number of GC runs per second Unit: count |
prof_go_max_gc_pause_time |
Maximum single pause duration caused by GC during a profiling period Unit: nanosecond |
prof_go_gc_pause_time |
Total pause time caused by GC during a profiling period Unit: nanosecond |
prof_go_num_goroutine |
Current total number of goroutines Unit: count |
prof_go_lifetime_heap_bytes |
Total memory size occupied by live objects in the heap Unit: byte |
prof_go_lifetime_heap_objects |
Total number of live objects in the heap Unit: count |
Tips
该功能默认开启,如果不需要可以通过修改采集器的配置文件 <DATAKIT_INSTALL_DIR>/conf.d/profile/profile.conf 把其中的配置项 generate_metrics 置为 false 并重启 DataKit.
Pull 方式¶
Go 应用开启 Profiling¶
应用中开启 Profiling 只需要引用 pprof 包即可,参考如下:
package main
import (
"net/http"
_ "net/http/pprof"
)
func main() {
http.ListenAndServe(":6060", nil)
}
运行代码后,可通过 http://localhost:6060/debug/pprof/heap?debug=1 来查看是否开启成功。
- Mutex 和 Block 性能分析
默认情况下,mutex 和 block 性能采集并未开启,如果需要开启,可添加如下代码:
var rate = 1
// enable mutex profiling
runtime.SetMutexProfileFraction(rate)
// enable block profiling
runtime.SetBlockProfileRate(rate)
rate 设置采集频率,即 1/rate 的事件被采集, 如设置为 0 或小于 0 的数值,是不进行采集的。
DataKit 配置¶
开启 Profile 采集器,进行如下设置 [[inputs.profile.go]]。
[[inputs.profile]]
## profile Agent endpoints register by version respectively.
## Endpoints can be skipped listen by remove them from the list.
## Default value set as below. DO NOT MODIFY THESE ENDPOINTS if not necessary.
endpoints = ["/profiling/v1/input"]
## set true to enable election
election = true
## go pprof config
[[inputs.profile.go]]
## pprof url
url = "http://localhost:6060"
## pull interval, should be greater or equal than 10s
interval = "10s"
## service name
service = "go-demo"
## app env
env = "dev"
## app version
version = "0.0.0"
## types to pull
## values: cpu, goroutine, heap, mutex, block
enabled_types = ["cpu","goroutine","heap","mutex","block"]
[inputs.profile.go.tags]
# tag1 = "val1"
Note
如果不需要开启 Profile 的 HTTP 服务,可将 endpoints 字段注释掉。
字段说明¶
url: 上报地址,如http://localhost:6060interval: 采集间隔时间,最小 10sservice: 服务名称env: 应用环境类型version: 应用的版本enabled_types: 性能类型,如cpu, goroutine, heap, mutex, block
配置好 Profile 采集器,启动或重启 DataKit,一段时间后即可在观测云中心查看 Go 的性能数据。