简介

最近服务器有个小功能 go 进程 内存占用突然变得很高,正好使用 go pprof 实操进行性能分析排查解决

这是个极小的服务,但是占用内存超过了 100MB,而且本身服务器内存就比较吃紧,因此尝试使用 pprof 进行性能分析,看看能不能优化到 50 MB 以内

关于 pprof 的使用教程,请移步文章:Golang 性能分析神器 pprof 详解与实践(图文教程)

接下来使用 go pprof 进行实操性能分析排查

一、开启 pprof

在项目启动时开启 pprof

导包:_ "net/http/pprof"

启动:http.ListenAndServe(":30552", nil)

参考代码如下

import _ "net/http/pprof"
func StartPprof() {
go func() {
logs.Info(http.ListenAndServe(":30552", nil))
}()
// 查看哪些函数占用内存比较多
// go tool pprof -http=localhost:8081 -seconds=10 http://0.0.0.0:30552/debug/pprof/heap # 内存堆栈分析
// go tool pprof -http=localhost:8081 -seconds=10 http://0.0.0.0:30552/debug/pprof/allocs # 内存分配分析 // 查看哪些函数占用耗时比较多
// go tool pprof -http=localhost:8081 -seconds=60 http://0.0.0.0:30552/debug/pprof/profile # 耗时分析 // go tool pprof -http=localhost:8081 -seconds=60 http://0.0.0.0:30552/debug/pprof/goroutine # 协程分析
// go tool pprof -http=localhost:8081 -seconds=10 http://0.0.0.0:30552/debug/pprof/block # 阻塞分析
// go tool pprof -http=localhost:8081 -seconds=10 http://0.0.0.0:30552/debug/pprof/mutex # 锁分析
}
func main(){
....
StartPprof()
err = router.Run(address)
if err != nil {
panic(err)
}
....
}

二、内存堆栈分析

分析哪些函数一直在占用内存

(一)问题分析

go tool pprof -http=0.0.0.0:8081 http://0.0.0.0:30552/debug/pprof/heap

这里我没有加 -seconds ,表示采样数据为:进程启动以来的总数据, 具体参数的使用:Golang 性能分析神器 pprof 详解与实践(图文教程)

浏览器会自动打开:0.0.0.0:8081/ui

如下图

从图中可以看到:又红又粗的函数有:

  • webdav(*memFile) Write

通过箭头查看上下的调用链接,可以发现 swaggerFiles init 调用了此函数,通过搜索查看代码,分析服务中确实是使用了 gin-swagger,但是这个项目其实没必要

解决:注释掉这块代码

  • embedFS

同样通过箭头查看上下的调用链接,发现有个 base64Captcha 调用,这是因为服务使用了一个第三方的验证码生成的包 github.com/mojocn/base64Captcha

embedFS 很明显是加载了文件,通过查看代码发现确实是加载了 fonts 字体

加载的字体大概有 5.9MB

解决:替换包,或者直接去掉验证码,我这里就选择一些比较轻量级的包做了替换

(二)总结

从火焰图上看,总体的内存堆栈不算太高,不过通过排查可以看到存在一些项目不需要的,但是有占用内存的函数/包,还是可以优化减少内存的占用,

通过以上的代码优化之后,重启并且观察一段时间后,内存确实稳定下降了一些

三、内存分配分析

分析哪些函数一直在分配内存

内存分配比较多比较频繁的函数会导致内存突然飙高,内存分配不同于内存堆栈,内存堆栈是常驻内存,

