Ambari Metrics 原理
Ambari Metrics System 簡稱為 AMS,它主要為系統管理員提供了集群性能的監察功能。Metrics 一般分為 Cluster、Host 以及 Service 三個層級。
Cluster 和 Host 級主要負責監察集群機器相關的性能,而 Service 級別則負責 Host Component 的性能。AMS 涉及的模塊如下圖所示:
圖 1. Ambari Metrics 原理圖
對於 AMS 本身來說,涉及的主要模塊有 Metrics Monitor、Hadoop Sinks 以及 Metrics Collector。
AMS 也是一個 Master-Slave 結構的框架。Master 模塊便是 Metrics Collector,Slave 則是 Metrics Monitor 和 Hadoop Sinks。Salve 模塊負責收集信息,並發送給 Collector。
當然 Metrics Monitor 和 Hadoop Sinks 也有不同的職責,前者主要負責收集機器本身相關的指標,例如 CPU、Mem、Disk 等;
后者則負責收集 Hadoop 相關 Service 模塊的性能數據,例如該模塊占用了多少 Mem,以及該模塊的 CPU 占用率等。
在 Ambari 2.1 之后的版本中(包含 2.1)支持了配置化 Widget 的功能。
Widget 也就是 Ambari Web 中呈現 Metrics 的圖控件,它會根據 Metrics 的數值,做出一個簡單的聚合運算,最終呈現在圖控件中。
AMS 會不斷的收集集群相關的性能數據,並最終由 Metrics Collector 中的 Timeline Server 保存到 Hbase 數據庫中(通過 Phoenix)。
隨着時間的推移,Metrics 數據會變得非常龐大,因此 Metrics Collector 支持兩種存儲模式,Embedded Mode(嵌入模式)和 Distributed Mode(分布式模式)。
簡單來說,對於在嵌入模式中,Hbase 會以本地文件系統作為存儲層,而在分布式模式中,Hbase 則以 HDFS 作為存儲層。
這樣就可以充分利用整個集群的物理存儲了。不過目前 AMS 並不支持自動化的數據遷移,也就是說當用戶從嵌入模式遷向分布式模式的時候,無法自動的完成 HBase 的數據導出導入。
慶幸的是,我們可以通過簡單的 HDFS CLI 命令,將整個 Hbase 數據目錄從本地拷貝到 HDFS 中,從而完成 Metrics 數據遷移。
這里我們還需要注意,如果 AMS 要以分布式模式運行,那么 Metrics Collector 所在的機器必須部署一個 HDFS 的 Data Node 模塊。
Ambari Widget
Ambari Widget 的出現進一步提升了 Ambari 的易用性,以及可配置化。之前我們已經講過 Widget 控件的用途,也就是顯示 AMS 收集的 Metrics 屬性。
不過 Ambari 目前只支持在 Service Summary 頁面定制化 Widget 組件。Ambari Widget 主要分為四類:Graph、Gauge、Number 以及 Template,其中前三者較為常用。
Graph 是一種線性或矩形圖,它用於顯示在某時間內 Service 的某個(可以是多個)Metrics 屬性值。效果如下圖(5 種 Graph 圖):
圖 2. Graph 效果圖
Gauge 一般用於顯示百分比,其數值來源於一個(可以是多個)Metrics 經過計算后的值(小於 1)。其效果如下圖:
圖 3. Gauge 示例圖
Number 則用於直接的顯示一個數值,並可以為其配置一個單位,例如 MB 等。其所顯示的數值也是來源於一個或多個 Metrics 屬性。
由於 Widget 只支持對 Service Summary 的定制,也就是說 Widget 只支持對 Service Component Metrics 屬性的定制。
然而同一個 Service 的 Component 可以由多個 Host Component 組成,那么 Widget 就必須經過某一種聚合運算才可以得到一個數值。
Ambari 為 Widget 組件提供了 4 中聚合方式,分別是 max、min、avg、sum。
簡單來說:max 就是 Host Component 收集的同個 metrics 屬性的最大值;min 是最小值;avg 是平均值;sum 則是求和。Widget 組件會以 avg 為默認的聚合方式。用戶可以在 widget 的配置文件中重寫該方式。
Ambari 中預定義的 Metrics 和 Widget
在詳細介紹具體的預定義之前,我們先看下 Ambari Web 中相關的頁面。首先便是 Cluster Dashboard 中所顯示的 Metrics Widget 控件,這些便是所謂的 Cluster 級 Metrics,如圖 4。
圖 4. Cluster 級 Metrics
在機器的 Component 頁面中,我們便可以看到該機器相關的 Metrics 信息。並且,用戶可以在一部分 Service 的 Summary 頁面中可以看到該 Service 相關的 Metrics 信息。
目前,Ambari 只為 YARN、HDFS 以及 Ambari Metrics 等部分 Service 預定義了 Metrics 和 Widget 信息。
這里我們就以 YARN 為例,看看如何為一個 Service 定義 Ambari 的 Metrics 和 Widgets。首先我們先看下 Ambari Server 上 HDFS 的目錄結構,如圖 5。
圖 5. HDFS 的目錄結構
在目錄結構中,我們可以看到 metrics.json 和 widgets.json 這兩個文件。在 Ambari 的 Web 上部署一個 Service 的時候,Ambari Server 就會讀取這兩個 JSON 文件中的定義。
對於 HDFS 來說,其 Metrics 和 Widget 的配置相當豐富和繁雜,因而這里我們只簡單的看下這兩個文件中的一小段。
這里我們先在 Ambari Web 中打開 HDFS 的 Summary 頁面,並觀察名為 NameNode Heap 的控件,如圖 6(這是一個摘要圖,可以點擊該圖,進而查看詳細圖)。
圖 6. NameNode Heap 摘要圖
顧名思義,我們可以了解該圖是為了記錄 NameNode 進程堆內存的使用情況。那么在 AMS 系統中,就必然有一個模塊負責收集該信息並發送給 Metrics Collector。
最后便需要定義一個這樣的圖控件,來讀取和顯示收集到的 Metrics 信息。如下便是該 Widget 的定義內容:
清單 1.NameNode Heap 的定義(widget.json)
{ "widget_name": "NameNode Heap", "description": "Heap memory committed and Heap memory used with respect to time.", "widget_type": "GRAPH", "is_visible": true, "metrics": [ { "name": "jvm.JvmMetrics.MemHeapCommittedM", "metric_path": "metrics/jvm/memHeapCommittedM", "service_name": "HDFS", "component_name": "NAMENODE", "host_component_criteria": "host_components/metrics/dfs/FSNamesystem/HAState=active" }, { "name": "jvm.JvmMetrics.MemHeapUsedM", "metric_path": "metrics/jvm/memHeapUsedM", "service_name": "HDFS", "component_name": "NAMENODE", "host_component_criteria": "host_components/metrics/dfs/FSNamesystem/HAState=active" } ], "values": [ { "name": "JVM heap committed", "value": "${jvm.JvmMetrics.MemHeapCommittedM}" }, { "name": "JVM heap used", "value": "${jvm.JvmMetrics.MemHeapUsedM}" } ], "properties": { "display_unit": "MB", "graph_type": "LINE", "time_range": "1" } }
如上的配置代碼主要由 4 部分組成,分別是 widget 控件的描述內容、metrics 的匹配關系、value 的計算以及控件圖的顯示屬性。
例如最開始的幾行中配置了該 widget 的名稱為“NameNode Heap”以及 Description 信息。widget_type 則用於定義該圖的類型,這里是 Graph。
is_visible 用於配置該圖是否可見。metrics 段就是配置 widget 組件所綁定的 metrics 屬性。
在如上的代碼中,widget 綁定了 jvm.JvmMetrics.MemHeapCommittedM 和 jvm.JvmMetrics.MemHeapUsedM 兩個 metrics 屬性。
values 段則定義如何使用綁定的 metrics 屬性值。Name 用於顯示圖中該屬性的名稱,value 則是一個數學表達式,定義如何使用(計算,例如加減乘除)metric 值。
如上代碼中的定義,表示直接使用 metric 值,並未經過計算。properties 段則定義了該 Graph 圖的屬性。display_unit 定義了顯示的單位(也可以用“%”等符號作為單位)。
graph_type 定義了 Graph 圖的類型,可以是 LINE(線形圖)或 STACK(矩形圖)。time_range 則為取樣時間。下圖則為 NameNode Heap 的示例圖(詳細圖)。
圖 7. NameNode Heap 詳細圖
在清單 1 中,我們講解了 HDFS widget.json 的一段配置代碼,下面來讓我們再找到對應的 Metrics 配置代碼。
首先我們打開 HDFS 的 metrics.json,並分別搜索字符串“jvm.JvmMetrics.MemHeapUsedM”和“jvm.JvmMetrics.MemHeapCommittedM”找到如下的示例代碼(我已將兩段黏貼在一起):
清單 2.metrics.json
{ "NAMENODE": { "Component": [ { "type": "ganglia", "metrics": { "default": { "metrics/jvm/memHeapUsedM": { "metric": "jvm.JvmMetrics.MemHeapUsedM", "unit": "MB", "pointInTime": false, "temporal": true }, "metrics/jvm/memHeapCommittedM": { "metric": "jvm.JvmMetrics.MemHeapCommittedM", "unit": "MB", "pointInTime": true, "temporal": true } } } }] } }
我們可以從如上的代碼中看到該 Metrics 的屬性是為 HDFS 的 Namenode 配置的。在 type 一項,配置了該 metrics 請求的實現類型。
了解過 ganglia 的讀者,應該知道 ganglia 也是 Apache 下面的一個開源框架,其目的就是為了實現集群性能的監控,這里就不再贅述了。
在 metrics 的字段中,則詳細定義了每個 metrics 的屬性。代碼中“metrics/jvm/memHeapUsedM”和“metrics/jvm/memHeapCommittedM”都是 metrics 的 key,這個 key 對一個 service 來說是唯一的,用於唯一鑒別一個 metric 請求。
metric 定義了名稱,unit 則是單位。pointInTime 表示該 Metric 屬性是否允許時間段的查詢,如果為 false 則代表不允許,這樣就會只取最后一次的值。
Temporal 代表是否支持時間段的查詢請求,這里一般都是 true。因為 Widget 配置有 time range 的屬性,如果 temporal 是 false,widget 組件則無法顯示任何數據。
如何為第三方 Service 增加 Metrics 和 Widgets
Ambari 現在已經支持高度的可配置化,對於 Metrics 和 Widget 來說,我們先需要簡單的配置相關的 metrics.json 以及 widget.json。
這里我以一個示例 Sample Service 作為講解(Ambari 版本為 2.2,HDP Stack 為 2.3)。我們先看下 Sample 的目錄結構,如下圖。
圖 8. 示例 Sample 目錄結構
這里我為 Sample Service 增加了 metrics.json 以及 widgets.json。在控制腳本 master.py 中只簡單的定義了相關的控制函數,並沒有真實的邏輯代碼。示例 Sample 的 metainfo.xml 代碼如下:
清單 3.Sample Service 的 metainfo.xml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
|
|
這里需要注意字段 timelineAppId,該值是唯一的,一般用 Service Name 即可,並且不區分大小寫。Metrics Collector 中的 Tmeline Server 會通過 timelineAppid 區分各個模塊的 Metrics 信息。Sample 中,我就使用 sample 作為 app id 即可。具體的 Metrics 定義如下:
清單 4.Sample 的 metrics.json
<metainfo> <schemaVersion>2.0</schemaVersion> <services> <service> <name>SAMPLE</name> <displayName>my sample</displayName> <comment>Service definition for sample</comment> <version>1.0</version> <components> <component> <name>MY_MASTER</name> <displayName>My Master</displayName> <category>MASTER</category> <cardinality>1</cardinality> <timelineAppid>sample</timelineAppid> <commandScript> <script>scripts/master.py</script> <scriptType>PYTHON</scriptType> <timeout>600</timeout> </commandScript> </component> </components> <osSpecifics> <osSpecific> <osFamily>any</osFamily> </osSpecific> </osSpecifics> </service> </services> </metainfo>
如上的代碼為 Sample 的 Master 模塊配置了 4 項 metric 屬性:test1、test2、test3 以及 test4。然后又通過如下的 widget.json,預定義了一個 Graph 類型的的線性圖。具體代碼如下:
清單 5.Sample 的 widget.json
{ "layouts": [ { "layout_name": "default_sample_dashboard", "display_name": "Standard TEST Dashboard", "section_name": "SAMPLE_SUMMARY", "widgetLayoutInfo": [ { "widget_name": "test_widget", "description": "test widget", "widget_type": "GRAPH", "is_visible": true, "metrics": [ { "name": "test1", "metric_path": "metrics/test1", "service_name": "SAMPLE", "component_name": "MY_MASTER" } ], "values": [ { "name": "test1", "value": "${test1}" } ], "properties": { "graph_type": "LINE", "time_range": "1" } } ] } ] }
從以上的代碼中,我們看到該 Widget 綁定了 Metrics 中的 test1,並直接使用 test1 的值作為其 value 屬性。之后我們可以從 Ambari Web 中部署這個 Sample Service 到 Ambari 集群。安裝完成之后,我們便可以看到如下的 Service Summary 界面:
圖 9. Sample Service Summary 界面
到此,我們就已經看到了預定義的 test_widget 控件。或許大家會好奇,為什么控件會顯示沒有可用的數據。很簡單,因為我們並沒有為該 Sample Service 實現收集與發送 Metrics 數據的模塊。
第一小節中我們已經介紹過,AMS 中有 Metrics Monitor 以及 Hadoop Sinks 收集相關的 Metrics 數據,但這些並不會服務於第三方服務。
HDFS Service 之所以可以看到相關的 Widget 數據,也是因為 Ambari 為其實現了對應 Hadoop Sinks。
簡單點說,Hadoop Sink 就是一個 jar 包,其 Java 代碼中會實現一個 HTPP Client 的線程,定期的收集和發送相關的數據。
而 Metrics Monitor 也是 Ambari 在后台通過 Shell 腳本啟動的一個 Python 進程,其通過 url 類庫實現了 HTPP 的 Client,定期向 Collector 發送數據。
這里我用一個簡單的 Shell 腳本完成類似的功能,示例代碼如下。
清單 6. 發送 Metrics 數據的腳本 (metric_sender.sh)
#!/bin/sh url=http://$1:6188/ws/v1/timeline/metrics while [ 1 ] do millon_time=$(( $(date +%s%N) / 1000000 )) random=`expr $RANDOM % 10` json="{ \"metrics\": [ { \"metricname\": \"$2\", \"appid\": \"$3\", \"hostname\": \"localhost\", \"timestamp\": ${millon_time}, \"starttime\": ${millon_time}, \"metrics\": { \"${millon_time}\": ${random} } } ] }" echo $json |tee -a /root/my_metric.log curl -i -X POST -H "Content-Type: application/json" -d "${json}" ${url} sleep 5 done
運行如下命令(這里一定要注意參數 1 是 Metrics Collector 的所在機器,並不是 Ambari Server):
./metric_sender.sh ambari_collector_host test1 sample
上面的代碼以 5 秒為間隔,向 Metrics Collector 發送一個隨機數作為 test1 的 metrics 屬性值,命令的發送是由 curl 實現的。
另外讀者也可以使用 Firefox 的 Poster 工具進行測試。如果使用 curl 命令完成該功能,需要注意-H 參數的使用。
當該命令運行一段時間之后,我們就可以在 Summary 頁面看到 Widget 的圖樣,點開詳細的數據圖如下:
圖 10. Test_widget 示例圖
通過以上的努力,我們就成功的為 Sample Service 定制了 test1 的 metrics 屬性,並由 test_widget 動態的顯示該屬性的變化情況,從而可以很大程度的方便系統管理員完成相關的監測工作。
我們可以回頭再看下 Sample Service 的 metrics.json,其中我們定義了 4 個 metrics 屬性,然而我們只有一個 widget 組件調用了一個 Metrics 屬性。
可能有的讀者會覺得不合理,我之所以這么定義,是想舉例在現實的環境中,第三方服務可以詳盡的定義更多的 Metrics 屬性,而系統管理員可以有選擇的監測一些關鍵屬性。
操作也很簡單(前提是該 Service 已經定義過 widget.json),只需要在 Service 的 Summary 頁面中選擇 Action -> Create Widget,然后選擇對應的 Metrics 屬性,並定義相關的數學表達式。
如下圖,定義了一個 Gauge 類的百分比圖,其用途是顯示 Test2(小於 10 的隨機數)除以 10 的數值(結果小與 1)。
並且 Warning 的閥值為 0.7,Error 的閥值為 0.9,也就是說當百分比大於 70%小於 90%,圖的顏色會變成黃色,大與 90%則會為紅色,綠色為正常色。
圖 11. 顯示 Test2 屬性的 Gauge 圖
圖 12. Summary 頁面效果圖
如何做 AMS 集成的 Trouble-shooting
通過 Log 機制
AMS 的系統並不復雜,與其集成的核心便在 Metrics Collector。如果遇到相關的問題,首先我們可以查看 Metrics Collector 和 Ambari Server 的日志。
在配置完 metrics.json 以及 widget.json 之后,成功部署 Service 之前,如果出現問題則大多只需要查看 Ambari Server 的 log 即可,大多問題都是兩個 json 的格式問題引起的。
成功部署之后,則大多只需查看 Metrics Collector 的日志。這里最好打開 Metrics Collector 的 DEBUG 級別 log。
這個需要在 AMS Service 的 Config 頁面找到 ams-log4j 段,並更改其中的 log4j.rootLogger 為 DEBUG 即可。
這里再次提醒下,Metrics Collector 不是 Ambari Server,它們可能不在一台機器上,有很多人一直在 Ambari Server 的機器查找 Metrics Collector 的日志。
Metrics Collector 的 Rest API
另外我們可以通過 Metrics Collector 的 Rest API 測試其是否正常。其 API 很簡單,且只支持 POST 和 GET 兩種請求。
POST 方法可以參考上小節腳本中的 curl 命令。GET 方法如下所示,我們可以獲取上小節 Sample 中的 test2 屬性值(這里也需要提醒下,Collector 上 Timeline Server 的 Web 端口默認為 6188,但有時候也會是 6189。
因此需要在 AMS 的 Config 頁面中找到 ams-site 配置欄,確認其端口)。
執行如下的命令:
curl -X GET http://xalin64sw8:6188/ws/v1/timeline/metrics?metricNames=test2&appid=sample
獲得如下輸出(最近一次的 Metrics 屬性值):
{"metrics":[{"timestamp":1457263674650,"metricname":"test2","appid":"sample","starttime":1457263674650,"metrics":{"1457263674650":7.875}}]}
通過 Phoenix 查詢 Hbase 數據庫
Phoenix 也是 Apache 下面一個知名的項目,其主要功能就是用於支持 Hbase 之上的 SQL 操作。有興趣的讀者也可以在 Phoenix 的官方網站了解其具體的內容。AMS 通過 Phoenix 在 Hbase 中創建了如下的八張表:
表 1. AMS 通過 Phoenix 創建的 Hbase 表格
如上,我們已經知道了相關的表格名稱,接着便可以通過 Phoenix 查詢對應的表格內容。下面的示例圖中使用是 phoenix 4.2.2 版本中的 sqlline 方式訪問 Hbase。通過查詢 Hbase 數據庫,我們可以知曉發送 Metrics 屬性的模塊是否正常。