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等。腾讯数据库技术团队专注于持续优化数据库内核和架构能力,提升数据库性能和稳定性,为腾讯自研业务和腾讯云客户提供“省心、放心”的数据库服务。此公众号和广大数据库技术爱好者一起,推广和分享数据库领域专业知识,希望对大家有所帮助。