译文 Go: sysmon, Runtime Monitoring

fliter · 2020年09月15日 · 537 次阅读
本帖已被设为精华帖!

原文作者Vincent Blanchon, 地址Go: sysmon, Runtime Monitoring

插图来自A Journey With Go,由 Renee French方面提供

本篇文章基于Go 1.14

Go 的标准库提供了一种监测应用程序的线程,并帮你 (找寻) 程序可能遇到的瓶颈. 该线程称为sysmon,即系统监视器 (system monitor).在GMP 模型中,这个 (特殊) 线程未链接任何的 P, 这意味着调度器 (scheduler) 没有将其考虑在内, 因此始终处于运行状态.

如下是带有此特殊线程的图:

更多关于GMP模型的内容,推荐阅读作者的另一篇文章 协程,系统线程及 CPU 管理

同样, 通过Go tool trace无法追踪到此线程.


Scope

sysmon线程的作用很广, 主要涉及以下方面:

  • 由应用程序创建的计时器 (timers). sysmon线程查看应该在运行却仍在等待执行时间的计时器. 在这种情况下, Go 将查看空闲的 M 和 P 列表, 以便尽可能快地运行它们.

  • 网络轮询器和系统调用. 它将运行在网络操作中被阻塞的 goroutine.

  • 垃圾回收器(如果已经很长时间没有运行). 如果垃圾回收器已经两分钟没有运行,则 sysmon 将强制执行一轮垃圾回收 (GC). 如下是用Go tool trace工具生成的追踪示例:

  • 长时间运行的 goroutine 的抢占. 任何运行时间超过10 毫秒的 goroutine 都会被抢占, 将运行时间 (running time) 留给其他 goroutine.

有关异步抢占的更多信息,推荐阅读作者 Go:异步抢占



Pace

sysmon足够聪明, 在无事可做时不会消耗资源. 其周期 (循环时间) 是动态的,取决于正在运行的程序的当前活动.

初始速度 (执行频次) 设置为20 纳秒,这意味着sysmon线程一直在寻求 (哪里需要) 帮助. 然后,经过几个周期, 如果sysmon线程没有执行任何操作, 则两个周期之间的休眠将加倍, 直至达到10 毫秒. 如果应用程序没有很多系统调用长时间运行的 goroutine, 则该线程将在大多数情形下,回退变为10 毫秒的延迟 (执行频次),从而给应用程序带来非常小的开销.

sysmon线程还能够检测其何时不应运行, 如以下两种情况:

  • 垃圾回收器即将要运行. (sysmon线程将在垃圾回收结束时恢复)
  • 所有线程都处于空闲状态,没有任何一个在运行中

在这两种情况下, sysmon都会休眠,从而不会有任何不必要的资源消耗.


( 译者注:Go 并发的最小逻辑单位叫做 goroutine, 是 Go 为实现并发提供的用户态线程,这种用户态线程运行在内核态线程(OS线程)之上,也称为协程. 协程是一种用户态的轻量级线程, 其调度完全由用户控制. 从技术角度说,“协程就是你可以暂停执行的函数”. 协程拥有自己的寄存器上下文和栈. 协程调度切换时, 将寄存器上下文和栈保存到其他地方, 在切回来时,恢复先前保存的寄存器上下文和栈. 直接操作栈则基本没有内核切换的开销, 可以不加锁的访问全局变量,所以上下文的切换非常快.

Go 中的协程有三种:一种是主 (轻量级) 线程,一种是用来跑 sysmon 的 (轻量级) 线程,一种是普通的 (轻量级) 线程,

想这样一个问题:

在调度过程中,如果一个 goroutine 一直占有 CPU 又不会有阻塞或则主动让出 CPU 的调度,scheduler 怎么做抢占式调度让出 CPU?

有一个特殊的 sysmon 线程做抢占式调度, 当一个 goroutine 占用 CPU 超过10 毫秒之后,调度器会根据实际情况提供不保证的协程切换

这便是 sysmon 的作用之一 )


sysmon有关的源码, 主要在runtime/proc.goruntime/runtime2.go

更多原创文章干货分享,请关注公众号
  • 加微信实战群请加微信(注明:实战群):gocnio
cuteLittleDevil GoCN 每日新闻 (2020-09-15) 中提及了此贴 09月15日 20:41
kevin 将本帖设为了精华贴 09月15日 23:10
需要 登录 后方可回复, 如果你还没有账号请点击这里 注册