流处理基本知识

流处理基本知识

Posted by danfeng on October 20, 2018

流式架构的基本概念

### 流 最初流式系统架构是通过微批处理的方式来实现的,如SparkStreaming,其原理是将多个微批处理任务进行串联起来进行数据处理,牺牲了吞吐和延迟,为此,业界便开始构建用于处理没有时间边界的数据(无界数据集,Unbounded Data)的实时数据。因此从这个角度分析,流可以定义为一种无界数据集设计的数据处理引擎,这种引擎具备以下的特征:

  • 具备强一致性,支持exactly-once语义
  • 提供丰富的时间工具,如事件时间、处理时间、窗口等。
  • 保证系统具有可弹性、伸缩性。
  • 支持高层语义,如流式SQL、复杂时间CEP。

    时间

    在流式处理理论中,通常采用事件和记录表示从处理的集合中拉取的数据,在Flink中通常以有结构的对象表示事件。在无界数据集合处理中,主要有两类时间:

  • 事件时间:事件实际发生的时间。
  • 处理时间:事件被处理的时间。

并非所有的场景都关注事件时间,但是其重要性不言而喻,例如在用户行为分析、异常检测、基于信贷历史风控模型中 ,事件的起点起到了决定性作用。

  • 用户行为特征分析:用户浏览网页产生一系列的页面点击和浏览时长的数据,这些数据被称之为用户行为数据,用户行为数据可以在精准营销,产品迭代等功能环节。
  • 异常检测
  • 信贷历史/反欺诈

事件处理时间 和 事件时间偏差原因

  • 受共享资源影响 :如网络延迟、网络分区(CAP理论)、共享cpu等
  • 软件架构:如分布式的并发竞争和时钟不一致
  • 数据自身特性:如key的特殊分布、吞吐量的快速涨落、乱序等。

    窗口

    将数据集划分成一个个的有限数据区间的机制,也就是在数据集合中增加临时处理边界,用于将事件按照时间或其他特征进行分组分析。

  • 滚动窗口(Tumbling window):按时间划分成固定长度,不重叠且等长的时间窗口。其中time可以是事件时间和处理时间。
  • 滑动窗口(sliding window):有重叠的窗口,按照滑动步长将时间拆分成固定的长度,当滑动步长小于窗口长度的时候,时间窗口会发生重叠。
  • 会话窗口:以活动时间间隔作为边界,将一系列连续事件拆分到不同的会话中,会话窗口的长度是动态的。

    水印(WaterMark)

    水印是嵌入到事件时间轴上,用于判断时间窗口内的所有数据均已经到达引擎的一种时间推理工具,是一种既可以在流处理引擎侧嵌入,又可以在消息系统侧嵌入的时间戳。水印的语义是事件的时间小于水印标记的时间的事件不会再出现,因为水印是事件的推进器。水印可以有效的标记出每个窗格里面有多少个记录点可以被聚合处理,我们不能够确定什么时候触发聚合水印,水印可以标记出这个时间点。水印可以标记出某个时间点以前的所有记录都已经到达引擎,可以被处理。考虑到系统开销,水印是离散的,只有部分记录后面附有水印,为了便于分析,水印通常以连续曲线表示。通常的水印主要分成下面两种水印:

    1. 完美水印表示早于水印标记的时间戳的所有的记录都已经成功的到达,非乱序的无界数据集中最后一条记录的时间就是完美时间水印。完美水印会造成大概率的大延迟,同时会拉长窗口的生存期–也就是这两个窗口所占用的资源都不能及时的进行释放。
    2. 启发式水印:尽可能的确定时间戳的一种估计,可能某些事件晚于水印到达的情况。(不足:统计不够精确,导致某些事件落后于水印,导致没有计算在窗口中,这不满足精准计算的要求,引擎需要提供事处理机制予以校正。)

FLINK有三种时间

  • Event time:事件时间是基于数据中字段的时间,决定数据产生的时间,而不是当前系统时间。事件时间程序必须指定如何生成事件Watermarks,用来保证事件时间的有序性。由于消息可能是乱序流入Task的,所以Task需要缓存当前时间窗口消息处理的状态,直到确认属于该时间窗口的所有消息都被处理后,才可以释放其状态。如果乱序的消息延迟很高的话,会影响分布式系统的吞吐量和延迟
  • Ingestion time:摄入时间(Ingestion Time)是事件进入Flink的时间,依赖source operator所在服务器的系统时间,后续基于时间的操作(如: time window)会依赖这个时间戳.摄入时间从概念上来讲是处在event time和processing time之间,由于不能处理无序的事件或延迟数据,所以也不必指定生成Watermark.与processing time相比,生产的成本可能会高一点,但是会提供更加可预测的结果。因为摄入时间使用的是固定的时间戳(都是在source处指定的),不依赖后续operator 所在系统的时间,不会因机器的时钟不同步或网络延迟导致计算问题.Ingress Time可以看成是Event Time的一个特例,由于其在消息源处时间戳一定是有序的,其乱序的消息延迟不会很高,因此对Flink分布式系统的吞吐量和延迟的影响也会更小 .
  • Processing time:是指所有基于时间计算的算子(如时间窗口)将使用当前运行机器的系统时间。处理时间是最简单的时间概念,不需做时间上的对比协调,因此使用processing time的flink应用具有最好的性能和最低的延迟。同时在分布式环境中,如果每台机器的时间不同步,即便数据本身有序,也会在数据处理过程中产生乱序问题,影响计算结果。

    下面通过一个样例对Flink中的窗口、时间、水印进行简单的认识:


假设源分别在13秒、13秒和16秒的时候生成了三条a类型的消息。(窗口大小10秒)。

Case 1: 数据没有延迟,基于Processing time 这些消息将如下所示进入窗口。第13秒生成的前两条消息将同时落入window1[5s-15s]和window2[10s-20s],第16秒生成的第三条消息将同时落入window2[10s-20s]和window3[15s-25s]。每个窗口发出的最终计数将分别为(a,2)、(a,3)和(a,1)。 https://s2.ax1x.com/2019/07/20/Zzoh1x.jpg

Case 2: 数据有延迟,基于Processing time 现在假设有一条消息(在第13秒生成)延迟了6秒(在第19秒生成),这可能是由于某些网络拥塞造成的。 image   延迟消息进入窗口2和窗口3,因为19在10-20和15-25之间。它没有给window2中的计算带来任何问题(因为消息本来就应该落在那个窗口中),但是它影响了window1和window3的结果。

Case 3: 数据有延迟,基于event time 结果看起来好多了,windows 2和windows 3现在发出了正确的结果,但windows 1仍然是错误的。Flink没有将延迟消息分配给窗口3,因为它现在检查了消息的事件时间,并且知道它没有落在窗口中。但是为什么不把消息分配到窗口1呢?原因是当延迟消息到达系统时(19秒),窗口1的计算已经完成(15秒)。 image

Case 4: 数据有延迟,基于event time和水印 我们现在将水印设置为当前时间- 5秒,这告诉Flink期望消息的最大时间为5秒,这是因为只有当水印通过每个窗口时,才会对其进行触发。由于我们的水印是当前时间-5秒,第一个窗口[5s-15s]将只在第20秒触发。类似地,窗口[10s-20s]将在25秒触发,以此类推。 image

image image

  对于flink来说,一般Watermark是在Source函数生成,当然也可以再后期的算子中生成,但是一定要在时间函数(主要是窗口函数)之前生成。一个source函数的每个并行子任务通常独立的产生watermark。这些watermark定义了特定并行source的事件时间。一些操作算子会有多个输入流。例如,union操作或者keyBy(…)或partition(…)之后的操作.这些操作算子的当前事件时间是取决于所有输入流最小的事件时间。当输入流更新它们的事件时间时,操作算子也会更新。

我们可以看出每个窗口都会有开始时间和结束时间(一般window的时间窗口为左闭右开的区间范围),在这段时间内,我们是否能拿到所有需要处理的数据,我们就需要watermark来配合了