prof

package
v1.4.42 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jul 21, 2026 License: MIT Imports: 14 Imported by: 0

README

prof

封装官方 net/http/pprof 的 HTTP 路由注册和运行时 profiling 采样能力,提供大厂标准化的性能分析工具集。


功能特性

  • HTTP 实时分析:将 pprof 路由注册到 http.ServeMux,支持鉴权中间件保护生产环境
  • 信号触发采样:通过系统信号动态开关采样,按需采集 profile 文件,不影响正常服务性能
  • IO 等待时间分析:集成 fgprof,额外采集 IO 等待时间,适合 IO 密集型服务
  • 丰富 profile 类型:CPU、Memory、Goroutine、Block、Mutex、ThreadCreate、Trace
  • Options 模式配置:采样时长、输出目录、trace 开关、错误处理均可定制


一、HTTP 方式实时分析

1.1 基础用法

将 pprof 路由注册到标准 http.ServeMux,通过浏览器或 go tool pprof 实时查看。

package main

import (
    "net/http"
    "time"

    "github.com/18721889353/sunshine/pkg/prof"
)

func main() {
    mux := http.NewServeMux()
    prof.Register(mux)

    // 访问 http://localhost:8080/debug/pprof/ 即可查看
    httpServer := &http.Server{
        Addr:    ":8080",
        Handler: mux,
    }

    if err := httpServer.ListenAndServe(); err != nil && err != http.ErrServerClosed {
        panic(err)
    }
}

1.2 自定义路由前缀
prof.Register(mux, prof.WithPrefix("/my-pprof"))

// 访问 http://localhost:8080/my-pprof/ 查看 pprof 首页
// 访问 http://localhost:8080/my-pprof/heap 查看堆内存

1.3 启用 IO 等待时间分析

开启 fgprof 支持,采集标准 pprof 不包含的 IO 等待时间,适合分析 IO 密集型服务(如网络、磁盘操作频繁的应用)。

prof.Register(mux,
    prof.WithPrefix("/debug/pprof"),
    prof.WithIOWaitTime(),
)

// 额外增加 /debug/pprof/profile-io 路由
// 使用: go tool pprof -http=:8081 http://localhost:8080/debug/pprof/profile-io

1.4 生产环境鉴权保护

pprof 可能暴露敏感信息(源码路径、goroutine 堆栈、环境变量等),生产环境务必添加鉴权。

package main

import (
    "net/http"

    "github.com/18721889353/sunshine/pkg/prof"
)

// simpleTokenAuth 简单的 Token 鉴权中间件
func simpleTokenAuth(next http.Handler) http.Handler {
    return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
        if r.Header.Get("X-Auth-Token") != "my-secret-token" {
            http.Error(w, "Forbidden", http.StatusForbidden)
            return
        }
        next.ServeHTTP(w, r)
    })
}

func main() {
    mux := http.NewServeMux()
    prof.Register(mux,
        prof.WithPrefix("/debug/pprof"),
        prof.WithIOWaitTime(),
        prof.WithAuth(simpleTokenAuth),
    )

    http.ListenAndServe(":8080", mux)
}

// 使用方式:
//   curl -H "X-Auth-Token: my-secret-token" http://localhost:8080/debug/pprof/heap

1.5 结合 go tool pprof 分析
# 查看堆内存(交互式)
go tool pprof http://localhost:8080/debug/pprof/heap

# 查看 CPU 使用(采样 30 秒)
go tool pprof http://localhost:8080/debug/pprof/profile

# 查看协程堆栈
go tool pprof http://localhost:8080/debug/pprof/goroutine

# 查看互斥锁
go tool pprof http://localhost:8080/debug/pprof/mutex

# 查看阻塞
go tool pprof http://localhost:8080/debug/pprof/block

# 查看内存分配(含历史)
go tool pprof http://localhost:8080/debug/pprof/allocs

# Web 界面分析
go tool pprof -http=:8081 http://localhost:8080/debug/pprof/heap


二、信号触发离线采样

适用于生产环境:平时不采样,通过发送系统信号按需开启,采样完成后自动保存文件到磁盘。

2.1 基础用法(默认配置)
package main

import (
    "os"
    "os/signal"
    "syscall"

    "github.com/18721889353/sunshine/pkg/prof"
)

