这是我参与「第四届青训营 」笔记创作活动的第4天
本节课主要分为四个部分:
- 概述流式计算跟批计算,以及实时数仓和离线数仓的区别;引出流式计算中的window计算定义以及挑战
- 介绍实时计算中的Watermark概念,以及如何产生、传递,还有一些典型的生产实践中遇到的问题
- 介绍三种最基本的window类型,以及他们的实现原理;同时会结合业务场景介绍一些高级优化的功能和原理
- 结合两个真实业务场景的需求,讲解window是如何解决实际生产问题的
概述
流式计算与批式计算的对比
数据价值:实时性越高,数据价值越高。
批处理
处理时间窗口
处理时间vs真实时间
Watermark
什么是Watermark?
表示系统认为的当前真实的事件时间
Watermark如何产生
一般是从数据的事件时间来产生,产生策略可以灵活多样,最常见的包括使用当前事件时间的时间减去一个固定的delay,来表示可以可以容忍多长时间的乱序。
如何传递Watermark
这个类似于上节课中介绍的Checkpoint的制作过程,传递就类似于Checkpoint的barrier,上下游task之间有数据传输关系的,上游就会将watermark传递给下游;下游收到多个上游传递过来的watermark后,默认会取其中最小值来作为自身的watermark,同时它也会将自己watermark传递给它的下游。经过整个传递过程,最终系统中每一个计算单元就都会实时的知道自身当前的watermark是多少。
典型的问题
怎么观察一个任务中的watermark是多少,是否是正常的?
- 一般通过Flink Web UI上的信息来观察当前任务的watermark情况
- 这个问题是生产实践中最容易遇到的问题,大家在开发事件时间的窗口任务的时候,经常会忘记了设置watermark,或者数据太少,watermark没有及时的更新,导致窗口一直不能触发。
Per-partition / Per-subtask 生成watermark的优缺点
- 在Flink里早期都是per-subtask的方式进行watermark的生成,这种方式比较简单。但是如果每个source task如果有消费多个partition的情况的话,那多个partition之间的数据可能会因为消费的速度不同而最终导致数据的乱序程度增加。
- 后期就逐步的变成了per-partition的方式来产生watermark,来避免上面的问题。
如果有部分partition/subtask会断流,应该如何处理?
数据断流是很常见的问题,有时候是业务数据本身就有这种特点,比如白天有数据,晚上没有数据。在这种情况下,watermark默认是不会更新的,因为它要取上游subtask发来的watermark中的最小值。此时我们可以用一种IDLE状态来标记这种subtask,被标记为这种状态的subtask,我们在计算watermark的时候,可以把它先排除在外。这样就可以保证有部分partition断流的时候,watermark仍然可以继续更新。
算子对于时间晚于watermark的数据的处理
- 对于迟到数据,不同的算子对于这种情况的处理可以有不同的实现(主要是根据算子本身的语义来决定的)
- 比如window对于迟到的数据,默认就是丢弃;比如双流join,对于迟到数据,可以认为是无法与之前正常数据join上。
Window
Window的分类
滚动窗口
滑动窗口
会话窗口
迟到的数据处理
对于迟到的数据,我们现在有两种处理方式:
- 使用side output方式,把迟到的数据转变成一个单独的流,再由用户自己来决定如何处理这部分数据
- 直接drop掉
(注意:side output只有在DataStream的窗口中才可以用,在SQL中目前还没有这种语义,所以暂时只有drop这一个策略)
增量vs全量计算
EMIT触发
什么叫EMIT
怎么实现
Window高级优化
Mini-batch优化
倾斜优化 - local-global
Distinct计算状态复用
Pane优化
案例分析
计算抖音的日常曲线
计算大数据任务的资源使用
个人总结
通过本节课,首先我了解到流式计算和批式计算的区别,然后了解了Watermark的概念以及如何生成、如何传递、如何处理部分partition断流的问题,最后了解了Window的定义,以及如何处理迟到数据,增量计算和全量计算的比较、EMIT输出,以及各种优化方案。