本文选自《实时流计算系统设计与实现》 文末有惊喜数据库
状态管理是流计算系统的核心问题之一。在实现流数据的关联操做时,流计算系统须要先将窗口内的数据临时保存起来,而后在窗口结束时,再对窗口内的数据作关联计算。在实现时间维度聚合特征计算和关联图谱特征计算时,更是须要建立大量的寄存用于记录聚合的结果。而CEP的实现,自己就与常说的有限状态机(Finite-state machine,FSM)是密切相关的。不论是为了关联计算而临时保存的数据,仍是为了保存聚合计算的数据,抑或是CEP里的有限状态机,这些数据都是流计算应用开始运行以后才建立和积累起来。若是没有作持久化操做,这些数据在流计算应用重启后会被彻底清空。正由于如此,咱们将这些数据称之为流计算应用的“状态”。从各类开源流计算框架的发展历史来看,你们对实时流计算中的“状态”问题也是一点点逐步弄清楚的。缓存
咱们将流在执行过程当中涉及到的状态分为两类:流数据状态和流信息状态。网络
图1: 流数据状态和流信息状态架构
为何区分这两种状态很是重要?思考这么一个问题,若是咱们要计算“用户过去7天交易的总金额”,该如何作?一种显而易见的方法,是直接使用在各类流计算框架中都提供的窗口函数来实现。好比在Flink中以下:并发
userTransactions.keyBy(0)// 滑动窗口,每1秒钟计算一次7天窗口内的交易金额.timeWindow(Time.days(7), Time.seconds(1)).sum(1);
上面的Flink示例代码使用timeWindow窗口,每1秒钟计算一次7天窗口内的总交易金额。其它流计算平台如Spark Streaming、Storm等也有相似的方法。但这样作有如下几点很是不妥:框架
因此说,直接使用由流计算框架提供的窗口函数来实现诸如“时间维度聚合特征”的计算问题,咱们在不少状况下都会遇到问题。究其根本缘由,是由于混淆了“对流的管理”和“对数据信息的管理”这二者自己。由于“窗口”其实是对“流数据”的分块管理,咱们用“窗口”来将“无穷无尽”的流数据分割成一个个的“数据块”,而后在“数据块”上作各类计算。这属于对流数据的“分而治之”处理。咱们不能将这种针对“流数据”自己的分治管理模式,与咱们对数据的业务信息分析窗口耦和起来。函数
所以,咱们须要将“对流的管理”和“对数据信息的管理”这二者分离开来。其中“对流的管理”须要解决诸如窗口、乱序、多流关联等问题,其中也会涉及对数据的临时缓存,它缓存的是流数据自己,所以咱们称之为“流数据状态”。而“对数据信息的管理”则是为了在咱们在分析和挖掘数据内含信息时,帮助咱们记录和保存业务分析结果,于是称之为“流信息状态”。优化
流数据状态管理中,比较重要的就是事件窗口、时间乱序和流的关联操做。设计
事件窗口是产生流数据状态的主要缘由。好比“每30秒钟计算一次过去五分钟交易总额”、“每满100个事件计算平均交易金额”、“统计用户在一次活跃期间点击过的商品数量”等。对于这些以“窗口”为单元来处理事件的方式,咱们须要用一个缓冲区(buffer)临时地存储过去一段时间接收到的事件,等触发窗口计算的条件知足时,再触发处理窗口内的事件。当处理完成后,还须要将过时和之后再也不使用的数据清除掉。另外,在实际生产环境中,可能会出现故障恢复、重启等状况,这些“缓冲区”的数据在必要时须要被写入磁盘,并在从新计算或重启时恢复。code
解决时间乱序问题是使用流数据状态的另外一个重要缘由。因为网络传输和并发处理的缘由,在流计算系统接收到事件时,很是有可能事件已经在时间上乱序了。好比时间戳为1532329665005的事件,比时间戳为1532329665001的事件先到达流计算系统。怎样处理这种事件在时间上乱序的问题呢?一般的作法就是将收到的事件先保存起来,等过一段时间后乱序的事件到达时,再将其和保存的事件按时间排序,这样就恢复了事件的时间顺序。固然,上面的过程存在一个问题,就是“等过一段时间”究竟是怎样等以及等多久?针对这个问题有一个很是优秀的解决方案,就是水印(watermark)。使用水印解决时间乱序的原理以下,在流计算数据中,按照必定的规律(好比以特定周期)插入“水印”,水印是一个时间戳,当处理单元接收到“水印”时,表示应该处理全部时间戳在该水印以前的事件。咱们一般将水印设置为事件的时间戳减去一段时间的值,这样就给先到的时间戳较大的事件一个等待晚到的时间戳较小的事件的机会,并且确保了不会没完没了地等待下去。
流的关联操做也会涉及流数据状态的管理。常见的关联操做有join和union。特别是在实现join操做时,须要先将参与join操做的各个流的相应窗口内的数据缓存在流计算系统内,而后以这些窗口内的数据为基础,作相似于关系型数据库中表与表之间的join计算,获得join计算的结果,以后再将这些结果以流的方式输出。很显然,流的关联操做也是须要临时保存部分流数据的,故而也是一种“流数据状态”的运用。
除了以上三种“流数据状态”的主要用途外,还有些地方也会涉及流数据状态的管理,好比排序(sorting)、分组(group by)等。但无论怎样,这些操做都有个共同的特色,即它们须要缓存的是部分原始的流数据。换言之,这些操做要保存的状态是部分“流数据”自己。这也正是将这类状态取名为“流数据状态”的缘由。流信息状态是为了记录流数据的处理和分析过程当中得到的咱们感兴趣的信息,这些信息会在后续的流处理过程当中会被继续使用和更新。以“实时计算每一个交易事件在发生时过去7天交易的总金额”这个计算为例,能够将每小时的交易金额记录为一条状态,这样,当一个交易事件到来时,计算“过去7天的交易总金额”,就是将过去7天每一个小时的总交易金额读取出来,而后对这些金额记录求总和便可。在上面这个例子中,将每小时的交易金额记录为一条状态,就是咱们说的“流信息状态”。
流信息状态的管理一般依赖于数据库完成。这是由于对于从流分析出来的信息,咱们可能须要保存较长时间,并且数据量会很大,若是将这些信息状态放在内存中,势必会占用过多的内存,这是没必要要的。对于保存的流信息状态,咱们并非在每次计算中都会用到,它会存在冷数据和过时淘汰的问题。因此,对于流信息状态的管理,交给专门的数据库是很是明智的。毕竟目前为止,各类数据库的选择十分丰富,并且许多数据库对热数据缓存和TTL机制都有很是好的支持。
实时流计算应用中的“流数据状态”和“流信息状态”。能够说是分别从两个不一样的维度对“流”进行了管理。前者“流数据状态”是从“时间”角度对流进行管理,然后者“流信息状态”则是从“空间”角度对流的管理。“流信息状态”弥补了“流数据状态”弥补了“流数据状态”只是对事件在时间序列上作管理的不足,将流的状态扩展到了任意的空间。
做者简介:周爽,本硕毕业于华中科技大学,前后在华为2012实验室高斯部门和上海行邑信息科技有限公司工做。开发过实时分析型内存数据库RTANA、华为公有云RDS服务、移动反欺诈MoFA等产品。目前但任公司技术部架构师一职。著有《实时流计算系统设计与实现》一书。
本次联合【机械工业出版社华章公司】为你们送上1本做者的正版书籍《实时流计算系统设计与实现》
请在关注“实时流式计算” 并在后台回复 “抽奖”参与活动
更多实时数据分析相关博文与科技资讯,欢迎关注 “实时流式计算”