func main() {
    p := prof.NewProfile()

    signals := make(chan os.Signal, 1)
    signal.Notify(signals, syscall.SIGINT, syscall.SIGTERM, syscall.SIGHUP, syscall.SIGTRAP)

    for {
        v := <-signals
        switch v {
        case syscall.SIGTRAP:
            // 开关式:第一次开始采样,第二次停止采样
            p.StartOrStop()

        case syscall.SIGINT, syscall.SIGTERM, syscall.SIGHUP:
            // 清理 profile 文件后退出
            p.Cleanup()
            os.Exit(0)
        }
    }
}
# 查看服务 PID
ps aux | grep 服务名称

# 发送 SIGTRAP 信号开启采样(默认采样 60 秒)
kill -TRAP <pid>

# 再次发送 SIGTRAP 信号可提前停止采样
kill -TRAP <pid>

# 采样文件保存到 /tmp/<服务名>_profile/ 目录
# ls /tmp/<服务名>_profile/
# 20260721T150405_12345_服务名_cpu.out
# 20260721T150405_12345_服务名_mem.out
# 20260721T150405_12345_服务名_goroutine.out

2.2 自定义采样配置

通过 ProfileOption 定制采样时长、输出目录、trace 开关、错误处理等。

package main

import (
    "log"
    "os"
    "os/signal"
    "path/filepath"
    "syscall"

    "github.com/18721889353/sunshine/pkg/prof"
)

func main() {
    // 自定义输出目录
    outputDir := filepath.Join("/data", "profiles")

    p := prof.NewProfile(
        prof.WithProfileDuration(30),            // 采样时长 30 秒(默认 60 秒)
        prof.WithProfileTrace(true),              // 启用 trace 采样(默认关闭)
        prof.WithProfileOutputDir(outputDir),     // 输出到 /data/profiles/
        prof.WithProfileErrorHandler(func(err error) {
            log.Printf("[profile] 采样错误: %v", err)
        }),
    )

    signals := make(chan os.Signal, 1)
    signal.Notify(signals, syscall.SIGINT, syscall.SIGTERM, syscall.SIGHUP, syscall.SIGTRAP)

    for {
        v := <-signals
        switch v {
        case syscall.SIGTRAP:
            p.StartOrStop()
            // 停止后可立即获取文件列表进行分析
            for _, f := range p.Files() {
                log.Printf("profile 文件: %s", f)
            }

        case syscall.SIGINT, syscall.SIGTERM, syscall.SIGHUP:
            p.Cleanup() // 退出时清理 profile 文件
            os.Exit(0)
        }
    }
}

2.3 采集文件管理与清理

Files() 返回只读文件列表,Cleanup() 清理磁盘文件。

p := prof.NewProfile(prof.WithProfileDuration(10))

// 开始采样
p.StartOrStop()
time.Sleep(5 * time.Second)
// 手动停止
p.StartOrStop()

// 获取生成的文件列表(只读副本,不影响内部状态)
files := p.Files()
for _, f := range files {
    fmt.Printf("采样文件: %s\n", f)
}

// 分析完成后清理文件
p.Cleanup()
// 此时 Files() 返回空列表,磁盘文件已删除

2.4 定时自动采样

结合 cron 定时任务,定期采集 profile 用于性能基线对比。

package main

import (
    "log"
    "time"

    "github.com/18721889353/sunshine/pkg/prof"
)

func collectProfile() {
    p := prof.NewProfile(
        prof.WithProfileDuration(10),
        prof.WithProfileOutputDir("/tmp/periodic_profiles"),
    )

    p.StartOrStop()
    // 等待采样完成(或者手动停止)
    time.Sleep(12 * time.Second)

    log.Printf("采集完成,文件: %v", p.Files())
    // 可在此上传文件到对象存储等
    // p.Cleanup() // 根据需要决定是否清理
}

func main() {
    // 每小时的 05 分钟采集一次
    for {
        now := time.Now()
        next := time.Date(now.Year(), now.Month(), now.Day(), now.Hour(), 5, 0, 0, now.Location())
        if next.Before(now) {
            next = next.Add(time.Hour)
        }
        time.Sleep(time.Until(next))
        collectProfile()
    }
}


三、框架集成(Sunshine 微服务框架)

prof 包已深度集成到 Sunshine 框架中,使用 sunshine CLI 工具创建的项目默认支持性能分析。 HTTP 服务通过 pkg/gin/prof 注册 pprof 路由,gRPC 服务通过 pkg/prof 将 pprof 挂载到内置 HTTP mux。

3.1 YAML 配置驱动

通过 configs/serverNameExample.yml 中的 enableHTTPProfile 控制是否启用 pprof 路由:

app:
  enableHTTPProfile: true    # 是否开启性能分析, true:开启, false:关闭
  enableStat: false          # 是否开启资源统计(用于自适应采集)

[!tip] http.timeout 若设置了非零值,需确保大于采样时长(如设为 0> 60), 否则 Gin 超时中间件可能在采样完成前中断请求。


3.2 HTTP 服务集成(Gin 引擎)

internal/routers/routers.goNewRouter() 中,通过 pkg/gin/prof 包将 pprof 路由注册到 Gin 引擎:

import "github.com/18721889353/sunshine/pkg/gin/prof"

func NewRouter() *gin.Engine {
    r := gin.New()
    // ... 中间件链 ...

    // profile performance analysis
    if cfg.App.EnableHTTPProfile {
        prof.Register(r, prof.WithIOWaitTime())
    }

    // ... 业务路由 ...
    return r
}

注册后的访问地址:

  • HTTP 服务http://localhost:8001/debug/pprof/(端口由 http.port 配置)
  • PB 路由模式http://localhost:8001/debug/pprof/(通过 NewRouter_pbExample()

3.3 gRPC 服务集成

gRPC 服务内置独立的 HTTP mux 用于暴露 pprof 和指标接口(端口由 grpc.httpPort 配置):

import "github.com/18721889353/sunshine/pkg/prof"

func (s *grpcServer) registerProfMux() {
    if s.mux == nil {
        s.mux = http.NewServeMux()
    }
    prof.Register(s.mux, prof.WithIOWaitTime())
}

func NewGRPCServer(addr string, opts ...GrpcOption) app.IServer {
    // ...
    s.addHTTPRouter()               // 注册错误码、配置等路由
    if config.Get().App.EnableHTTPProfile {
        s.registerProfMux()         // 注册 pprof 路由
    }
    // ...
}

访问地址:http://localhost:6001/debug/pprof/(端口由 grpc.httpPort 配置,默认 6001)

[!note] gRPC 与 HTTP 混合服务架构中,pprof 统一由 gRPC 端在独立端口暴露,HTTP 端不重复注册。


3.4 自适应采集集成

Sunshine 框架的 internal/stat 包会定期采集 CPU 和内存使用率,当满足告警条件时自动触发 prof 采样:

app:
  enableStat: true           # 启用资源统计(自适应采集的前提)
  enableHTTPProfile: true    # 启用 pprof 路由

告警阈值(默认):

  • CPU 使用率连续 3 次(每分钟一次)平均超过 80%
  • 物理内存使用率连续 3 次(每分钟一次)平均超过 80%
  • 持续超过阈值后默认间隔 15 分钟再次告警

触发告警时,框架内部调用 kill -TRAP <pid> 采集 profile,文件保存到 /tmp/<服务名>_profile/。 即使半夜发生资源异常,第二天仍可通过分析 profile 文件定位根因。

[!warning] 自适应采集在 Windows 环境不受支持。


3.5 代码生成模板自动集成

使用 sunshine CLI 创建新服务时,prof 集成代码由模板自动生成:

# 创建 HTTP 服务(自动集成 pprof)
sunshine new http-serverNameExample

# 创建 gRPC + HTTP 混合服务(自动集成 pprof 到 gRPC 端)
sunshine new grpc-http-serverNameExample

生成的服务代码中:

  • internal/routers/routers.go → 通过 pkg/gin/prof 注册 Gin 路由
  • internal/server/grpc.go → 通过 pkg/prof 注册 mux 路由
  • configs/serverNameExample.yml → 自动包含 enableHTTPProfile: true

开发者只需确保 YAML 中 enableHTTPProfile: true,无需手动编写任何 prof 相关代码。


四、离线文件分析

获得 profile 离线文件后,使用 pprof 工具分析:

# 交互式分析
go tool pprof /tmp/myapp_profile/20260721T150405_12345_myapp_cpu.out

# Web 界面分析
go tool pprof -http=:8081 /tmp/myapp_profile/20260721T150405_12345_myapp_mem.out

# 对比两次采样(如升级前后的内存变化)
go tool pprof -http=:8081 \
    --base /tmp/myapp_profile/20260721T150405_12345_myapp_mem_baseline.out \
    /tmp/myapp_profile/20260721T150405_12345_myapp_mem.out


五、API 参考

