如何監控 Go Runtime

文章來自於 http://blog.helongfei.com/2019/%E7%9B%91%E6%8E%A7-go-runtime/,也可以閱讀原文閱讀。

Go 通常作爲守護進程存在,若我們不做任何監控,放任其「自由」的使用資源,那有可能會發現意外情況,比如「Goroutine 泄露」。那我們應該如何監控,又要監控哪些指標呢?

監控指標

監控的核心是監控指標,「有用」的指標纔是有意義,那 Go 有哪些有意義的指標呢?

我認爲只要監控go runtime 相關的指標就行,整體分爲兩大類:

  1. CPU:goroutine、cgo

  2. 內存:gc、heap、stack

監控架構

既然確定了監控指標,那如何監控呢?這裏要感謝 Brian Hatfield 開源的 go-runtime-metrics[1],我們可以利用它快速的搭建監控系統。

整體架構如下:

Go runtime 監控架構圖

由圖可知,我們使用了GrafanaGraphiteStatsd;其中Statsd是和運行程序部署在一起的,默認是 10s 上報一次,對性能的影響不是太大,真的出現瓶頸的時候,可以再抽離;Graphite 是包含圖表的;這裏使用的是 Grafana 集成 Graphite

Go-runtime-metric

https://github.com/bmhatfield/go-runtime-metrics

