mysqld_exporter的源碼分析和定制化(單個mysqld_exporter監控多個數據庫實例)


mysqld_exporter是prometheus官方提供的用於監控mysql運行狀態的exporter。其相關信息可以參考:https://github.com/prometheus/mysqld_exporter

 

1. 配置

先看一下其配置方式。主要的配置內容分為兩部分,一部分是監控目標mysql的連接信息,另一部分是exporter抓取的監控參數的設置。

 

首先是連接信息:

連接信息的設置方法有兩種。第一種是通過環境變量設置,例如:

export DATA_SOURCE_NAME='user:password@(hostname:3306)/'
./mysqld_exporter <flags>

另一種方法是通過配置文件進行設置。配置文件會在func parseMycnf()函數中被轉化為與環境變量設置的格式相同。隨后該設置將傳入golang的db庫並進行數據庫連接。

對於兩種設置的優先級,當環境變量存在(長度大於0)時,將不會對配置文件進行解析。

 

然后是exporter抓取的監控參數的設置:

這里用集合來表示監控參數的范圍。首先exporter中利用scrapers常量記錄了一個默認的采集范圍集合A。

exporter也允許在exporter啟動的時候,通過設置啟動參數來設置采集范圍B。

當集合B不存在時,集合A生效;當集合B存在時,集合B生效,集合A失效。

Prometheus在采集exporter的數據時,可以攜帶一個collect[]參數設定采集范圍C。

當集合C不存在時,Prometheus最終的采集范圍是A或者B(取決於哪個集合生效);當集合C存在時,Prometheus最終的采集范圍時C和A或者B(取決於哪個集合生效)的交集。

 

2. 工作模式

exporter收集監控數據主要是由Collector實現的。

首先是路由的注冊。注意mysqld_exporter.go的277和278行:

    handlerFunc := newHandler(collector.NewMetrics(), enabledScrapers)
    http.Handle(*metricPath, promhttp.InstrumentMetricHandler(prometheus.DefaultRegisterer, handlerFunc))

可以看出主要的處理函數在newHandler(),回到162行函數本體。164行是默認的scraper,165行是獲取prometheus帶的collect[]參數。在196-208行,對collect[]進行了處理,並與scraper求了交集。

在210-211行注冊了prometheus的collector,collector的處理入口在/collector/exporter.go的85行New()函數。函數New()返回了一個叫Exporter的結構體。該結構體實現了Prometheus采集的interface,因此在117行的其成員函數Collect()就是采集數據的位置。

Collect()函數調用了126行的scrape()函數。scrape()函數做了一些數據庫初始化的操作后,在160行遍歷了所有scraper,並go func調用所有scraper的Scrape()函數,實現對目標數據的采集。

綜上,對於mysqld_exporter,只有Prometheus在訪問其數據接口時,exporter才對數據庫進行連接並采集數據。對於多個scraper,exporter采取多個協程實現數據的並發采集。(具體的並發能力還要看mysql中為exporter提供的賬號的並發連接數)

 

3. 定制化

對於單個mysqld_exporter,其內存占用多在幾十M左右。而在實際的應用中,單個exporter實例只能監控單個mysql數據庫是該exporter的一個痛點。

而第2節中介紹的數據采集的特性,其數據接口在未被訪問時幾乎沒有其他動作,因此從性能開銷上來講,利用單個exporter監控多個數據庫並不會存在太大問題。

(當然一個顯然的問題是,多個數據庫的請求是串行還是並行?如果選擇並行,對每個數據庫的每個scraper使用單獨的協程,在協程數量過多的時候對性能會不會產生影響。這是需要深入討論的問題。但是接下來的內容避開了這個問題。)

如何使exporter可以監控多個數據庫實例?一個直接的思路是,在Prometheus訪問數據接口時,多傳入一個instance參數,該參數為監控目標數據庫的地址和端口,例如“localhost:3306”。

那么,當我們處理Prometheus的訪問(即前文提到的newHandler)時,如果解析到了instance參數,就將該instance信息替換掉配置中的數據庫連接信息,這樣就實現了利用Prometheus的配置參數選擇監控的數據庫實例。

通常,Prometheus的配置文件應該類似:

scrape_configs:

  - job_name: 'prometheus'

    static_configs:
      - targets: ['localhost:9090']

      - params
        "collect[]":
          - ***

 

但是這樣每次訪問接口只能獲取某個數據庫實例的監控數據。這些數據如何整合到一起?

這時候Prometheus配置中的relabel config就登場了。(這里,具體的說明文檔請參考https://prometheus.io/docs/prometheus/latest/configuration/configuration/#relabel_config

這里我們解釋一下relabel和metrics relabel的區別。relabel是在Prometheus訪問數據接口前生效的,metrics relabel是在接收到數據之后生效的。

relabel config中提供了以下兩個label:

第一個是__address__。通常,我們在配置Prometheus的監控對象時,監控的目標時target。在relabel階段,target會自動傳給__address__,並作為relabel之后Prometheus訪問數據接口的地址。

因此,在relabel階段,我們可以直接將__address__這個label進行replace,這樣就可以重新制定Prometheus訪問的數據接口的地址。

第二個是__param_<name>。即,我們可以在relabel階段,通過對這個label進行處理,實現在訪問數據接口時攜帶指定的參數和內容。

舉例如下:

scrape_configs:

  - job_name: 'prometheus'

    static_configs:
      - targets:
        - localhost:3306
        - localhost:3308

      - params
        "collect[]":
          - ***
    
    relabel_config
      - source_labels: ['targets']
        target_label: __address__
      - source_labels: ['__address__']
        target_label: __param_instance
      - source_labels: ['__address__']
        replacement: localhost:9104

假設我們在本地3306和3308兩個端口起了兩個mysql,然后再9104起了定制化的exporter。

先看relabel,我們把targets放入__address__,然后將__address__放入__param_instance,這樣原來的target就作為訪問數據接口的參數instance。而訪問接口的地址被replace成localhost:9104。

這樣就通過在exporter的數據接口增加參數,結合Prometheus配置中的relabel,實現了利用單個mysqld_exporter對多個數據庫實例進行監控。

 

如果需要更深的定制化,比如通過sql語句指定采集的數據等,用mysqld_exporter就不合適了。為了實現這個功能,需要實現一個獨立的Colletor,這樣開發成本較高。

對於自定義sql語句這個需求,可以使用sql_exporter實現。詳情可以參考https://github.com/free/sql_exporter


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM