從 0 到 1 搭建一套 Flink 的監控系統

點擊上方“zhisheng”,選擇“設爲星標”

後臺回覆"666",獲取新資料

之前講解了 JobManager、TaskManager 和 Flink Job 的監控,以及需要關注的監控指標有哪些。本文帶大家講解一下如何搭建一套完整的 Flink 監控系統,如果你所在的公司沒有專門的監控平臺,那麼可以根據本文的內容來爲公司搭建一套屬於自己公司的 Flink 監控系統。

利用 API 獲取監控數據

熟悉 Flink 的朋友都知道 Flink 的 UI 上面已經詳細地展示了很多監控指標的數據,並且這些指標還是比較重要的,所以如果不想搭建額外的監控系統,那麼直接利用 Flink 自身的 UI 就可以獲取到很多重要的監控信息。這裏要講的是這些監控信息其實也是通過 Flink 自身的 Rest API 來獲取數據的,所以其實要搭建一個粗糙的監控平臺,也是可以直接利用現有的接口定時去獲取數據,然後將這些指標的數據存儲在某種時序數據庫中,最後用些可視化圖表做個展示,這樣一個完整的監控系統就做出來了。

這裏通過 Chrome 瀏覽器的控制檯來查看一下有哪些 REST API 是用來提供監控數據的。

1.在 Chrome 瀏覽器中打開 http://localhost:8081/overview 頁面,可以獲取到整個 Flink 集羣的資源信息:TaskManager 個數(TaskManagers)、Slot 總個數(Total Task Slots)、可用 Slot 個數(Available Task Slots)、Job 運行個數(Running Jobs)、Job 運行狀態(Finished 0 Canceled 0 Failed 0)等,如下圖所示。

2.通過 http://localhost:8081/taskmanagers 頁面查看 TaskManager 列表,可以知道該集羣下所有 TaskManager 的信息(數據端口號(Data Port)、上一次心跳時間(Last Heartbeat)、總共的 Slot 個數(All Slots)、空閒的 Slot 個數(Free Slots)、以及 CPU 和內存的分配使用情況,如下圖所示。

3.通過 http://localhost:8081/taskmanagers/tm_id 頁面查看 TaskManager 的具體情況(這裏的 tm_id 是個隨機的 UUID 值)。在這個頁面上,除了上一條的監控信息可以查看,還可以查看該 TaskManager 的 JVM(堆和非堆)、Direct 內存、網絡、GC 次數和時間,如下圖所示。內存和 GC 這些信息非常重要,很多時候 TaskManager 頻繁重啓的原因就是 JVM 內存設置得不合理,導致頻繁的 GC,最後使得 OOM 崩潰,不得不重啓。

另外如果你在 /taskmanagers/tm_id 接口後面加個 /log 就可以查看該 TaskManager 的日誌,注意,在 Flink 中的日誌和平常自己寫的應用中的日誌是不一樣的。在 Flink 中,日誌是以 TaskManager 爲概念打印出來的,而不是以單個 Job 打印出來的,如果你的 Job 在多個 TaskManager 上運行,那麼日誌就會在多個 TaskManager 中打印出來。如果一個 TaskManager 中運行了多個 Job,那麼它裏面的日誌就會很混亂,查看日誌時會發現它爲什麼既有這個 Job 打出來的日誌,又有那個 Job 打出來的日誌,如果你之前有這個疑問,那麼相信你看完這裏,就不會有疑問了。

對於這種設計是否真的好,不同的人有不同的看法,在 Flink 的 Issue 中就有人提出了該問題,Issue 中的描述是希望日誌可以是 Job 與 Job 之間的隔離,這樣日誌更方便採集和查看,對於排查問題也會更快。對此國內有公司也對這一部分做了改進,不知道正在看文的你是否有什麼好的想法可以解決 Flink 的這一痛點。

4.通過 http://localhost:8081/#/job-manager/config 頁面可以看到可 JobManager 的配置信息,另外通過 http://localhost:8081/jobmanager/log 頁面可以查看 JobManager 的日誌詳情。

5.通過 http://localhost:8081/jobs/job_id 頁面可以查看 Job 的監控數據,如下圖所示,由於指標(包括了 Job 的 Task 數據、Operator 數據、Exception 數據、Checkpoint 數據等)過多,大家可以自己在本地測試查看。

上面列舉了幾個 REST API(不是全部),主要是爲了告訴大家,其實這些接口我們都知道,那麼我們也可以利用這些接口去獲取對應的監控數據,然後繪製出更酷炫的圖表,用更直觀的頁面將這些數據展示出來,這樣就能更好地控制。

除了利用 Flink UI 提供的接口去定時獲取到監控數據,其實 Flink 還提供了很多的 reporter 去上報監控數據,比如 JMXReporter、PrometheusReporter、PrometheusPushGatewayReporter、InfluxDBReporter、StatsDReporter 等,這樣就可以根據需求去定製獲取到 Flink 的監控數據,下面教大家使用幾個常用的 reporter。

相關 Rest API 可以查看官網鏈接:rest-api-integration

Metrics 類型簡介

可以在繼承自 RichFunction 的函數中通過 getRuntimeContext().getMetricGroup() 獲取 Metric 信息,常見的 Metrics 的類型有 Counter、Gauge、Histogram、Meter。

Counter

Counter 用於計數,當前值可以使用 inc()/inc(long n) 遞增和 dec()/dec(long n) 遞減,在實現 RichFunction 中的函數的 open 方法註冊 Counter。

private transient Counter counter;

@Override
public void open(Configuration config) {
this.counter = getRuntimeContext()
  .getMetricGroup()
  .counter("zhisheng_counter");
}

//或者自定義 Counter
@Override
public void open(Configuration config) {
this.counter = getRuntimeContext()
  .getMetricGroup()
  .counter("zhisheng_counter", new CustomCounter());
}

@Override
public String map(String value) throws Exception {
this.counter.inc();
return value;
}

Gauge

Gauge 根據需要提供任何類型的值,要使用 Gauge 的話,需要實現 Gauge 接口,返回值沒有規定類型。

private transient int valueToExpose = 0;

@Override
public void open(Configuration config) {
getRuntimeContext()
  .getMetricGroup()
  .gauge("zhisheng_gauge", new Gauge<Integer>() {
    @Override
    public Integer getValue() {
      return valueToExpose;
    }
  });
}

@Override
public String map(String value) throws Exception {
valueToExpose++;
return value;
}

Histogram

Histogram 統計數據的分佈情況,比如最小值,最大值,中間值,還有分位數等。使用情況如下:

private transient Histogram histogram;

@Override
public void open(Configuration config) {
    this.histogram = getRuntimeContext()
  .getMetricGroup()
  .histogram("zhisheng_histogram", new MyHistogram());
}

@Override
public Long map(Long value) throws Exception {
    this.histogram.update(value);
return value;
}

Meter

Meter 代表平均吞吐量,使用情況如下:

private transient Meter meter;

@Override
public void open(Configuration config) {
this.meter = getRuntimeContext()
  .getMetricGroup()
  .meter("myMeter", new MyMeter());
}

@Override
public Long map(Long value) throws Exception {
this.meter.markEvent();
return value;
}

利用 JMXReporter 獲取監控數據

JMX 對於大家來說應該不太陌生,在 Flink 中默認提供了 JMXReporter 獲取到監控數據,不需要額外添加依賴項,但是需要在 flink-conf.yaml 配置文件中加入如下配置即可開啓 JMX:

metrics.reporter.jmx.factory.class: org.apache.flink.metrics.jmx.JMXReporterFactory
metrics.reporter.jmx.port: 8789

然後利用 JDK 自帶的 jconsole 可以查看 MBean 信息,首先需要啓動 jconsole,操作如下圖所示。

啓動 jconsole

然後要配置與進程進行建立連接,如下圖所示。

與進程建立連接

連接成功的話,你可以看到左側是有很多的監控指標,如果點進去是可以查看到每個指標對應的 value 值,如下圖所示。

查看 JMX 監控指標

但是你有沒有發現這些指標只有 JobManager 的監控指標,沒有 TaskManager 的監控指標,如果你在同一臺服務器上面既運行了 JobManager,又運行了 TaskManager,那麼只開啓一個端口號那麼是隻能夠監聽到一個的數據,如果你要監聽多個數據,那麼就需要在端口設置裏填寫一個範圍(這裏需要特別注意一下),具體配置如下:

# jmx reporter
metrics.reporter.jmx.factory.class: org.apache.flink.metrics.jmx.JMXReporterFactory
metrics.reporter.jmx.port: 8789-8799

這樣就表示監聽了多個端口(從 8789 ~ 8799),那麼再通過 jconsole 連接 8790 端口就會出現 TaskManager 的監控指標數據了,如下圖所示。

出現 TaskManager 監控數據

查看日誌也可以看到開啓 JMX 成功的日誌,如下所示。

2019-10-07 10:52:51,839 INFO  org.apache.flink.metrics.jmx.JMXReporter                      - Started JMX server on port 8789.
2019-10-07 10:52:51,839 INFO  org.apache.flink.metrics.jmx.JMXReporter                      - Configured JMXReporter with {port:8789-8799}
2019-10-07 10:52:51,840 INFO  org.apache.flink.runtime.metrics.ReporterSetup                - Configuring jmx with {factory.class=org.apache.flink.metrics.jmx.JMXReporterFactory, port=8789-8799}.
2019-10-07 10:52:51,841 INFO  org.apache.flink.runtime.metrics.MetricRegistryImpl           - Reporting metrics for reporter jmx of type org.apache.flink.metrics.jmx.JMXReporter.

利用 PrometheusReporter 獲取監控數據

要使用該 reporter 的話,需要將 opt 目錄下的 flink-metrics-prometheus-1.9.0.jar 依賴放到 lib 目錄下,可以配置的參數有:

  • port:該參數爲可選項,Prometheus 監聽的端口,默認是 9249,和上面使用 JMXReporter 一樣,如果是在一臺服務器上既運行了 JobManager,又運行了 TaskManager,則使用端口範圍,比如 9249-9259

  • filterLabelValueCharacters:該參數爲可選項,表示指定是否過濾標籤值字符,如果開啓,則刪除所有不匹配 [a-zA-Z0-9:_] 的字符,否則不會刪除任何字符。

除了上面兩個可選參數,另外一個參數是必須要在 flink-conf.yaml 中配置的,那就是 metrics reporter class。比如像下面這樣配置:

metrics.reporter.prom.class: org.apache.flink.metrics.prometheus.PrometheusReporter

Flink 中的 metrics 類型和 Prometheus 中 metrics 類型對比如下圖所示。

利用 PrometheusPushGatewayReporter 獲取監控數據

PushGateway 是 Prometheus 生態中一個重要工具,使用它的原因主要是:

  • Prometheus 採用 pull 模式,可能由於 Prometheus 和其他 target 對象不在一個子網或者防火牆原因,導致 Prometheus 無法直接拉取各個 target 數據。

  • 在監控業務數據的時候,需要將不同數據彙總, 由 Prometheus 統一收集。

那麼使用 PrometheusPushGatewayReporter 的話,該 reporter 會定時將 metrics 數據推送到 PushGateway,然後再由 Prometheus 去拉取這些 metrics 數據。如果使用 PrometheusPushGatewayReporter 收集數據的話,也是需要將 opt 目錄下的 flink-metrics-prometheus-1.9.0.jar 依賴放到 lib 目錄下的,可配置的參數有:

  • deleteOnShutdown:默認值是 true,表示是否在關閉時從 PushGateway 刪除指標。

  • filterLabelValueCharacters:默認值是 true,表示是否過濾標籤值字符,如果開啓,則不符合 [a-zA-Z0-9:_] 的字符都將被刪除。

  • host:無默認值,配置 PushGateway 服務所在的機器 IP。

  • jobName:無默認值,要上報 Metrics 的 Job 名稱。

  • port:默認值是 -1,這裏配置 PushGateway 服務的端口。

  • randomJobNameSuffix:默認值是 true,指定是否將隨機後綴名附加到作業名。

在 flink-conf.yaml 中配置的樣例如下:

metrics.reporter.promgateway.class: org.apache.flink.metrics.prometheus.PrometheusPushGatewayReporter
metrics.reporter.promgateway.host: localhost
metrics.reporter.promgateway.port: 9091
metrics.reporter.promgateway.jobName: zhisheng
metrics.reporter.promgateway.randomJobNameSuffix: true
metrics.reporter.promgateway.deleteOnShutdown: false

利用 InfluxDBReporter 獲取監控數據

Flink 裏面提供了 InfluxDBReporter 支持將 Flink 的 metrics 數據直接存儲到 InfluxDB 中,在源碼中該模塊是通過 MetricMapper 類將 MeasurementInfo(這個類是 metric 的數據結構,裏面含有兩個字段 name 和 tags) 和 Gauge、Counter、Histogram、Meter 組裝成 InfluxDB 中的 Point 數據,Point 結構如下(主要就是構造 metric name、fields、tags 和 timestamp):

private String measurement;
private Map<String, String> tags;
private Long time;
private TimeUnit precision;
private Map<String, Object> fields;

然後在 InfluxdbReporter 類中將 metric 數據導入 InfluxDB,該類繼承自 AbstractReporter 抽象類,實現了 Scheduled 接口,有下面 3 個屬性:

private String database;
private String retentionPolicy;
private InfluxDB influxDB;

在 open 方法中獲取配置文件中的 InfluxDB 設置,然後初始化 InfluxDB 相關的配置,構造 InfluxDB 客戶端:

public void open(MetricConfig config) {
    //獲取到 host 和 port
 String host = getString(config, HOST);
 int port = getInteger(config, PORT);
 //判斷 host 和 port 是否合法
 if (!isValidHost(host) || !isValidPort(port)) {
  throw new IllegalArgumentException("Invalid host/port configuration. Host: " + host + " Port: " + port);
 }
 //獲取到 InfluxDB database
 String database = getString(config, DB);
 if (database == null) {
  throw new IllegalArgumentException("'" + DB.key() + "' configuration option is not set");
 }
 String url = String.format("http://%s:%d", host, port);
 //獲取到 InfluxDB username 和 password
 String username = getString(config, USERNAME);
 String password = getString(config, PASSWORD);

 this.database = database;
 //InfluxDB 保留政策
 this.retentionPolicy = getString(config, RETENTION_POLICY);
 if (username != null && password != null) {
     //如果有用戶名和密碼,根據 url 和 用戶名密碼來創建連接
  influxDB = InfluxDBFactory.connect(url, username, password);
 } else {
     //否則就根據 url 連接
  influxDB = InfluxDBFactory.connect(url);
 }

 log.info("Configured InfluxDBReporter with {host:{}, port:{}, db:{}, and retentionPolicy:{}}", host, port, database, retentionPolicy);
}

然後在 report 方法中調用一個內部 buildReport 方法來構造 BatchPoints,將一批 Point 放在該對象中,BatchPoints 對象的屬性如下:

private String database;
private String retentionPolicy;
private Map<String, String> tags;
private List<Point> points;
private ConsistencyLevel consistency;
private TimeUnit precision;

通過 buildReport 方法返回的 BatchPoints 如果不爲空,則會通過 write 方法將 BatchPoints 寫入 InfluxDB:

if (report != null) {
 influxDB.write(report);
}

在使用 InfluxDBReporter 時需要注意:

1.必須複製 Flink 安裝目錄下的 /opt/flink-metrics-influxdb-1.9.0.jar 到 flink 的 lib 目錄下,否則運行起來會報 ClassNotFoundException 錯誤,詳細錯誤如下圖所示:

2.如下所示,在 flink-conf.yaml 中添加 InfluxDB 相關的配置。

metrics.reporter.influxdb.class:org.apache.flink.metrics.influxdb.InfluxdbReporter
metrics.reporter.influxdb.host:localhost  # InfluxDB服務器主機
metrics.reporter.influxdb.port: 8086   # 可選)InfluxDB 服務器端口,默認爲 8086
metrics.reporter.influxdb.db:zhisheng # 用於存儲指標的 InfluxDB 數據庫  
metrics.reporter.influxdb.username:zhisheng # (可選)用於身份驗證的 InfluxDB 用戶名
metrics.reporter.influxdb.password:123456 # (可選)InfluxDB 用戶名用於身份驗證的密碼
metrics.reporter.influxdb.retentionPolicy: one_hour #(可選)InfluxDB 數據保留策略,默認爲服務器上數據庫定義的保留策略

如果填錯了密碼會報鑑權失敗的錯誤,錯誤信息如下圖所示。

安裝 InfluxDB 和 Grafana

接下來將講解 InfluxDB 和 Grafana 的安裝和配置。

安裝 InfluxDB

InfluxDB 是一款時序數據庫,使用它作爲監控數據存儲的公司也有很多,可以根據 InfluxDB 官網:https://docs.influxdata.com/influxdb/v1.7/introduction/installation/  的安裝步驟來操作。

1、配置 InfluxDB 下載源。

cat <<EOF | sudo tee /etc/yum.repos.d/influxdb.repo
[influxdb]
name = InfluxDB Repository - RHEL \$releasever
baseurl = https://repos.influxdata.com/rhel/\$releasever/\$basearch/stable
enabled = 1
gpgcheck = 1
gpgkey = https://repos.influxdata.com/influxdb.key
EOF

2、根據 yum 安裝命令操作。

yum install influxdb 

3、啓停 InfluxDB。

//啓動 influxdb 命令
systemctl start influxdb
//重啓 influxdb 命令
systemctl restart influxd
//停止 influxdb 命令
systemctl stop influxd
//設置開機自啓動
systemctl enable influxdb

4、InfluxDB 相關的命令操作。

啓動好 InfluxDB 後執行 influx 命令,然後使用下面命令來創建用戶:

CREATE USER zhisheng WITH PASSWORD '123456' WITH ALL PRIVILEGES

然後執行 show users; 命令查看創建的用戶,操作運行的結果如下圖所示。

對 InfluxDB 開啓身份驗證,編輯 InfluxDB 配置文件 /etc/influxdb/influxdb.conf ,將 auth-enabled 設置爲 true。然後重啓 InfluxDB,再次使用 influx 命令進入的話,這時候查看用戶或者數據的話,就會報異常(需要使用用戶名和密碼認證登錄),異常完整信息如下圖所示。

這時需要使用下面命令的命令才能夠登錄:

influx -username  zhisheng -password 123456

重新登錄就能查詢到用戶和數據了,查詢到的結果如下圖所示。

然後創建一個叫 zhisheng 的數據庫,後面會將 Flink 中的監控數據全部存儲到該數據庫下,創建後可以查詢到該數據庫,效果如下圖所示。

安裝 Grafana

Grafana 是一款優秀的圖表可視化組件,它擁有超多酷炫的圖表,並支持自定義配置,用它來做監控的 Dashboard 簡直特別完美。

1、下載

wget https://dl.grafana.com/oss/release/grafana-6.3.6-1.x86_64.rpm

2、安裝

yum localinstall grafana-6.3.6-1.x86_64.rpm

安裝完成後的效果如下圖所示:

3、啓停 Grafana

//啓動 Grafana
systemctl start grafana-server
//停止 Grafana
systemctl stop grafana-server
//重啓 Grafana
systemctl restart grafana-server
//設置開機自啓動
systemctl enable grafana-server

然後訪問 http://54tianzhisheng.cn:3000 就可以登錄了。第一次登錄的默認賬號密碼是 admin/admin,會提示修改密碼。

配置 Grafana 展示監控數據

登錄 Grafana 後,需要配置數據源,Grafana 支持的數據源有很多,比如 InfluxDB、Prometheus 等,選擇不同的數據源都可以繪製出很酷炫的圖表,如果你公司有使用 Prometheus 做監控系統的,那麼可以選擇 Prometheus 作爲數據源,這裏演示就選擇 InfluxDB,然後填寫 InfluxDB 的地址和用戶名密碼,操作步驟如下圖所示。

配置好數據源之後,接下來就是要根據數據源來添加數據圖表,因爲構造數據圖表首先得知道有哪些指標,所以這裏先看下分別有哪些指標,這裏分 JobManager、TaskManager 和 Job 三大類。具體有哪些指標其實是可以根據 InfluxDB 裏面的 measurements 來查看的,我在 GitHub 放了一份完整的 measurements 列表 以供大家查閱,在 8.1.4 和 8.2.1 節中也都講解了比較關心的指標,這裏展示下如何在 Grafana 中根據這些指標來配置可視化圖表。

1、添加圖表

2、配置圖表從哪個數據源獲取數據、選擇哪種指標、選擇分組、選擇單位、添加多個指標、圖表命名

從哪個數據源獲取數據、選擇哪種指標、選擇分組
選擇單位
圖表命名

3、配置告警

這樣一個完整的監控圖表就配置出來了,有些指標可能直接用數字展示就比較友好,另外還有就是要注意單位,大家可以好好琢磨研究一下 Grafana 的自定義可視化圖表的配置,配置好了比較重要的監控指標之後,JobManager 和 TaskManager 的效果分別如下兩圖所示。

好了,一個 Flink 的監控系統已經完全搭建好了,從數據採集、數據存儲、數據展示、告警整個鏈路都支持,可以適應大部分公司的場景了,如果還需要做更多的定製化,比如添加更多的監控指標,那麼你可以在你的 Job 裏面自定義 metrics 做埋點,然後還是通過 reporter 進行數據上報,最後依舊用 Grafana 配置圖表展示。

小結與反思

本節講了如何利用 API 去獲取監控數據,對 Metrics 的類型進行介紹,然後還介紹了怎麼利用 Reporter 去將 Metrics 數據進行上報,並通過 InfluxDB + Grafana 搭建了一套 Flink 的監控系統。另外你還可以根據公司的需要使用其他的存儲方案來存儲監控數據,Grafana 也支持不同的數據源,你們公司的監控系統架構是怎麼樣的,是否可以直接接入這套監控系統?




基於 Apache Flink 的實時監控告警系統關於數據中臺的深度思考與總結(乾乾貨)日誌收集Agent,陰暗潮溼的地底世界
2020 繼續踏踏實實的做好自己

公衆號(zhisheng)裏回覆 面經、ES、Flink、 Spring、Java、Kafka、監控 等關鍵字可以查看更多關鍵字對應的文章。

你點的每個贊,我都當成了喜歡
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章