谈到让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.MemoryInfo
mp := 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 MinInt64if 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程序自己监控自己,有什么用呢?那肯定是能以这个为基点做一些服务治理的事情啦,具体的应用场景以后再分享,感兴趣的可以关注一波。

参考链接

  • 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

- END -

扫码关注公众号「网管叨bi叨」

给网管个星标,第一时间吸我的知识 

学会这几招让 Go 程序自己监控自己相关推荐

  1. 透过现象看本质,究竟为什么阿里巴巴爱招Java开发程序员?

    为什么阿里巴巴最爱招Java开发程序员? 因为java本身设计特性就是大规模工程语言.它有三个根本性的特征 1.适应各种业务,你目前知道的几乎所有的业务都可以用java写.有很多语言做不到这一点. 2 ...

  2. 计算机u盘驱动坏了如何的修复,U盘损坏怎么恢复?学会这两招,快速恢复里面的文件...

    原标题:U盘损坏怎么恢复?学会这两招,快速恢复里面的文件 U盘损坏怎么恢复?U盘想必大家都不陌生,U盘是我们常用的数据存储设备,但是U盘也很脆弱,使用一段时间过后就会出现连接不上,打不开这些故障,当U ...

  3. log加时间 securecrt_今日头条如何加V?学会这几招加V很容易

    轻松玩转今日头条,学会这几招加黄V超容易,让"大智"忠臣为你服务!人人都能加黄V!加v就意味着你是某个领域的"专家"了,身份的象征!那么如何在今日头条站稳脚,快 ...

  4. word回车后间距太大_Word这些神奇的功能,你知道多少?学会这4招,工作不再发愁...

    工作中,常常有朋友花费大量时间去学习excel和PPT,很少钻研word,仅仅认为word就是一文字编辑软件,会录入文字就可以了.其实不然,经常使用word的朋友肯定会感慨,它给了我们很多的惨痛教训, ...

  5. 学会这9招,你也能成为演讲高手

    ==== 此回答不仅会帮助你提升演讲能力,并且提供了使人变得风趣幽默的独门心法 === 2014年的12月,接到公司一个重要任务,需要我在12月底举办的<做自己>大型青年论坛上,代表公司出 ...

  6. nb信号和4g信号_手机信号很强但是4G网络却很卡?学会这三招,立马恢复网速

    相信不少小伙伴在使用手机的时候,可能会遇到这样一种情况,那就是手机信号明明很强,但是4G网络却很卡,无论是看视频还是玩游戏都时不时出现卡顿的情况,非常影响体验.那么这种情况我们应该怎么解决呢,其实只要 ...

  7. 电脑卡顿不流畅怎么解决_电脑用久了卡怎么办?学会这四招解决你的电脑卡顿问题...

    很多人在遇到电脑卡顿时总会吐槽:这电脑配置真烂,或者Windows系统垃圾,又或是转向攻击其他事物(品牌.硬件等).其实这些吐槽有的对,有的不对.有些时候确实是电脑的锅,有的时候却是操作系统或软件的问 ...

  8. adf盖怎么打开_罐头好吃盖难开,学会这几招,再不靠蛮力了,女生也轻松拧开...

    家里储备的罐头怎么开?学会这几招,不用蛮力,女生也轻松拧开.这段时期家里肯定储备了很多罐头食品,像水果罐头.腌菜罐头.果酱.调料酱罐头等等,家里的青菜水果不足了,可以临时用罐头食品顶上几天,能尽量多宅 ...

  9. 2017年秋招美团Java程序员开发,看我如何拿到offer

    转载自  2017年秋招美团Java程序员开发,看我如何拿到offer 本人是一名本科毕业非计算机专业的程序员,面了阿里,结果没过,最后面上了美团,热乎乎的面经,昨天面的美团,虽然面完了HR面,但是感 ...

最新文章

  1. Android四大基本组件介绍与生命周期
  2. C++中数字和字符串类型的转换
  3. idea新建maven项目没有src目录
  4. python switch_从邮箱验证小项目说python字符串判断与if判断那些事儿
  5. 【独家揭秘】阿里怎么做双11全链路压测?| CSDN 博文精选
  6. 黑马程序员——选择排序
  7. php switch正则表达式,switch的用法以及正则表达式简单的用法
  8. python之slice,range
  9. Javascript中的!-- //--
  10. python 中读取yaml
  11. 10-TensorFlow 基于LeNet的轴承故障诊断
  12. Efficient polynomial commitment schemes for multiple points and polynomials学习笔记
  13. 纹理(讲得比较详细的文章)
  14. 文明与征服萨拉丁怎么搭配阵容?
  15. HBase原理–所有Region切分的细节都在这里了
  16. 流水线-流水线相关计算
  17. javaEE练习(商城练习)
  18. 独立游戏——《爱与正义》准备开工啦!
  19. make命令 makefile文件
  20. 6、查询学过“张三”老师所教的所有课的同学的学号、姓名(重点)

热门文章

  1. (二)java版spring cloud+spring boot 社交电子商务平台 - 整合企业架构的技术点
  2. 磊哥评测之数据库:腾讯云MongoDB vs自建
  3. Kafka#4:存储设计 分布式设计 源码分析
  4. 用android LinearLayout和RelativeLayout实现精确布局(转)
  5. linux 单引号,双引号,反引号
  6. 安驾者电子狗升级步骤
  7. CodeForces - 1328D Carousel(构造+贪心)
  8. POJ - 2594 Treasure Exploration(最小路径覆盖-二分图最大匹配+传递闭包)
  9. HDU - 3397 Sequence operation(线段树+区间合并)
  10. EOJ_1049_三元组稀疏矩阵相加