• go pprof 实战


    为什么要进行性能优化

    哪些情况需要进行性能优化

    其实关于性能优化的主题,网上已经讨论很多次,这里谈一下我的理解,那么其实核心就是 2 个点:

    • 服务一直高负载,业务增长需要经常扩容
    • 架构不能满足业务发展,需要重构,与此同时需要进行服务的压测&性能优化

    性能优化的一般步骤

    • 准备阶段:发现系统性能问题,明确优化方向
    • 分析阶段:通过各种工具和手段,初步定为瓶颈点
    • 调优阶段:根据定位到的瓶颈点,进行性能调优
    • 测试阶段:实际验证调优效果,如果不能满足期望要求,那么可能需要重复 2-3 步骤(如果还不行可能是架构设计存在问题)

    linux 常见的性能问题排查工具

    linux 程序常用的调试工具:

    vmstat、iostat、 mpstat、netstat、 sar 、top:查看系统、程序信息等

    gprof、perf、perf top:定位到具体函数、调用等

    strace、ltrace:系统调用、函数调用、库函数调用等

    pstack、ptree、pmap:堆栈信息

    dmesg:系统 log 信息

    对于 go 程序,如果遇到高负载等性能问题推荐使用:perf top、pprof 快速定位问题。

    perf top

    当前系统的 uptime:load average 2.50 左右,以下 perf top 信息中出现_raw_spin_unlock_irqrestore 表示系统可能比较“闲’‘,以及有较多的软中断(服务交互)。unknown 则是没有加载符号文件,所以没有显示函数名,vdso 很可能 time 相关系统调用。

    runtime.scanobject、mallocgc 说明可能有较多小对象申请等等。

    go 程序性能问题梳理

    1. 内存泄露
    2. 内存大量申请释放
    3. 协程泄露
    4. 协程数量异常
    5. 对象数量异常
    6. 反射使用(gc、内存问题)
    7. 定时器使用导致的内存泄露
    8. 以及业务逻辑上的问题
    9. ...

    pprof 分析程序性能问题

    pprof 如何收集程序信息

    on cpu 类型的 pprof 收集原理:注册 settimer 系统调用回调,1 秒触发 100 次回调,然后遍历每个线程的堆栈信息并保存生成 prof 文件。(off cpu 则是 IO 较大的程序)

    程序中如下使用,注册 pprof 监听的端口即可。

    1. import _ "net/http/pprof"
    2. gofunc() {
    3. http.ListenAndServe("0.0.0.0:8080", nil)
    4. }()

    pprof.go 文件的 init 在 DefaultServeMux 默认路由上注册了多个 handle,分别用来收集 cpu、内存等信息

    1. pprof.go
    2. func init() {
    3. http.HandleFunc("/debug/pprof/", Index)
    4. http.HandleFunc("/debug/pprof/cmdline", Cmdline)
    5. http.HandleFunc("/debug/pprof/profile", Profile)
    6. http.HandleFunc("/debug/pprof/symbol", Symbol)
    7. http.HandleFunc("/debug/pprof/trace", Trace)
    8. }

    对应的 handle,定期以固定 hz 频率收集程序信息到 profileBuilder 对象中。最终在收集完成返回收集的数据信息,最终 web 页面展示出来。

    1. type profileBuilder struct {
    2. start time.Time
    3. end time.Time
    4. havePeriod bool
    5. period int64
    6. m profMap
    7. // encoding state
    8. w io.Writer
    9. zw *gzip.Writer
    10. pb protobuf
    11. strings []string
    12. stringMap map[string]int
    13. locs map[uintptr]locInfo
    14. funcs map[string]int
    15. mem []memMap
    16. deck pcDeck
    17. }
    18. // and
    19. runtime.MemProfileRecord // goroutine堆栈信息
    20. runtime.MemStats // 内存数据统计信息

    pprof 查看程序信息

    我们可以使用下面多种方式查看程序的内存、cpu、锁等信息。

    1. // Then use the pprof tool to look at the heap profile:
    2. //
    3. // go tool pprof http://localhost:6060/debug/pprof/heap
    4. //
    5. // Or to look at a 30-second CPU profile:
    6. //
    7. // go tool pprof http://localhost:6060/debug/pprof/profile?seconds=30
    8. //
    9. // Or to look at the goroutine blocking profile, after calling
    10. // runtime.SetBlockProfileRate in your program:
    11. //
    12. // go tool pprof http://localhost:6060/debug/pprof/block
    13. //
    14. // Or to look at the holders of contended mutexes, after calling
    15. // runtime.SetMutexProfileFraction in your program:
    16. //
    17. // go tool pprof http://localhost:6060/debug/pprof/mutex
    18. //
    19. // The package also exports a handler that serves execution trace data
    20. // for the "go tool trace" command. To collect a 5-second execution trace:
    21. //
    22. // wget -O trace.out http://localhost:6060/debug/pprof/trace?seconds=5
    23. // go tool trace trace.out
    24. //
    25. // To view all available profiles, open http://localhost:6060/debug/pprof/
    26. // in your browser.
    27. //
    28. // For a study of the facility in action, visit
    29. //
    30. // https://blog.golang.org/2011/06/profiling-go-programs.html

    简单的示例,查看 goroutine 的堆栈、程序的内存信息、gc 次数等。

    1. go tool pprof http://localhost:6060/debug/pprof/heap?debug=1
    2. // runtime.MemProfileRecord
    3. heap profile: 71: 35532256 [15150: 492894072] @ heap/1048576
    4. 1: 31203328 [1: 31203328] @ 0xc2c83a 0x49ed0a 0x49ecd7 0x49ecd7 0x49ecd7 0x491985 0x4c79c1
    5. # 0xc2c839 git.code.oa.com/tmemesh.io/sidecar.init+0x39 git.code.oa.com/tmemesh.io/sidecar@v0.0.27/report.go:14
    6. # 0x49ed09 runtime.doInit+0x89 /usr/local/go/src/runtime/proc.go:5646
    7. # 0x49ecd6 runtime.doInit+0x56 /usr/local/go/src/runtime/proc.go:5641
    8. # 0x49ecd6 runtime.doInit+0x56 /usr/local/go/src/runtime/proc.go:5641
    9. # 0x49ecd6 runtime.doInit+0x56 /usr/local/go/src/runtime/proc.go:5641
    10. # 0x491984 runtime.main+0x1c4 /usr/local/go/src/runtime/proc.go:191
    11. // runtime.MemStats
    12. # runtime.MemStats
    13. # Alloc = 83374072
    14. # TotalAlloc = 8261199880
    15. # Sys = 216980496
    16. # Lookups = 0
    17. # Mallocs = 102656515
    18. # Frees = 102139727
    19. # HeapAlloc = 83374072
    20. # HeapSys = 199491584
    21. # HeapIdle = 94797824
    22. # HeapInuse = 104693760
    23. ...
    24. # NextGC = 163876768
    25. # LastGC = 1618924964269456488
    26. # NumGC = 333
    27. # NumForcedGC = 0
    28. # GCCPUFraction = 0.00011171208329868897
    29. # DebugGC = false
    30. # MaxRSS = 130633728

    投放服务【测试环境压测】

    投放服务的主要工作就是给用户投放合适的内容(主播、会员广告)

    这里压测 srf 服务可以使用 bm_tools 工具,可以很方便的压测 qps 以及查看服务平均延迟等(下面有示例)

     

    资料领取直通车:Golang云原生最新资料+视频学习路线

    Go语言学习地址:Golang DevOps项目实战

  • 相关阅读:
    RxJava/RxAndroid的操作符使用(二)
    什么是探索性测试?探索性测试有哪些方法?
    超详细全面 spring 复习总结笔记
    两个步骤轻松搞定批量合并视频
    1515_人月神话阅读笔记_20年后的人月神话_下篇
    Hive中的数据倾斜优化
    R语言非线性方程数值分析生物降解、植物生长数据:多项式、渐近回归、米氏方程、逻辑曲线、Gompertz、Weibull曲线...
    逐秒追加带序号输入当前时间:fgets fputs sprintf fprintf
    (八)Python类和对象
    AVR128单片机 USART通信控制发光二极管显示
  • 原文地址:https://blog.csdn.net/weixin_52183917/article/details/127886896