学会这几招让 Go 程序自己监控自己
发布日期:2022-02-01 16:54:05 浏览次数:47 分类:技术文章

本文共 3581 字,大约阅读时间需要 11 分钟。

谈到让Go程序监控自己进程的资源使用情况,那么就让我们先来谈一谈有哪些指标是需要监控的,一般谈论进程的指标最常见的就是进程的内存占用率、CPU占用率、创建的线程数。因为Go语言又在线程之上自己维护了Goroutine,所以针对Go进程的资源指标还需要加一个创建的Goroutine数量。

又因为现在服务很多都部署在Kubernetes集群上,一个Go进程往往就是一个Pod,但是容器的资源是跟宿主机共享的,只是在创建的时候指定了其资源的使用上限,所以在获取CPUMemory这些信息的时候还需要具体情况分开讨论。

怎么用Go获取进程的各项指标

我们先来讨论普通的宿主机和虚拟机情况下怎么获取这些指标,容器环境放在下一节来说。

获取Go进程的资源使用情况使用gopstuil库即可完成,它我们屏蔽了各个系统之间的差异,帮助我们方便地获取各种系统和硬件信息。gopsutil将不同的功能划分到不同的子包中,它提供的模块主要有:

  • cpu:系统CPU 相关模块;

  • disk:系统磁盘相关模块;

  • docker:docker 相关模块;

  • mem:内存相关模块;

  • net:网络相关;

  • process:进程相关模块;

  • winservices:Windows 服务相关模块。

我们这里只用到了它的process子包,获取进程相关的信息。

声明:process 模块需要 import "github.com/shirou/gopsutil/process"后引入到项目,后面演示的代码会用到的os等模块会统一省略import相关的信息和错误处理,在此提前说明。

创建进程对象

process模块的NewProcess会返回一个持有指定PIDProcess对象,方法会检查PID是否存在,如果不存在会返回错误,通过Process对象上定义的其他方法我们可以获取关于进程的各种信息。

p, _ := process.NewProcess(int32(os.Getpid()))

进程的CPU使用率

进程的CPU使用率需要通过计算指定时间内的进程的CPU使用时间变化计算出来

cpuPercent, err := p.Percent(time.Second)

上面返回的是占所有CPU时间的比例,如果想更直观的看占比,可以算一下占单个核心的比例。

cp := cpuPercent / float64(runtime.NumCPU())

内存使用率、线程数和goroutine数

这三个指标的获取过于简单咱们就放在一块说

// 获取进程占用内存的比例mp, _ := p.MemoryPercent()// 创建的线程数threadCount := pprof.Lookup("threadcreate").Count()// Goroutine数 gNum := runtime.NumGoroutine()

上面获取进程资源占比的方法只有在虚拟机和物理机环境下才能准确。类似Docker这样的Linux容器是靠着Linux的Namespace和Cgroups技术实现的进程隔离和资源限制,是不行的。

现在的服务很多公司是K8s集群部署,所以如果是在Docker中获取Go进程的资源使用情况需要根据Cgroups分配给容器的资源上限进行计算才准确。

容器环境下获取进程指标

Linux中,Cgroups给用户暴露出来的操作接口是文件系统,它以文件和目录的方式组织在操作系统的/sys/fs/cgroup路径下,在 /sys/fs/cgroup下面有很多诸cpusetcpumemory这样的子目录,每个子目录都代表系统当前可以被Cgroups进行限制的资源种类

针对我们监控Go进程内存和CPU指标的需求,我们只要知道cpu.cfs_period_uscpu.cfs_quota_usmemory.limit_in_bytes 就行。前两个参数需要组合使用,可以用来限制进程在长度为cfs_period的一段时间内,只能被分配到总量为cfs_quotaCPU时间, 可以简单的理解为容器能使用的核心数 = cfs_quota / cfs_period

所以在容器里获取Go进程CPU的占比的方法,需要做一些调整,利用我们上面给出的公式计算出容器能使用的最大核心数。

cpuPeriod, err := readUint("/sys/fs/cgroup/cpu/cpu.cfs_period_us")cpuQuota, err := readUint("/sys/fs/cgroup/cpu/cpu.cfs_quota_us")cpuNum := float64(cpuQuota) / float64(cpuPeriod)

然后再把通过p.Percent获取到的进程占用机器所有CPU时间的比例除以计算出的核心数即可算出Go进程在容器里对CPU的占比。

cpuPercent, err := p.Percent(time.Second)// cp := cpuPercent / float64(runtime.NumCPU())// 调整为cp := cpuPercent / cpuNum

而容器的能使用的最大内存数,自然就是在memory.limit_in_bytes里指定的啦,所以Go进程在容器中占用的内存比例需要通过下面这种方法获取

memLimit, err := readUint("/sys/fs/cgroup/memory/memory.limit_in_bytes")memInfo, err := p.MemoryInfomp := memInfo.RSS * 100 / memLimit