HTTP 注册
函数/选项 说明
Register(mux, opts...) 将 pprof 路由注册到 http.ServeMux
WithPrefix(prefix) 自定义路由前缀,默认 /debug/pprof
WithIOWaitTime() 启用 fgprof IO 等待时间分析
WithAuth(authFn) 添加鉴权中间件保护生产环境
信号采样
函数/选项 说明
NewProfile(opts...) 创建 Profile 采样器
StartOrStop() 开关式启动/停止采样
Files() 获取本次采样生成的文件列表(只读)
Cleanup() 删除本次采样产生的所有文件
WithProfileDuration(sec) 设置采样时长,默认 60 秒
WithProfileTrace(enabled) 启用/禁用 trace 采样
WithProfileOutputDir(dir) 设置输出目录
WithProfileErrorHandler(fn) 设置错误处理回调

六、路由一览

以默认前缀 /debug/pprof 为例:

路径 说明 采样时长
/debug/pprof/ pprof 首页 -
/debug/pprof/cmdline 命令行参数 -
/debug/pprof/profile CPU profile 30 秒
/debug/pprof/profile-io IO 等待时间 WithIOWaitTime
/debug/pprof/symbol 符号查询 -
/debug/pprof/trace 执行轨迹 1 秒
/debug/pprof/allocs 内存分配(历史) 即时
/debug/pprof/heap 堆内存 即时
/debug/pprof/goroutine 协程堆栈 即时
/debug/pprof/threadcreate 线程创建 即时
/debug/pprof/block 阻塞分析 即时
/debug/pprof/mutex 互斥锁 即时

Documentation

Overview

Package prof 封装官方 net/http/pprof 路由和运行时 profiling 采样能力,提供大厂标准化的性能分析工具集。

功能特性

  1. HTTP 实时分析:将 pprof 路由注册到 http.ServeMux 或 Gin 引擎, 通过浏览器或 go tool pprof 实时查看 CPU、内存、协程等 profile 数据。 支持可选鉴权中间件保护生产环境安全。

  2. 信号触发采样:通过 NewProfile() 创建采样器,结合系统信号(SIGTRAP)开关 采样。适合生产环境按需采集,不影响正常服务性能。

  3. 自适应采集:结合资源监控告警,在 CPU/内存超阈值时自动触发 profile 采样, 便于问题事后追溯。

采集类型

  • CPU:CPU 使用率 profiling,分析热点函数
  • Memory:堆内存分配,定位内存泄漏
  • Goroutine:所有 goroutine 堆栈,排查协程泄漏
  • Block:同步原语阻塞,分析锁竞争
  • Mutex:互斥锁持有者,排查死锁
  • ThreadCreate:线程创建,分析线程爆炸
  • Trace:运行时 trace(可选),分析调度和 GC

使用方式

HTTP 方式:

mux := http.NewServeMux()
prof.Register(mux, prof.WithIOWaitTime())

信号触发方式:

p := prof.NewProfile(prof.WithProfileDuration(30))
// 收到 SIGTRAP 时调用 p.StartOrStop()

安全提示

pprof 可能暴露敏感信息(源码路径、goroutine 堆栈等), 生产环境建议:

  • 通过 WithAuth() 添加鉴权中间件
  • 仅在内部网络暴露 pprof 端口
  • 结合 K8S 网络安全策略限制访问

Index

Constants

View Source
const (
	// DefaultDuration 默认采样时长(秒)
	DefaultDuration = 60
	// DefaultOutputDirSuffix 默认输出目录名格式(追加到系统临时目录后)
	DefaultOutputDirSuffix = "_profile"
	// TimeFormat 采样文件时间戳格式
	TimeFormat = "20060102T150405"
)
View Source
const (
	// DefaultPrefix 默认 pprof 路由前缀
	DefaultPrefix = "/debug/pprof"
)

Variables

This section is empty.

Functions

func EnableTrace

func EnableTrace()

EnableTrace 启用包级默认 trace 采样。 此函数影响全局默认值,仅对后续 NewProfile() 调用有效。 推荐使用 WithProfileTrace(true) 替代。

func Register

func Register(mux *http.ServeMux, opts ...HTTPOption)

Register 将 pprof 路由注册到标准 http.ServeMux 中。

注册的路由(以默认前缀 /debug/pprof 为例):

  • /debug/pprof/ - pprof 首页
  • /debug/pprof/cmdline - 命令行参数
  • /debug/pprof/profile - CPU profile(30 秒采样)
  • /debug/pprof/symbol - 符号查询
  • /debug/pprof/trace - 执行轨迹
  • /debug/pprof/allocs - 内存分配
  • /debug/pprof/block - 阻塞分析
  • /debug/pprof/goroutine - 协程堆栈
  • /debug/pprof/heap - 堆内存
  • /debug/pprof/mutex - 互斥锁
  • /debug/pprof/threadcreate - 线程创建
  • /debug/pprof/profile-io - IO 等待时间(需 WithIOWaitTime)

如果设置了 WithAuth,所有 pprof 路由都将经过鉴权中间件检查。

func SetDurationSecond

func SetDurationSecond(d uint32)

SetDurationSecond 设置包级默认采样时长(秒)。 此函数影响全局默认值,仅对后续 NewProfile() 调用有效。 推荐使用 WithProfileDuration() 替代。

Types

type HTTPOption added in v1.4.42

type HTTPOption func(o *httpOptions)

HTTPOption 定义 HTTP pprof 注册的配置选项函数

func WithAuth added in v1.4.42

func WithAuth(authFn func(http.Handler) http.Handler) HTTPOption

WithAuth 设置 pprof 路由的鉴权中间件。 在生成环境中,pprof 可能暴露敏感信息(如源码路径、goroutine 堆栈等), 建议通过此选项添加鉴权保护。

示例:

// 简单 Token 鉴权
auth := func(next http.Handler) http.Handler {
    return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
        if r.Header.Get("X-Auth-Token") != "my-secret-token" {
            http.Error(w, "Forbidden", http.StatusForbidden)
            return
        }
        next.ServeHTTP(w, r)
    })
}
prof.Register(mux, prof.WithAuth(auth))

func WithIOWaitTime

func WithIOWaitTime() HTTPOption

WithIOWaitTime 启用 IO 等待时间 profile 分析。 开启后在 {prefix}/profile-io 路由提供 fgprof 分析, 它比标准 pprof 多包含 IO 等待时间,更适合分析 IO 密集型服务。

func WithPrefix

func WithPrefix(prefix string) HTTPOption

WithPrefix 设置 pprof 路由前缀。 如果 prefix 为空字符串,则使用默认前缀 /debug/pprof。

type Profile added in v1.4.27

type Profile struct {
	// contains filtered or unexported fields
}

Profile 表示一次 profiling 采样会话。 每次 StartOrStop() 调用会开启或停止采样,采样文件保存至输出目录。

func NewProfile

func NewProfile(opts ...ProfileOption) *Profile

NewProfile 创建一个新的 Profile 采样器。 支持通过 ProfileOption 配置采样时长、trace 开关、输出目录等。

示例:

p := NewProfile(
    WithProfileDuration(30),
    WithProfileTrace(true),
    WithProfileOutputDir("/tmp/myapp_profile"),
    WithProfileErrorHandler(func(err error) {
        log.Printf("profile error: %v", err)
    }),
)

func (*Profile) Cleanup added in v1.4.42

func (p *Profile) Cleanup()

Cleanup 删除本次采样产生的所有 profile 文件。 通常在分析完成文件后调用。

func (*Profile) Files added in v1.4.42

func (p *Profile) Files() []string

Files 返回本次采样产生的所有文件路径列表。

func (*Profile) StartOrStop added in v1.4.27

func (p *Profile) StartOrStop()

StartOrStop 开关式启动/停止采样。

  • 第一次调用:启动采样(如果当前状态为停止)
  • 第二次调用:停止采样(如果当前状态为启动)

启动后,若在 durationSec 内未收到停止信号,自动停止采样。

type ProfileOption added in v1.4.42

type ProfileOption func(p *profileOptions)

ProfileOption 定义 Profile 的配置选项函数

func WithProfileDuration added in v1.4.42

func WithProfileDuration(sec uint32) ProfileOption

WithProfileDuration 设置采样持续时间(秒),默认 60 秒。 如果设置为 0,使用默认值。

func WithProfileErrorHandler added in v1.4.42

func WithProfileErrorHandler(fn func(error)) ProfileOption

WithProfileErrorHandler 设置采样过程中错误处理回调函数。 默认为 fmt.Println 输出到标准输出。

func WithProfileOutputDir added in v1.4.42

func WithProfileOutputDir(dir string) ProfileOption

WithProfileOutputDir 设置采样文件输出目录,默认在系统临时目录下。

func WithProfileTrace added in v1.4.42

func WithProfileTrace(enabled bool) ProfileOption

WithProfileTrace 启用或禁用 trace 采样,默认禁用。

type ProfileType added in v1.4.42

type ProfileType int

ProfileType 类型别名,用于 iota 常量定义

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL