两种状态
流在执行过程中涉及到的状态分为两类:流数据状态和流信息状态。
流数据状态:在流数据处理的过程中,可能需要处理事件窗口、时间乱序、多流关联等问题,在解决这些问题的过程中,通常会涉及到对部分流数据的临时缓存,并在处理完后将其清理。这些临时保存的部分流数据称为“流数据状态”。
流信息状态:在对流数据的分析过程中,会得到一些有用的信息,比如时间维度的聚合数据、关联图谱中的一度关联节点数、CEP中的有限状态机等,我们需要保存这些信息以便会在后续的流数据分析过程中继续使用。同时在后续的流数据处理过程中,这些信息还会被不断地访问和更新。这些分析所得并保存下来的数据称为“流信息状态”。
流数据状态
事件窗口是产生流数据状态的主要原因。比如“每30秒钟计算一次过去五分钟交易总额”、“每满100个事件计算平均交易金额”、“统计用户在一次活跃期间点击过的商品数量”等。对于这些以“窗口”为单元来处理事件的方式,我们需要用一个缓冲区(buffer)临时地存储过去一段时间接收到的事件,等触发窗口计算的条件满足时,再触发处理窗口内的事件。当处理完成后,还需要将过期和以后不再使用的数据清除掉。另外,在实际生产环境中,可能会出现故障恢复、重启等情况,这些“缓冲区”的数据在必要时需要被写入磁盘,并在重新计算或重启时恢复。
解决时间乱序问题是使用流数据状态的另一个重要原因。由于网络传输和并发处理的原因,在流计算系统接收到事件时,非常有可能事件已经在时间上乱序了。比如时间戳为1532329665005的事件,比时间戳为1532329665001的事件先到达流计算系统。怎样处理这种事件在时间上乱序的问题呢?通常的做法就是将收到的事件先保存起来,等过一段时间后乱序的事件到达时,再将其和保存的事件按时间排序,这样就恢复了事件的时间顺序。当然,上面的过程存在一个问题,就是“等过一段时间”到底是怎样等以及等多久?针对这个问题有一个非常优秀的解决方案,就是水位线(watermark)。使用水位线解决时间乱序的原理如下,在流计算数据中,按照一定的规律(比如以特定周期)插入“水位线”,水位线是一个时间戳,当处理单元接收到“水位线”时,表示应该处理所有时间戳在该水位线之前的事件。我们通常将水位线设置为事件的时间戳减去一段时间的值,这样就给先到的时间戳较大的事件一个等待晚到的时间戳较小的事件的机会,而且确保了不会没完没了地等待下去。
流的关联操作也会涉及流数据状态的管理。常见的关联操作有join和union。特别是在实现join操作时,需要先将参与join操作的各个流的相应窗口内的数据缓存在流计算系统内,然后以这些窗口内的数据为基础,做类似于关系型数据库中表与表之间的join计算,得到join计算的结果,之后再将这些结果以流的方式输出。很显然,流的关联操作也是需要临时保存部分流数据的,故而也是一种“流数据状态”的运用。
流信息状态
流信息状态的管理通常依赖于数据库完成。这是因为对于从流分析出来的信息,我们可能需要保存较长时间,而且数据量会很大,如果将这些信息状态放在内存中,势必会占用过多的内存,这是不必要的。对于保存的流信息状态,我们并不是在每次计算中都会用到,它会存在冷数据和过期淘汰的问题。所以,对于流信息状态的管理,交给专门的数据库是非常明智的。毕竟目前为止,各种数据库的选择十分丰富,而且许多数据库对热数据缓存和TTL机制都有非常好的支持。
将实时流计算应用中的状态分为了“流数据状态”和“流信息状态”,可以说是从两个不同的维度对“流”进行的管理。
前者“流数据状态”是从“时间”角度对流进行管理,
后者“流信息状态”则是从“空间”角度对流的管理。
“流信息状态”弥补了“流数据状态”只是对事件在时间序列上做管理的不足,将流的状态扩展到了任意的空间。
“流信息状态”的三种存储方式
计算节点和状态数据节点分离的分布式内存数据库方案
使用Redis集群进行状态存储和管理计算节点和状态数据节点共存的分布式内存格点方案
使用Ignite集群进行状态存储和管理基于分布式文件系统同步状态数据的方案
基于分布式文件系统的状态存储和管理集群将“流计算应用本身的执行过程”和“流数据的信息管理机制”解耦,会使得实时流计算系统的整体结构更加清晰。
前者可以理解为CPU的执行流水线,后者就相当于是内存。
网友评论