Elasticsearch X-Pack 系列之 Machine Learning 解析
- 2019 年 10 月 8 日
- 筆記
提示:公眾號展示代碼會自動折行,建議橫屏閱讀
1 背景
目前騰訊雲 CES(Cloud Elasticsearch)支持了多項商業特性,例如基於角色的訪問控制權限(RBAC Security)、機器學習(ML)、跨集群複製(CCR)、應用性能監控(APM)等。為了更好的給用戶提供更多 CES 底層技術支持以及和社區共同優化 ES 產品,騰訊雲 ES 內核團隊將逐一為大家介紹並解析相關的商業特性功能。本文將從功能、架構、源碼層面給大家介紹 X-Pack 的機器學習功能。
2 基本概念
2.1 機器學習分類
機器學習總體分為有監督學習和無監督學習兩類。
- 有監督學習先對數據集打標籤,從有標記的訓練數據中推導出預測函數(模型),有一個訓練的過程,比如打上高富帥標籤的人找對象容易,打上矮矬窮的人找對象相對困難,有這麼一個模型就可以去預測有這些特徵數據的人找對象成功的概率。
- 無監督學習不會先對數據進行標記,也沒有提前訓練的過程,它從無標記的訓練數據中推導出結論。最典型的是聚類分析,將已有數據集按照其自身的規律進行分組歸類。比如對不同顏色、形狀的物體自動分類。
2.2 ES 中的機器學習
Elastic 公司 2016 年收購了一家基於機器學習做異常檢查分析(Anomaly Detection Analytics)的公司 Prelert,將機器學習功能整合進了 X-Pack 商業套件。上面介紹了有監督和無監督學習,對時序數據例如日誌、監控數據等進行異常檢查、預測屬於無監督學習,不需要對數據進行提前標記,自動探索數據隨着時間推移的規律。X-Pack Machine Learning 目前主要是利用無監督式機器學習,提供時間序列異常檢查、預測功能。以往我們的監控都是通過配置一個固定的閾值,到達閾值就告警來實現的,這種方式太粗,無法捕捉到某個趨勢上的異常值,而時間序列預測能做到更細粒度、更準確的異常檢查、監控。
本文將重點介紹如何使用 X-Pack 的機器學習功能,以及剖析 ES 底層是如何整合運作的,而機器學習的算法將不做重點討論。
3 功能介紹
我們先來看一個來自官方的簡短動畫演示:

這個示例創建了一個機器學習的任務自動分析某類時序數據的異常值。單一的趨勢線條為原始的數據,陰影部分為預測模型,代表各個時間點的正常值上下範圍,超出範圍為異常值,偏差越大異常越明顯,即動畫中黃色、紅色部分。
接下來我們介紹創建機器學習任務的過程,對某 web 應用的請求響應指標進行分析。
3.1 數據準備
導入 ES 示例數據 server-metrics。示例數據來自官方,約 9 萬條服務請求響應統計數據,共計 80MB 左右。
數據下載地址:https://download.elastic.co/demos/machine_learning/gettingstarted/server_metrics.tar.gz
數據示例如下:
{ "_index" : "server-metrics", "_type" : "metric", "_id" : "272961", "_score" : 1.0, "_source" : { "@timestamp" : "2017-04-01T12:42:00", // 時間字段,時間序列預測必須有的字段 "accept" : 11922, // 某段時間接受的請求量 "deny" : 1923, // 某段時間拒絕的請求量 "host" : "server_1", // 某主機 "response" : 2.4755486712, // 某段時間平響 "service" : "app_4", // 某應用 "total" : 13845 // 接受和拒絕的總請求量 } }
3.2 查看數據分佈
導入數據之後,在 kibana 上建好 index-pattern,就可以通過 Machine Learning 的 Data Visualizer 功能查看數據的分佈情況:

數據量大時,可以通過 Sample 下拉列表調整沒個分片數據抽取比例。
該功能可以讓用戶很方便的了解數據的分佈情況、字段的分佈情況等,便於稍後創建機器學習任務時選擇合適的字段、方法。
3.3 創建機器學習任務
kibana 上跳轉到 Job Management 頁面,點擊右上角 Create New Job 按鈕,選擇剛建好的 index-pattern,開始選擇建哪一類別的任務:

以上幾類任務的區別:
- Single metric:
單指標任務,比如想單純的分析一下平均響應時間的異常情況。
- Multi metric:
多指標任務,比如可以將拒絕和接受的請求數量一起分析,且可以按照某個維度切分,例如按照主機維度或者應用維度切分,後續查看結果就可以單獨看某個主機上或者某個應用的異常情況。多指標時,同時可以添加影響者(influencers),例如維度上按照應用切分了,可能同時向看一下這個維度上某些主機上的異常分佈是否有什麼特徵或關聯影響。
- Population
種群分析任務,前面的單指標、多指標都是分析某個維度隨着時間序列的推移,不同時間序列上對比出來的異常值。而總群分析主要是分析某個指標的某個維度和該維度其它種類的差異。例如針對某應用的平均響應時間,可以分析是否個別主機的響應時間比其它主機長。
- Advanced
創建任務需要更多可自定義的選項可以使用 Advanced 類別,裏面提供更多的分析配置,包括數據預聚合、分類,自定義 detector、datafeed 選項等。detector、datafeed 概念架構解析中詳細介紹。
接下來我們分別看一下上述各任務如何創建。
- 單指標任務。例如分析平均響應時間異常值:

上面紅色方框中有三個參數:
Aggregation:指定分析用到的聚合函數。例如求平均值為 mean。分析函數有很多種,主要包括 count(計數,low_count、high_count、distinct)、sum(求和)、metric(指標,min、max、mean)等。count 分為 count、high_count、low_count,區別是 count 統計異常高或者異常低的值,後兩者只統計其中一種。詳細參考官方文檔:https://www.elastic.co/guide/en/elastic-stack-overview/current/ml-functions.html
Field:選擇被統計的目標字段。
Bucket span:時序數據分析會將數據按照固定大小的時間窗口切分,分批分析建模,一般設置為 5 分鐘到 1 小時,具體看數據的分佈情況,可以通過上述 Data Visualizer 來查看數據分佈,也可以藉助後面的 Estimate bucket span 協助評估。
接下來給任務指定一個 ID 及描述,Advance 裏面還可以指定任務結果輸出的索引,默認是輸出到 .ml-anomalies*,可以指定不同的,以及可以指定模型最大內存消耗。
最後點擊 Create Job 創建任務,kibana 上就可以看到類似上面動畫的機器學習動態建模分析時序數據的過程。
查看任務執行結果,跳轉到 Single Metric Viewer 頁面,選擇對應的 Job 查看結果:

也可以直接看錶格化的數據,默認按嚴重程度排序:

紅框中 actual 為異常點真實值,typical 為在這個時間點上應該有的預估正常值,probability 為出現這個異常值的概率,偏差越大的概率越低。
- 多指標任務。例如同時分析各應用接受和拒絕的平均請求數量,同時考慮主機差異的影響:

查看結果,跳轉到 Anomaly Explorer 頁面:

Top Influencers:各維度 Top 異常列表排名,最高分及總分。Influencers 一般是你認為異常值一般和哪個維度有直接關聯,比如不同的主機請求數量可能存在較大差異等,一般維度不建議超過 3 個,太多會有性能消耗。
Anomaly timeline:時間序列上的異常分佈。
View by:可以選擇按照應用、主機維度查看。
Anomalies:異常表格,默認按嚴重程度排序。可以看到異常最嚴重的是 app_4,超出正常值幾十倍。
還可以通過點擊某一個維度,某個時間範圍上的異常值查看異常詳情:

- 種群分析。例如分析各主機拒絕率異常分佈,並添加應用維度分析:

查看結果,可以看到 server_1 上平均拒絕數最高,且主要是 app_4,超出了正常值 21 倍:

- 預測。例如對前面單指標任務,平均響應時間的預測:
跳到 Single Metric Viewer 頁面,選 mean_respose Job,點右上角的 Forecast,例如預測未來 3 天的趨勢:

點擊 Run,就可以得到預測結果:

預測的時間越長,越靠後的結果越不準確。
在有數據持續輸入的場景,機器學習任務可以持續不斷的運行,實時監測,另外機器學習任務還可以添加特殊事件,例如某些特定的節假日業務量可能有可預期的異常波動,可以提前設置一些規則避免異常誤報。
機器學習的功能可以通過 Kibana 頁面配置,也可以直接通過 ES 提供的 rest API 操作。詳細可操作相關官方接口文檔。https://www.elastic.co/guide/en/elasticsearch/reference/current/ml-apis.html
到這裡 ES X-Pack 機器學習的基本功能就介紹完了,接下來我們看看底層是如何運行的。
4 架構解析
Machine Learning 模塊包含任務(Jobs)、數據輸入(Datafeeds)、探測器(Detectors)等重要組件。
4.1 關鍵組件
- 任務(Jobs)
任務包含用戶輸入的配置信息,以及分析任務必要的元數據信息,會被持久化到 ES 的元數據(metadata)中。任務有階段性狀態,包括創建完畢開啟中(OPENING)、已開啟(OPENED)、關閉中(CLOSING)、已關閉(CLOSED)、失敗(FAILED)等。這些狀態決定了該任務的數據輸入、探測器的工作模式。
機器學習的功能可以通過節點級別配置項 xpack.ml.enabled 開啟或關閉,node.ml 配置項可以控制節點是否為機器學習節點。任務只會下發到機器學習節點。任務執行的目標機器學習節點是根據節點上的任務數、負載情況來衡量的,同一時間點一個任務只會在一個節點上執行,如果節點掛掉則會切換到其它機器學習節點,因為元數據有階段性保存,可以保證任務無縫切換。
- 數據輸入(Datafeeds)
機器學習的任務分析的數據可以來自存儲在 ES 中的數據,也可以來自外部。如果分析存儲在 ES 中的數據,則可以通過配置 index pattern 的方式設置 datafeeds 指定提取哪些數據分析,datafeeds 有啟停開關,也可以設置運行時間,也可以持續不斷的運行,適合時序數據的持續分析預測。如果數據來自 ES 外部,則不能直接使用 datafeeds,需要通過 ES 提供的 post data to Job API 來將數據送給機器學習任務。
- 探測器(Detectors)
探測器為承載機器學習建模分析的主要模塊,它負責對 datafeeds 送過來的數據進行實時建模分析處理,它提供多種簡單的算法封裝。同時我們還可以為 detectors 添加一些自定義的規則,例如單純的分析 CPU 使用率趨勢可能在整體使用率很低的時候也會探測出較低的異常值,而我們往往只關心使用率較高的異常,此時就可以添加一些過濾規則,詳細可以參考官方文檔 https://www.elastic.co/guide/en/elastic-stack-overview/7.2/ml-configuring-detector-custom-rules.html。
這個模塊為運行在 ES 進程之外的一組獨立的 C++ 進程,ES 調度到的主要包括 autodetect 建模分析進程;normalize 歸一化處理進程等。它們在 ES 的 ./modules/x-pack-ml/platform/linux-x86_64/bin 目錄下。該部分代碼暫時未開源。
4.2 數據流
下面我們用一個架構圖來看看上述幾個模塊之間的關係以及數據流:

架構圖中主要分為兩條數據流,數據發送流和結果輸出流:
- 數據發送流
Datafeeds 模塊從 ES index 中提取待分析的數據,調用 postData API 將數據通過命名管道發送給 detector 程序。ES 外部數據也可以通過 postData API 將數據發送給 detector 程序,該 API 內部實現是通過向一個 C++ 創建的命名管道寫入數據實現進程間的通信。Detector 進程會不斷的讀取命名管道的數據進行實時建模分析。
- 結果輸出流
Detector 進程將分析好的結果,包括模型、分析結果等寫入命名管道,ES 這邊 result 解析器不斷的將結果解析並存儲到結果索引中。同時 ES 也會不斷的解析 detector 進程輸出到命名管道的日誌,並打印到 ES 日誌中。
上述數據發送、結果輸出、日誌輸出等相關的管道文件在啟動 detector 進程時就約定好了,這些管道文件由 detector 進程創建,ES 進程讀寫。啟動示例:
./autodetect, --jobid=test1, --bucketspan=900, --summarycountfield=doc_count, --lengthEncodedInput, --maxAnomalyRecords=500, --timefield=@timestamp, --persistInterval=10000, --maxQuantileInterval=20000, --limitconfig=C:UsersDANIEL1AppDataLocalTemplimitconfig.conf, --modelplotconfig=C:UsersDANIEL1AppDataLocalTempmodelplotconfig.conf, --fieldconfig=C:UsersDANIEL~1AppDataLocalTempfieldconfig.conf, --logPipe =.pipeautodetect_test1_log, --input =.pipeautodetect_test1_input, --inputIsPipe, --output =.pipeautodetect_test1_output, --outputIsPipe, --persist=.pipeautodetect_test1_persist, --persistIsPipe
4.3 結果數據
機器學習任務最終會產生多個索引文件,存放不同的結果數據。下面我們來看看每個 ml 索引對應的內容:
- .ml-config
存放每個任務的配置信息。示例數據:
{ "job_id" : "mean_response", "job_type" : "anomaly_detector", "job_version" : "7.1.1", "description" : "mean response metric analysis", "create_time" : 1563714352001, "analysis_config" : { "bucket_span" : "15m", "summary_count_field_name" : "doc_count", "detectors" : [ { "detector_description" : "mean(response)", "function" : "mean", "field_name" : "response", "detector_index" : 0 } ], "influencers" : [ ] }, "analysis_limits" : { "model_memory_limit" : "10mb", "categorization_examples_limit" : 4 }, "data_description" : { "time_field" : "@timestamp", "time_format" : "epoch_ms" }, "model_plot_config" : { "enabled" : true }, "model_snapshot_retention_days" : 1, "custom_settings" : { "created_by" : "single-metric-wizard" }, "model_snapshot_id" : "1563714356", "results_index_name" : "shared", "finished_time" : "2019-07-23T01:19:25.072Z" } }
- .ml-anomalies-*
機器學習結果數據,包含每個 bucket span 內的模型邊界、異常評分數據等,前面描述的示例中陰影部分的模型圖片就是通過這個模型邊界畫出來的,不同顏色的異常值就是通過評分數據標識的。示例數據如下:
{ "_index" : ".ml-anomalies-shared", "_type" : "_doc", "_id" : "mean_response_model_plot_1490334300000_900_0_29791_0", "_score" : 1.0, "_source" : { "job_id" : "mean_response", "result_type" : "model_plot", "bucket_span" : 900, "detector_index" : 0, "timestamp" : 1490334300000, "model_feature" : "'arithmetic mean value by person'", "model_lower" : 2.2150513973399844, "model_upper" : 2.3863666767284384, "model_median" : 2.2995698482083644, "actual" : 2.2488529795692083 } }, { "_index" : ".ml-anomalies-shared", "_type" : "_doc", "_id" : "mean_response_bucket_1490334300000_900", "_score" : 1.0, "_source" : { "job_id" : "mean_response", "timestamp" : 1490334300000, "anomaly_score" : 0.0, "bucket_span" : 900, "initial_anomaly_score" : 0.0, "event_count" : 315, "is_interim" : false, "bucket_influencers" : [ ], "processing_time_ms" : 0, "result_type" : "bucket" } }
- .ml-state
每個機器學習任務產生的模型相關數據(model snapshot),壓縮存儲。便於後續任務重新啟動復用模型。
- .ml-notifications
機器學習任務相關的流程信息,任務的每個階段都會記錄。示例如下:
{ "_index" : ".ml-notifications", "_type" : "_doc", "_id" : "7m3pAmwBlYUidNP4p7KI", "_score" : 1.0, "_source" : { "job_id" : "test", "message" : "Starting datafeed [datafeed-test] on node [{node-1}{E4OOm81JSqqrcwPxvu2Wtw}{uer7q190Smq2W9e5XiXXQw}{localhost}{127.0.0.1:9300}{ml.machine_memory=8235999232, xpack.installed=true, ml.max_open_jobs=20}]", "level" : "info", "timestamp" : 1563416962952, "node_name" : "node-1" } }
- .ml-annotations-*
機器學習異常數據的註解信息,對異常數據做一些備註時使用,在 kibana 上可以添加、展示註解。示例數據如下:
{ "_index" : ".ml-annotations-6", "_type" : "_doc", "_id" : "Ocb_B2wBYO4WarXTOCEI", "_score" : 1.0, "_source" : { "timestamp" : 1492184042462, "end_timestamp" : 1492184853679, "annotation" : "some machine problems", "job_id" : "test2", "type" : "annotation", "create_time" : 1563502262245, "create_username" : "elastic", "modified_time" : 1563502262245, "modified_username" : "elastic" } }
4.4 源碼分析
最後我們結合一個機器學習的任務流程,對源碼做一些流程上的分析,這裡僅將代碼流程做一個簡單的梳理分析,有興趣的同學可以進一步結合源碼看看更細節的邏輯。下面流程中紅色箭頭的流程是隨着數據持續輸入而不斷循環處理的。

5 總結
本文從功能演示、架構、源碼解析等維度對 Elasticsearch X-Pack 的機器學習特性進行了描述,內容主要參考官方文檔以及源碼,有不太準確的地方歡迎大家討論指正。

騰訊數據庫技術團隊對內支持QQ空間、微信紅包、騰訊廣告、騰訊音樂、騰訊新聞等公司自研業務,對外在騰訊雲上支持TencentDB相關產品,如CynosDB、CDB、CTSDB、CMongo等。騰訊數據庫技術團隊專註於持續優化數據庫內核和架構能力,提升數據庫性能和穩定性,為騰訊自研業務和騰訊雲客戶提供「省心、放心」的數據庫服務。此公眾號和廣大數據庫技術愛好者一起,推廣和分享數據庫領域專業知識,希望對大家有所幫助。