Go: sysmon, Runtime Monitoring

fliter發表於2020-09-15

原文作者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

更多原創文章乾貨分享,請關注公眾號
  • Go: sysmon, Runtime Monitoring
  • 加微信實戰群請加微信(註明:實戰群):gocnio

相關文章