性能调优实战介绍 | 青训营笔记

119 阅读4分钟

这是我参与「第五届青训营 」伴学笔记创作活动的第 8 天

本文主要是对于之前学习性能调优实战的介绍以及介绍性能分析工具 pprof。学习性能分析工具可以很好的帮助我们对性能进行针对性调优。本文主要是学习笔记,观看课程可以在掘金课程中找到。

掘金课程

pprof 是一个强大的性能分析工具,可以捕捉到多维度的运行状态的数据,下面简单介绍一下pprof的用法。 golang在语言层面集成了profile采样工具,在程序运行过程中可以获取cpu、heap、block、traces等执行信息,这些会涉及到runtime/pprof、net/http/pprof、runtime/trace等package。

二、性能调优实战

2.1 简介

性能调优原则

  • 要依靠数据不是猜测
  • 要定位最大瓶颈而不是细枝末节
  • 不要过早优化
  • 不要过度优化

2.2 性能分析工具 pprof

说明

  • 希望知道应用在什么地方耗费了多少 CPU、Memory
  • pprof 是用于可视化和分析性能分析数据的工具

接下来会从

  • pprof 功能简介
  • pprof 排查实战
  • pprof 的采样过程和原理

2.2.1 性能分析工具 pprof - 功能简介

image.png

2.2.2 性能分析工具 pprof - 排查实战

搭建 pprof 实践项目

  • GitHub (来自 Wolfogre)
  • github.com/wolfogre/go…
  • 项目提前埋入了一些炸弹代码,产生可观测的性能问题

前置准备

  • 下载项目代码,能够编译运行
  • 注意会占用 1 CPU 核心和超过 1GB 的内存
import {
    "log"
    "net/http"
    "net/http/pprof" // 自动注册 pprof 的 handler 到 http server
    // ...
}

fun main() {
    log.SetFlags(log.Lshortfile | log.LstdFlags)
    log.SetOutput(os.Stdout)
    runtime.GOMAXPROCS(1)  // 限制 CPU 使用数
    runtime.SetMutexProfileFraction(1) // 开启调用跟踪
    runtime.SetBlockProfileRate(1)  // 开启阻塞调用跟踪
 
    go func() {
        // 启动 http server
        if err := http.ListenAndServe(":6060", nil); err!= nil {
            log.Fatal(err)
        }
        os.Exit(0)
    }()
    // ...
}

开启通过浏览器查看指标

在这里插入图片描述

CPU

image.png

  • 命令:topN
  • 查看占用资源最多的函数

在这里插入图片描述

image.png

Flat == Cum,函数中没有调用其他函数 Flat == 0,函数中只有其他函数的调用

  • 命令:list
  • 根据指定的正则表达式查找代码行

image.png

  • 命令:web
  • 调用关系可视化 在这里插入图片描述

Heap-堆内存

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

image.png

  • alloc_objects:程序累计申请的对象数
  • alloc_space:程序累计申请的内存大小
  • inuse_objects:程序当前持有的对象数
  • inuse_space:程序当前占用的内存大小

在这里插入图片描述

goroutine-协程

  • goroutine 泄露也会导致内存泄漏 image.png

在这里插入图片描述

  • 由上到下表示调用顺序
  • 每一块代表一个函数,越长代表占用 CPU 的时间更长
  • 火焰图是动态的,支持点击块进行分析

在这里插入图片描述

  • 支持搜索,在 Source 视图下搜索 wolf

image.png

  • 注释问题代码后的结果 在这里插入图片描述

mutex - 锁

在这里插入图片描述

block - 阻塞

image.png

在这里插入图片描述

  • 两个 Boloc 为什么只展示了一个 image.png
  • 第二个阻塞操作是什么

在这里插入图片描述

小结 在这里插入图片描述

2.2.3 性能分析工具 pprof - 采样过程和原理

CPU

  • 采样对象:函数调用和它们占用的时间

  • 采样率:100次/秒,固定值

  • 采样时间:从手动启动到手动结束 在这里插入图片描述

  • 操作系统

    • 每 10ms 向进程发送一次 SIGPROF 信号
  • 进程

    • 每次接收到 SIGPROF 会记录调用堆栈
  • 写缓冲

    • 每 100ms 读取已经记录的调用栈并写入输出流 在这里插入图片描述

Heap-堆内存

  • 采样程序通过内存分配器在堆上分配和释放的内存,记录分配/释放的大小和数量
  • 采样率:每分配 512KB 记录一次,可在运行开头修改,1 为每次分配均记录
  • 采样时间:从程序运行开始到采样时
  • 采样指标:alloc_space,alloc_objects,inuse_space,inuse_objects
  • 计算方式:inuse = alloc - free

Goroutine - 协程 & ThreadCreate - 线程创建

  • Goroutine
    • 记录所有用户发起且在运行中的 goroutine (即入口非 runtime 开头的)runtime.main 的调用栈信息
  • ThreadCreate
    • 记录程序创建的所有系统线程的信息

在这里插入图片描述

Block - 阻塞 & Mutex - 锁

  • 阻塞操作
    • 采样阻塞操作的次数和耗时
    • 采样率:阻塞耗时超过阈值的才会被记录,1为每次阻塞均记录
    • 在这里插入图片描述
  • 锁竞争
    • 采样争抢锁的次数和耗时
    • 采样率:只记录固定比例的锁操作,1为每次加锁均记录
    • 在这里插入图片描述

小结

  • 掌握常用的 pprof 工具功能
  • 灵活运用 pprof 工具分析解决性能问题
  • 了解 pprof 的采样过程和工作原理