工作原理:

  1. 程序啓動後,開啓一個 goroutine 採集上報 metric,數據收集使用 statsd,傳輸協議採用 UDP

  2. main函數中使用 flag.Parse() 纔會打開採集上報(上報服務地址等通過命令行參數修改)

  3. 採樣率 100%,且不可修改(可以自己 fork 後修改)

  4. 上報間隔 10s,可通過命令行--pause修改

  5. 使用的 metric type 是 Gauges

  6. 所有的採集項都是通過 runtime 包完成的;統計 mem 時,會觸發 STW(若關心性能,建議關閉統計 mem

可用參數:

--statsd=localhost:8125 # Statsd host:port
--metric-prefix # Metric prefix path;用於區分機器/應用等
--pause=10 # 上報間隔;default 10s
--publish-runtime-stats=true # 是否採集 go runtime;採集總開關
--cpu # 是否採集 CPU
--mem # 是否採集 mem
--gc # 是否採集 GC (必須開啓 --mem)

Statsd

https://github.com/statsd/statsd

基於 node.js 實現,用於收集 metric 數據,支持 UDP、TCP 協議,默認每 10s 向後端發送一次數據,支持集羣部署。支持的 metric type[2] 有 Counting、Sampling、Timing、Gauges。支持多種 backend[3],內置三個:Graphite,Console,Repeater,第三方見文檔。

啓動前使用run_tests.js 檢查下環境等問題。使用起來很簡單,主要是兩個配置文件:exampleConfig.jsexampleProxyConfig.js,前者用於單機部署,後者用於集羣部署;詳細配置含義見文件內容註釋。

使用Graphite示例:

// 單機部署
{
  graphitePort: 2003, 
  graphiteHost: "localhost", 
  port: 8125, 
  server: "./servers/udp", debug: true,
  backends: [ "./backends/console""./backends/graphite" ]
}

Graphite

http://graphiteapp.org/

Graphite 主要作用是保存 metric 數據,並將其可視化。內置三個組件:

  1. carbon:監聽時間序列數據(守護進程)

  2. whisper:存儲時間序列數據(數據存儲 - 類似 RRD)

  3. graphite-webapp:渲染時間序列數據,提供 Web & API(Web 應用)

架構圖如下:

graphite 架構圖

Carbon

Carbon 主要是監聽並處理 metric 。

配置

https://graphite.readthedocs.io/en/latest/config-carbon.html

包含多個 conf(默認在 /opt/graphite/conf):

  1. carbon.conf 主要是三個 sectoion:[cache] 緩存、[relay] 轉發、[aggregator] 聚合

  2. storage-schemas.conf 主要是存儲週期設置。修改後不會立即生效,需要執行下whisper-resize.py

    [apache_busyWorkers]
    pattern = ^servers\.www.*\.workers\.busyWorkers$
    # 15s 一個點,存 7 天;1m 一個點,存 21 天...
    retentions = 15s:7d,1m:21d,15m:5y
  3. storage-aggregation.conf 主要是多個相同 metric 聚合 metric,修改後不會立即生效,需要執行whisper-set-aggregation-method.py *.wsp <method>

    [all_min]
    pattern = \.min$
    # 上一個 retention level 至少含有下一個 level 的 10% 的值
    xFilesFactor = 0.1
    # 聚合方法
    aggregationMethod = min
  4. relay-rules.conf 主要是轉發數據

    [example]
    pattern = ^mydata\.foo\..+
    servers = 10.1.2.3, 10.1.2.4:2004, myserver.mydomain.com
  5. aggregation-rules.conf 主要是根據 rule、method,對 metric 進行聚合操作

    output_template (frequency) = method input_pattern
  6. rewrite-rules.conf 根據 rule 對 metric 進行重命名

    regex-pattern = replacement-text
  7. whitelist.conf 設置 metric 白名單

  8. blacklist.conf 設置 metric 黑名單

啓動

單機

https://graphite.readthedocs.io/en/latest/admin-carbon.html

使用 carbon-cache.py,相關配置:carbon.conf、storage-schemas.conf

/opt/graphite/bin/carbon-cache.py start

若有性能問題,可以在運行carbon-cache.py之前使用carbon-aggregator.py,對數據進行聚合,減少數據量。相關配置:carbon.conf、aggregation-rules.conf

集羣

https://graphite.readthedocs.io/en/latest/carbon-daemons.html

使用 carbon-relay.py,主要作用是複製和分片。相關配置:carbon.conf、relay-rules.conf 也可以使用carbon-aggregator-cache.py, 它合併了carbon-aggregator.pycarbon-cache.py兩個腳本,相關配置:carbon.conf、relay-rules.conf、aggregation-rules.conf

Graphite-web

使用 Django 開發。

配置

https://graphite.readthedocs.io/en/latest/config-local-settings.html

這裏的 database 主要是存儲用戶、dashboard 等信息。默認使用 SQLite。

啓動

https://graphite.readthedocs.io/en/latest/config-webapp.html

配置 nginx + gunicorn

Whisper

https://graphite.readthedocs.io/en/latest/whisper.html

存儲時間序列數據,類似 RRD,一個環形數據庫。

部署

本地學習環境安裝,非高性能版安裝。

安裝步驟

  1. 安裝 Graphite + statsd 使用 Docker 安裝,推薦使用 Graphite 官方的 docker repo[4],包含 Graphite & statsd

  2. 安裝 Grafana

  3. Go 工程代碼中添加 github.com/bmhatfield/go-runtime-metrics

使用示例:

package main

import (
 "flag"
 "log"
 "net/http"
 "os"

 _ "github.com/bmhatfield/go-runtime-metrics"
)

func main() {
  // 打開採集
 flag.Parse()

 cwd, err := os.Getwd()
 if err != nil {
  log.Fatal(err)
 }

 srv := &http.Server{
  Addr:    ":8000", // Normally ":443"
  Handler: http.FileServer(http.Dir(cwd)),
 }
 log.Fatal(srv.ListenAndServe())
}

參考資料

  1. Graphite[5]

  2. Statsd[6]

  3. Go-runtime-metric[7]

參考資料

[1]

go-runtime-metrics: https://github.com/bmhatfield/go-runtime-metrics

[2]

metric type: https://github.com/statsd/statsd/blob/master/docs/metric_types.md

[3]

backend: https://github.com/statsd/statsd/blob/master/docs/backend.md

[4]

docker repo: https://github.com/graphite-project/docker-graphite-statsd

[5]

Graphite: http://graphiteapp.org/

[6]

Statsd: https://github.com/statsd/statsd

[7]

Go-runtime-metric: https://github.com/bmhatfield/go-runtime-metrics

本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源https://mp.weixin.qq.com/s/67ChnjkM3QNmMuNvck28og