在Elasticsearch中实现统计异常检测器——第二部分

Implementing a statistical anomaly detector in Elasticsearch - Part 2

  上一周,我们建立了一个pipeline聚合,将数千个数据点分解成少数代表性指标。 这形成了Atlas的基础,并且为实现异常检测器所做的所有重大工作。本周,我们将结束实施并生成一些有趣的图表。

  我们创建的聚合被设计为在特定的时间窗口上运行:给定日期范围,它将为每一个metric发出第90个百分点的意外(surprise)值。要完全实现Atlas,我们需要随着时间的推移绘制第90个百分点值。目前这个功能仅仅使用Pipeline聚合是不可能使用的(虽然已经提出了一种“滑动柱状图”功能来弥补差距)。

  替代的,我们将把责任移交给TimeLion,它非常适合这种后期处理(Timelion是一个新的{Re}search项目,在kibana内部进行流畅的时间序列操作,你可以在这里阅读更多)。

  

  假如你重新去看模拟器的代码,你将看到我们在数据生成之后运行了一查询系列 。我们以一小时的增加滑动我们的Pipeline聚合数据(窗口的大小为24小时)。我们还使用了filter_path来最小化输出,我们实际并不关心60,000个buckets。我们仅仅想要每个metric的“ninetieth_surprise”。过滤响应大大较少了网络传输。然后将值索引回Elasticsearch,以便我们稍后再对其进行统计。

  我们在模拟器中提前预处理了这些值,以简化演示,但在一个真实的系统中,你可能会有一个Watcher或者cronjob每小时执行一次查询并保存结果。

Plotting 90th percentile surprise

  通过上周的艰难举措,我们可以转而使用Timelion完成实施。第一个业务是降低特定指标的第90个值(the 90th values)。我们可以使用以下Timelion语法:

.es('metric:0', metric='avg:value').label("#0 90th surprise")

  它将生成看起来像这样的一张图表:

  

  那看起来很有趣!绝对有事情发生。我们来看看这张图表的含义,因为它是Atlas的工作原理:

  • 上周,我们计算了每一个时间序列的“surprise”:偏离自己的移动平均线。
  • 然后,我们收集了这些“surprise”值的前第90个百分位数,并且正在随着时间的推移来绘制它们。
  • 实际上,这张图表显示告诉我们前面"surprise"(偏差)的变化性。
  • 这个图标中大幅度的颠簸意味着数据变得更加 surprising,前第90个百分位数发生了巨大变化(上升或下降,因为我们使用绝对值计算surprise)

   实际上,如果我们看到一个凸起,我们可以得出结论,基础数据已经发生了改变,以改变了我们的正常方差,可能是由于中断。这是Atlas的核心:不要看你的数据,因为它是如此的多。相反,观察偏离平均值的第90个百分位数的差异。

  假如将上图表和metric #0的实际数据相比较,你将看到明显的区别:

  

Building the Atlas Dashboard

  当然,诀窍是现在自动识别那些凸起和图表/警告。让我们开始构件逻辑。当第90个百分位数surprise是移动平均线以上3个标准差时,Atlas报警。假如你分解该问题,你将看到一些必要的组件:

  • 滚动三标准差
  • 数据滚动平均线
  • 在滚动数据之上添加滚动标准差。这表示数据必须低于“阈值”
  • 当数据冲破“阈值”时报警

   首先,我们构造滚动三标准差。我们通过自定义movingstd()函数来做到这一点(参见注脚脚本,它与movingavg()函数基本相同),然后乘以3,以得到第三个sigma:

  注意:我缩进了所有的查询,以使他们更加容易阅读。

.es('metric:0', metric='avg:value')
 .movingstd(6)
 .multiply(3)

  其次,我写了一个计算数据本身滚动平均线的片段:

.es('metric:0', metric='avg:value')
 .movingaverage(6)

  最后,我们通过将这两个片段加在一起以创建“阈值”。这将创建一条在数据移动平均线以上三个标准差的线。

.es('metric:0', metric='avg:value')
  .movingaverage(6)
  .sum(
    .es('metric:0', metric='avg:value')
      .movingstd(6)
      .multiply(3)
  )

  现在我们有了一个“阈值”,我们可以用原始数据绘制,并看看它们如果比较:

  

  嗯,OK。如果阈值是否工作,现在还不清楚。该图表很难阅读,一旦surprise值凸起,就会导致阈值的后续的凸起。这是因为凸起导致方差的巨大变化,滚动标准方差会上升,导致阈值本身的上升。

  假如我们放大第一个凸起,我们可以看到,在滚动标准方差上升之前,第90个百分位数稍微超过阈值:

    

  (抱歉,此图表错误标注:“metric:0”应该显示为“#0 Threshold”)


  现在很清楚:我们想显示的是surprise超过阈值的时刻,并且另外忽略阈值(因为它只在第一瞬间有用)。当它超过阈值的时候,让我们显示单独的条,以替代持续的线条。
  为了做它,我们构造了showifgreater()方法。这将只显示第一个系列中的数据点,如果它们大于第二个系列中的数据点(参见注脚脚本)。
.es('metric:0', metric='avg:value').showifgreater(...)

  要完成我们的查询,我们仅仅希望显示大于三个标准方差大的数据(假如它突破了阈值),然后我们要显示为棒而不是线条。这组成了我们最后的查询:

.es('metric:0', metric='avg:value')
 .showifgreater(
   .es('metric:0', metric='avg:value')
    .movingaverage(6)
    .sum(
      .es('metric:0', metric='avg:value')
      .movingstd(6)
      .multiply(3)
    )
  ).bars()
  .yaxis(2)
  .label("#0 anomalies")

  这产生了更好看的图表:

  

  最后让我们加回数据本身,这样就可以进行比较了:

.es('metric:0', metric='avg:value')
 .label("#0 90th surprise"),
.es('metric:0', metric='avg:value')
 .showifgreater(
   .es('metric:0', metric='avg:value')
    .movingaverage(6)
    .sum(
      .es('metric:0', metric='avg:value')
      .movingstd(6)
      .multiply(3)
    )
  ).bars()
  .yaxis(2)
  .label("#0 anomalies")

  

  瞧!我们已经实现了Atlas!完整的面板包括每个metric的图表,以及显示中断创建时的图表(你显然不会在生产环境中使用,但对于验证我们的模拟数据是有用的):

 

Analysis of anomalies

  如果你通过中断图表(左上角)进行操作,你将至少在一个metric图表中找到相关的异常,通常几个在同时。令人鼓舞的是,异常被标记为所有类型的中断(node,query,metric)。注脚包含了一个中断的列表和它们的大小,以让你了解影响。例如,一个“Query Disruption”持续了三个小时并且仅仅影响总共500个查询中的12个(2.4%)。

  在图表中看到的一个现象是一小段时间保持在高位的凸起。这部分是由于中断的持续时间,有些持续了几个小时。但也有可能是由于我们上周提到的pipeline聚合的局限性:我们选择了每个时间序列最大surprise,而不是最后的surprise。这意味着在最坏的情况下,中断会延长额外的24小时,因为一旦中断从窗口上脱落,surprise才会重置。这完全依赖于选择窗口的大小,并且可以通过增加/减少窗口来改变敏感度。

  这种现象不会影响的异常检测,尽管如果你尝试使用更长时间窗口,这一点变得更加明显。一旦pipeline聚合有选择“最后”的能力,这个现象应该就被解决了。

Conclusion

  So,那就是Atlas,在eBay建立的一个非常简单--但非常有效--统计异常检测系统,现在在Elasticsearch +Timelion上实现了。在pipeline聚合之前,这可能是由很多客户端逻辑实现的。但是,每小时将60K的buckets流向客户端处理的前景并不诱人,pipeline聚合已经将重要的举措转移到服务器以进行更有效的处理。

  pipeline聚合还很年轻,随着时间的推移,期待更多功能被添加。假如你有一个难以在pipeline中表达的用例,请告诉我们!

The end! Or is it...

  “可是,等等” 你说,“这只是绘制异常,我如何获取预警”。对于这个答案,你必须等到下周,当我们实现了TimeLion语法作为观察者观察,如此你能获得email,Slack等等的自动预警,下周见!

Footnotes

  • 自定义movingstd()和showifgreater() Timelion 功能能在这里找到,关闭Kibana,把该功能增加到Timelion的源码(kibana/installedPlugins/timelion/series_functions/<function_name>.js),删除优化的包(rm kibana/optimize/bundles/timelion.bundle.js)并重启Kibana。该功能现在应该可以在Timelion中使用了。注意:JavaScript不是我的特长,所以这些都不是典型的代码示例。
  • 模拟中断如下。格式为格式:中断类型:开始时间-截止时间[影响 节点/查询/指标]
    • Metric Disruption: 505-521 [0, 3, 4]
    • Metric Disruption: 145-151 [3, 4]
    • Node Disruption: 279-298 [0]
    • Metric Disruption: 240-243 [1]
    • Query Disruption: 352-355 [5, 23, 27, 51, 56, 64, 65, 70, 72, 83, 86, 95, 97, 116, 135, 139, 181, 185, 195, 200, 206, 231, 240, 263, 274, 291, 295, 307, 311, 315, 322, 328, 337, 347, 355, 375, 385, 426, 468]
    • Metric Disruption: 172-181 [0, 2]
    • Node Disruption: 334-337 [0]
    • Query Disruption: 272-275 [63, 64, 168, 179, 193, 204, 230, 295, 308, 343, 395, 458]
  • 在上周的文章之后,有一些关于数据本质的问题:也就是,使用正态(高斯)曲线生成数据。Atlas可以使用曲解的数据,因为现实生活中很多数据不会遵循一个很好的正态分布?我使用LogNormal曲线运行了一个快速测试,该曲线严重偏向左侧,而Atlas依旧运行良好。该Atlas论文证实了这一实验性证据。Atlas依赖于第90个surprise随着时间推移而变得正常,即使基础数据严重偏离,似乎也是如此。可能有关于Atlas在不同数据分布下行为的后续文章,假如我有时间进行实验。

原文地址:https://www.elastic.co/blog/implementing-a-statistical-anomaly-detector-part-2

转载于:https://www.cnblogs.com/benjiming/p/7147608.html

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值