具体区别请移步文章:Golang 性能分析神器 pprof 详解与实践(图文教程

(一)问题分析

go tool pprof -http=0.0.0.0:8081 http://0.0.0.0:30552/debug/pprof/allocs

浏览器会自动打开:0.0.0.0:8081/ui

如下图

火焰图有点大,只截取了有问题的部分

从图中可以看到:又红又粗的函数有:

  • webdav(*memFile) Write + embedFS

    这里看不出来这两个函数的调用,我们可以切换为 top 视图(左上角菜单 view 中),就可以看到完整文件位置。

    解决:这个在上一步骤【内存堆栈分析】中就已经做了分析处理(注:代码发布后确实已修复)

  • DBUpdateCronTask

    这里很有可能是索引没有生效,导致锁全表了

    解决:通过对 update where 条件进行索引优化即可

  • go.Marshal

    这里用 go 标准库的 json 序列化操作,看起来分配内存也不算太多,不过我们可以优化为第三方包,性能更佳

    解决:全局替换包 encoding/jsongithub.com/json-iterator/go

  • fmt.Sprintf

通过排查代码,发现 FmtContent 中使用 fmt.Sprintf ,并且做了大量字符串的拼接,

解决:字符串拼接优化为使用 :strings.Builder

关于字符串拼接性能请移步文章:Go语言字符串拼接性能对比与最佳实践 - 深度优化指南

(二)总结

从火焰图上看,总体的内存分配不算太高,不过仍然有优化空间

通过以上的代码优化之后,重启并且观察一段时间后,内存成功下降到了 50MB 以内

四、CPU 耗时分析

这里从 top 可以看出其实并没有什么 CPU 飙高的情况,不过既然都优化了,就顺便看看哪些函数在占用吧

(一)问题分析

go tool pprof -http=0.0.0.0:8081 http://0.0.0.0:30552/debug/pprof/profile

从火焰图上没看到什么耗时比较异常的函数

(二)总结

从 top 没看到CPU异常,火焰图也没有异常,如果存在异常,排查和优化的方法和前面内存的步骤是一样的

五、协程分析

分析程序开启的协程情况

(一)问题分析

浏览器直接打开以下命令

http://0.0.0.0:30552/debug/pprof/goroutine?debug=1  # 协程总览
http://0.0.0.0:30552/debug/pprof/goroutine?debug=2 # 协程详情

界面展示说明如下:

从上面界面的数据进行分析

  1. 协程总数量为:27(不算多,但是需要看下每个协程的堆栈情况)

  2. 从 debug=2 的信息中查看每个协程的情况,发现其他都是正常的,有 main、 pprof 、cron、业务等启动的协程

    但是存在一个协程【44】:从堆栈上看,这并不是我服务所需的,通过查看这个堆栈定位到代码的地方,发现之前做链路追踪测试时确实导入这个 go.opentelemetry.io

    但是实际没有任何功能作用

    解决:直接注释掉相关的代码和导包

(二)总结

通过界面先查询协程数量是不是太多,过多可能存在泄漏的情况,再通过 debug=2 界面查看每个协程的执行情况,是否非业务所需但是仍旧执行/阻塞,

然后根据堆栈定位代码,然后优化即可

总结

通过启动 pprof 服务,并且通过 go tool pprof 以及 pprof 内部提供的服务接口对 CPU、内存堆栈、内存分配、协程 等指标进行分析,定位问题函数,优化代码

定位问题函数时,优化后可以先本地做单元测试、压力测试、pprof 测试,具体步骤请查看文章:

go 如何进行 Benchmark 基准测试

Golang 性能分析神器 pprof 详解与实践(图文教程)

原文地址

实操使用 go pprof 对生产环境进行性能分析(问题定位及代码优化)

实操使用 go pprof 对生产环境进行性能分析(问题定位及代码优化)的更多相关文章

  1. JVM(五) 生产环境内存溢出调优

    1.gc配置参数 1.1 控制台打印gc日志 -verbose:gc -XX:+PrintGCDetails -XX:+PrintHeapAtGC(详细的gc信息) 1.2 输出gc日志到指定文件 - ...

  2. HDFS集群PB级数据迁移方案-DistCp生产环境实操篇

    HDFS集群PB级数据迁移方案-DistCp生产环境实操篇 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 用了接近2个星期的时间,终于把公司的需要的大数据组建部署完毕了,当然,在部 ...

  3. 生产环境搭建高可用Harbor(包括恢复演练实操)

    生产环境搭建高可用Harbor(包括恢复演练实操) 前言 因资源成本问题,本Harbor高可用架构为最小开销方案,如果资源充足,可以将PG.Redis全部使用使用云厂商集群模式. 同时为了配置简单,并 ...

  4. 【强烈推荐,超详细,实操零失误】node.js安装 + npm安装教程 + Vue开发环境搭建

    node.js安装 + npm安装教程 + Vue开发环境搭建 [强烈推荐,超详细,实操零失误] 原博客园地址:https://www.cnblogs.com/goldlong/p/8027997.h ...

  5. SBT实操指南

    参考资料:1.英文官方文档2.中文官方文档,内容翻译的不全 SBT是类似maven和gradle的自动构建和包依赖管理工具,SBT是Scala技术体系下的包管理工具,都是Lightbend公司开发的, ...

  6. ASP.NET Core托管和部署Linux实操演练手册

    一.课程介绍 ASP.NET Core 是一种全新的跨平台开源 .NET 框架,能够在 IIS.Nginx.Apache.Docker 上进行托管或在自己的进程中进行自托管. 作为一个.NET Web ...

  7. 《5天学会卡西欧fx-5800p之实操视频教程(初级)》目录和我的工作室现场曝光

    很多人给我讲,想让我录制一份卡西欧fx-5800p的视频教程,我也一直在准备,准备了半年,录制视频真的不是件容易的事,条件有限,而且工作也很忙,中途还会有想放弃的念头,真的是花费了我很多的心血,但不管 ...

  8. 第十章 Fisco Bcos 权限控制下的数据上链实操演练

    一.目的 前面已经完成fisco bcos 相关底层搭建.sdk使用.控制台.webase中间件平台等系列实战开发, 本次进行最后一个部分,体系化管理区块链底层,建立有序的底层控管制度,实现权限化管理 ...

  9. Linux+Nginx+Supervisor部署ASP.NET Core实操手册

    一.课程介绍 在上一节课程<ASP.NET Core托管和部署Linux实操演练手册>中我们学过net core的部署方式多样性和灵活性.我们通过远程工具输入dotnet 程序集名称.dl ...

  10. Flink 实战:如何解决生产环境中的技术难题?

    大数据作为未来技术的基石已成为国家基础性战略资源,挖掘数据无穷潜力,将算力推至极致是整个社会面临的挑战与难题. Apache Flink 作为业界公认为最好的流计算引擎,不仅仅局限于做流处理,而是一套 ...

随机推荐

  1. 鸿蒙Next开发实战教程--银行App

    昨天Mate70的官方预热直接引起网络爆炸,现在预约人数已经两百多万了,大家都这么有米吗 今天跟大家分享一个银行app实战教程. 页面虽然看起来比较复杂,但是仔细分析一下并不难,下面跟大家分享一下本项 ...

  2. Linux系列:聊一聊 SystemV 下的进程间共享内存

    一:背景 1. 讲故事 昨天在分析一个 linux 的 dump 时,看到了这么一话警告,参考如下: 0:000> !eeheap -gc *** WARNING: Unable to veri ...

  3. openEuler 20.03 LTS安装单病种前置机

    # 下载配置文件包 cd /opt wget https://interface-soft.oss-cn-hangzhou.aliyuncs.com/manual-package/config.tar ...

  4. 深入浅出了解生成模型-2:VAE模型原理以及代码实战

    From: https://www.big-yellow-j.top/posts/2025/05/11/VAE.html 前文已经介绍了GAN的基本原理以及代码操作,本文主要介绍VAE其基本原理以及代 ...

  5. 异步之舞:FastAPI与MongoDB的深度协奏

    title: 异步之舞:FastAPI与MongoDB的深度协奏 date: 2025/05/18 19:09:08 updated: 2025/05/18 19:09:08 author: cmdr ...

  6. 楚慧杯Misc—复现

    gza_CrackerCrack_me 追踪tcp流量 找到字典 保存字典,上流量一把梭 base64解密 特殊流量2 一把梭出个www.zip 打开,是个RSA <?php $cmd = @$ ...

  7. LocalDateTime获取 年月日时分秒和判断日期大小

    环境:java version "13.0.1". 创建一个DateUtils类,提供三个常用方法: String 转换 LocalDateTime的方法. 获取LocalDate ...

  8. MySQL中以数值类型存储IP地址

    前言   数据库中存储IP地址的时候,推荐使用整数存储而不是字符串.一般来说, 在保证正确性的前提下,尽量使用最小的数据类型来存储和展示数据:小的数据类型一般比大的更快,因为小的数据类型占用的磁盘空间 ...

  9. 启智树提高组day3T1 3479 : A:climb 树

    启智树提高组day3T1 3479 : A:climb 树 题目描述 DoubleDuck山是X省的著名旅游景点.这一天,淘淘慕名而来,打算爬到山顶处. DoubleDuck山的构造是十分特殊的.在这 ...

  10. Mac os的防火墙导致开的热点手机连不上

    在工位上用Mac给手机开热点用,结果今天手机一直连不上Mac开的热点,最后把Mac的防火墙关了就能让手机连上了,连上了再把防火墙打开也不影响连接.