事情的原由是某天CTO忽然和我說,生產環境的程序CPU有點高,關鍵是如今也沒什麼負載,一樣的代碼在開發環境上CPU就低的多了。linux
不用細說,那必定是有什麼地方出問題了。golang
CTO還說,他pprof過了,佔用CPU最高的runtime.futex,還發了一篇相關的文章誰佔了該CPU核的30% - 一個較意外的Go性能問題 ,打趣說沒準系統負載高了,這個問題就沒了。由於原文中寫到:bash
必須指出,本問題是由於系統空閒沒有goroutine能夠調度形成的。顯然的,系統繁忙的時候,即CPU資源真正體現價值時,上述30%的%CPU的overhead並不存在,由於大機率下會有goroutine可供調度,無需去作讓M去sleep這個很重的操做。服務器
而後就把這個鍋就「甩」給我了,讓我研究一下。畢竟開發環境的負載也沒有那麼高,可是CPU卻蠻正常的。app
一開始我是沒什麼頭緒,順着CTO提供的線索,搜索了一些runtime.futex的文章,幾乎全部文章都會提到如下可能會使CPU佔用率高的示例代碼:性能
var ticker = time.NewTicker(100 * time.Millisecond)
defer ticker.Stop()
var counter = 0
for {
select {
case <-serverDone:
return
case <-ticker.C:
counter += 1
}
}
複製代碼
這段代碼給我指明瞭一些方向,我開始全局搜索一些time.NewTicker的代碼。ui
巧的是,還真讓我搜到了一些,其中一個ticker的時間設置的頗有問題。spa
options = append(options, metrics.BatchInterval(time.Duration(conf.BatchInterval)))
複製代碼
這裏的time.Duration(conf.BatchInterval)沒有指定單位,那可就是nano second(納秒)級別的,這ticker的協程跑起來,沒形成死鎖,只能說linux服務器的性能好。code
後來,順藤摸瓜,發現了這個interval實際上是promethus的採樣interval,promethus只在生產打開了,也能夠解釋了爲何一樣的代碼只在生產上出問題。server
初步的解決方法很簡單,就是給這個interval加上單位,再略微調大一些就好,並且目前咱們並無過重視promethus的性能數據,因此也不是很肯定50ms的採樣間隔是否是有些過大。
雖然說找到了問題的root cause,但仍是有值得改進的地方,好比說,若是一開始就先diff生產和開發的程序的配置有哪些不一樣,說不定能夠更快的解決問題。