流式统计的几个难点

在本文发出之后不久,老外就写了一篇类似内容的。人家比我写得好,推荐大家读这篇
http://radar.oreilly.com/2015/08/the-world-beyond-batch-streaming-101….

流式统计听着挺容易的一个事情,说到底不就是数数嘛,每个告警系统里基本上都有一个简单的流式统计模块。但是当时基于storm做的时候,这几个问题还是困扰了我很长时间的。没有用过spark streaming/flink,不知道下面这些问题在spark streaming/flink里是不是都已经解决得很好了。

时间窗口切分问题

做流式统计首要的问题是把一个时间窗口内的数据统计到一起。问题是,什么是时间窗口?有两种选择

  • 日志时间(event timestamp)
  • 墙上时间(wall clock)

最简单的时间窗口统计的是基于“墙上时间”的,每过1分钟就切分出一个新窗口出来。比如statsd,它的窗口切分就是这样的。这种基于“墙上时间”的统计有一个非常严重的问题是不能回放数据流。当数据流是实时产生的时候,“墙上时间”的一分钟也就只会有一分钟的event被产生出来。但是如果统计的数据流是基于历史event的,那么一分钟可以产生消费的event数量只受限于数据处理速度。另外event在分布式采集的时候也遇到有快有慢的问题,一分钟内产生的event未必可以在一分钟内精确到达统计端,这样就会因为采集的延迟波动影响统计数据的准确性。实际上基于“墙上时间”统计需要

collection latency = wall clock - event timestamp

基于“墙上时间”的统计需要采集延迟非常小,波动也很小才可以工作良好。大部分时候更现实的选择是需要基于“日志时间”来进行窗口统计的。

使用“日志时间”就会引入数据乱序的问题,对于一个实时event stream流,其每个event的timestamp未必是严格递增的。这种乱序有两种因素引入:

  • event产生的机器的时钟不完全同步(NTP有100ms左右的不同步)
  • event从采集到到达kafka的速度不均衡(不同的网络线路有快有慢)

我们希望的流式统计是这样的:

但是实际上数据只是基本有序的,也就是在时间窗口的边缘会有一些event需要跨到另外一个窗口去:

最简单的分发event到时间窗口代码是这样的

window index = event timestamp / window size

对1分钟的时间窗口 window size 就是60,timestamp除以60为相同window index的event就是在同一个时间窗口的。问题的关键是,什么时候我可以确信这个时间窗口内的event都已经到齐了。如果到齐了,就可以开始统计出这个时间窗口内的指标了。然后突然又有一个落后于大伙的event落到这个已经被计算过的时间窗口如何处理?

  • 对于大部分统计而言,一个时间窗口统计出多条结果存入db并不是什么大的问题,从db里查询的时候把多条结果再合并就可以了。
  • 对于一些类型的统计(非monad),比如平均值,时间窗口内的event分为两批统计出来的结果是没有办法被再次汇总的。
  • 实时类的计算对时间敏感,来晚了的数据就没有意义了。比如告警,一个时间窗过去了就没有必要再理会这个时间窗口了。

所以对于来晚了的数据就两种策略:要么再统计一条结果出来,要么直接丢弃。要确定什么时候一个时间窗口内的event已经到齐了,有几种策略:

  • sleep 等待一段时间(墙上时间)
  • event timestamp超过了时间窗口一点点不关闭当前时间窗口,而是要等event timestamp大幅超出时间窗口的时候才关闭窗口。比如12:05:30秒的event到了才关闭12:04:00 ~ 12:05:00的时间窗口。
  • 一两个event超出了时间窗口不关闭,只有当“大量”的event超出时间窗口才关闭。比如1个event超过12:05分不关闭,如果有100个event超过了12:05的时间窗口就关闭它。

三种策略其实都是“等”,只是等的依据不同。实践中,第二种策略也就是根据“日志时间”的等待是最容易实现的。如果对于过期的event不是丢弃,而是要再次统计一条结果出来,那么过期的窗口要重新打开,又要经过一轮“等待”去判断这个过去的窗口什么时候再被关闭。

在spark上已经有人做类似的尝试了:Building Big Data Operational Intelligence platform with Apache Spark - Eric Carr (Guavus)

多流合并的问题

一个kafka的partition就是一个流,一个kafka topic的多个partition就是多个独立的流(offset彼此独立增长)。多个kafka topic显然是多个独立的流。流式统计经常需要把多个流合并统计到一起。这种里会遇到两个难题

  • 多个流的速度不一样,如何判断一个时间窗口内的event都到齐了。如果按照前面的等待策略,可能处理一个流内部的基本有序局部乱序是有效的,但是对于多个流速差异很大的流就无能为力了。一个很快的流很容易把时间窗口往后推得很远,把其他流远远跑到后面。
  • 流速不均不能靠下游兜着,下游的内存是有限的。根本上是需要一种“背压”的机制,让下游通知流速过快的上游,你慢点产生新的event,等等其他人。

举一个具体的例子:

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值