上面进程内存信息里的RSS叫常驻内存,是在RAM里分配给进程,允许进程访问的内存量。而读取容器资源用的readUint,是containerd组织在cgroups实现里给出的方法。

func readUint(path string) (uint64, error) { v, err := ioutil.ReadFile(path) if err != nil {  return 0, err } return parseUint(strings.TrimSpace(string(v)), 10, 64)}func parseUint(s string, base, bitSize int) (uint64, error) { v, err := strconv.ParseUint(s, base, bitSize) if err != nil {  intValue, intErr := strconv.ParseInt(s, base, bitSize)  // 1. Handle negative values greater than MinInt64 (and)  // 2. Handle negative values lesser than MinInt64  if intErr == nil && intValue < 0 {   return 0, nil  } else if intErr != nil &&   intErr.(*strconv.NumError).Err == strconv.ErrRange &&   intValue < 0 {   return 0, nil  }  return 0, err } return v, nil}

我在下方参考链接里会给出他们源码的链接。

总结

关于本文的完整源码和一些进程监控相关的有价值资料已经收入到我的《Go开发参考书》里了,有需要的可以在【网管叨bi叨】公众号回复gocookbook 领取阅读,如果想在容器环境下尝试的话需要自己动手起个Docker或者Kubernetes集群才能进行测试。

如果想入门K8s,安利下我的 ,包治不会~!

你可能会问,为啥让Go程序自己监控自己,有什么用呢?那肯定是能以这个为基点做一些服务治理的事情啦,具体的应用场景以后再分享,感兴趣的可以关注一波。

参考链接

  • Contianerd utils: https://github.com/containerd/cgroups/blob/318312a373405e5e91134d8063d04d59768a1bff/utils.go#L243

  • What is RSS: https://stackoverflow.com/questions/7880784/what-is-rss-and-vsz-in-linux-memory-management

转载地址:https://blog.csdn.net/slphahaha/article/details/121506842 如侵犯您的版权,请留言回复原文章的地址,我们会给您删除此文章,给您带来不便请您谅解!

上一篇:你对 Go 错误处理的几个误解!
下一篇:Go 开发中常用的几个开源库

发表评论

最新留言

表示我来过!
[***.240.166.169]2024年04月10日 05时45分19秒

关于作者

    喝酒易醉,品茶养心,人生如梦,品茶悟道,何以解忧?唯有杜康!
-- 愿君每日到此一游!

推荐文章

《中国债券市场》精髓:中国债券市场由政府主导,其最重要的目的是为国家建设筹集资金 2019-04-26
《极简GDP史》精髓:GDP虽有诸多局限性,但是对于社会经济发展仍然有举足轻重的作用 2019-04-26
《经济学是什么》精髓:如何用经济学家的眼光理解个人选择和市场经济? 2019-04-26
《卧底经济学》书中精髓:我们如何正确理解“稀缺”这件事儿? 2019-04-26
《学会花钱》书中精髓:花钱如何掌握分寸,以及如何避开花钱误区 2019-04-26
《定投十年财务自由》书中精髓:我们如何通过定投获得更高的收益? 2019-04-26
《海龟交易法则》精髓:制定对自己有利的交易规则,在风险可控的前提下,当机会出现,你要坚定不移的机械性执行交易 2019-04-26
《彼得·林奇教你理财》书中精髓:如何开始投资,以及我们到底该投资什么? 2019-04-26
《货币简史》书中的精髓:货币产生的起源是什么?货币又是如何发展起来的? 2019-04-26
《摩根财团》精髓:摩根财团与时俱进,在不同时代扮演不同角色,始终走在时代的前列 2019-04-26
《朝贡贸易与仗剑经商》精髓:古代中国朝廷不保护商人,将中国商人置于西方势力的仗剑经商之下 2019-04-26
《华尔街之狼》精髓:摔倒并不是坏事,就怕你因此放弃。 2019-04-26
《微观动机与宏观行为》精髓:个人的微观动机,是如何影响宏观行为结果的? 2019-04-26
《国富论》精髓:亚当·斯密提出的对后世影响深远的三个经济学理论:劳动分工理论、生产要素理论和宏观调控理论 2019-04-26
《动荡的世界》精髓:什么是动物精神?动物精神又是怎么影响2008年全球经济危机的,以及我们该如何预防动物精神,避免危机再次发生。 2019-04-26
《投资最重要的事》精髓:利用逆向思维,掌握既冷静又勇猛的投资方法,成为投资界真正厉害的人。 2019-04-26
《周期》书中的精髓:如何利用周期,掌握世界的发展趋势,实现财富积累。 2019-04-26
《伟大的博弈》书中的精髓:华尔街是如何从一条小街,一步步发展为世界金融中心的。 2019-04-26
《逃不开的经济周期》书中的精髓:经济周期是推动创新变革和经济增长以及复兴的关键力量。 2019-04-26
《朋友还是对手》书中的精髓:奥地利学派和芝加哥学派两派共识远多于分歧,两派首先是朋友,其次才是对手。 2019-04-26