Flink相关源码解读
一、窗口相关源码解读
说明:上图是对于窗口的主要分类,在这里着重取分析滑动处理时间窗口的源码分析,其他类型可以照此类推。
功能实现代码:
//该程序主要实现的功能是每隔5s计算一次最近10s内的数据的数量
public class WaterMarkTest1 {
public static void main(String[] args) throws Exception {
StreamExecutionEnvironment environment = StreamExecutionEnvironment.getExecutionEnvironment();
environment.getConfig().setAutoWatermarkInterval(10000);
DataStreamSource<String> streamSource = environment.socketTextStream("node01", 8888);
//事件类型:
streamSource
.map(line -> {
String[] split = line.split(",");
return Tuple2.of(split[0], 1);
}, Types.TUPLE(Types.STRING, Types.INT))
.keyBy(tp -> tp.f0)
.window(SlidingProcessingTimeWindows.of(Time.seconds(10),Time.seconds(5)))
.sum(1)
.print();
environment.execute();
}
}
解析步骤:
窗口的生成
进入SlidingProcessingTimeWindows.class
类中,
首先找到调用的of()
方法:
由上述方法得到对应三个全局变量的值:
size=10000-------窗口大小
slide=5000-------滑动步长
offset=0---------偏移量
然后找到assignWindows()
方法,给方法顾名思义就是用于做窗口创建的,
接下来逐条解析每句代码:
timestamp = context.getCurrentProcessingTime();
——获取当前系统时间
List<TimeWindow> windows = new ArrayList<>((int) (size / slide));
——声明一个List用于存储产生的窗口
long lastStart = TimeWindow.getWindowStartWithOffset(timestamp, offset, slide);
——主要获取一个窗口的开始时间,在下面会进行详细的解读
for (long start = lastStart; start > timestamp - size; start -= slide) {
windows.add(new TimeWindow(start, start + size));
}
——通过循环的方式创建窗口,下面会列举实例
assignWindows()
中getWindowStartWithOffset()
方法解读:
通过对该代码的解读可以得到,该方法的功能就是返回比指定时间戳小的最大可以被slide滑动步长整除的时间戳。
根据long start = lastStart; start > timestamp - size; start -= slide
进行窗口创建实例:
timestamp | start-time | end-time |
---|---|---|
1695114522 | 1695114520 | 1695114530 |
1695114522 | 1695114515 | 1695114525 |
由上述创建了两个,得到带有时间戳1695114522
的事件存在两个窗口中。
接下来寻找assignWindows()
在何处被调用使用Ctrl+Atl+H
,选择WindowOperator
类
代码量比较大只分为两部分也就是一个if判断:
该部分主要功能是如果是会话窗口进行窗口的合并
else之后的代码是进行窗口创建的代码,代码量比较大只需要看以下两句:
windowState.setCurrentNamespace(window);
——该句主要规定了Window如何存放,将windowState的CurrentNamespace更新为当前窗口的state,也就是用一个中间变量进行存储。
windowState.add(element.getValue());
——说明了数据如何存放
深入了解以下上述中窗口数据的存放,进入接口AppendingState
的实现类HeapListState
中,找到其实现的add()
方法:
上述代码中主要实现功能:
1、从StateTable中获得一个类似Map对象
2、从这map对象中获得对应窗口的List集合,该集合中存放着对应窗口的数据,namespace就是窗口的标识
3、如果List集合为空则之间创建一个List集合用于存放窗口中的数据
窗口的触发
概述:
Flink
中含有Trigger
抽象类,该类的主要作用就是进行窗口计算触发的判断。
以下为Trigger
含有的方法:
由上图可以看出每种类型的窗口都存在专属自己的触发器,以onEvent()
为例:
其次对于每种触发器返回类型做一个深入了解,通过查看TriggerResult
进行了解,
对上述参数进行解释:
CONTINUE——表示继续等待不触发窗口计算
FIRE_AND_PURGE——表示触发窗口计算同时删除掉窗口内容
FIRE——表示触发窗口计算,但不删除窗口内容
PURGE——表示清除窗口中所有元素并丢弃窗口,不触发窗口计算或者转发任何元素
UE——表示继续等待不触发窗口计算
FIRE_AND_PURGE——表示触发窗口计算同时删除掉窗口内容
FIRE——表示触发窗口计算,但不删除窗口内容
PURGE——表示清除窗口中所有元素并丢弃窗口,不触发窗口计算或者转发任何元素
> 补充:虽然每种类型的窗口都含有对应的默认触发器,但是如果在实际开发中并不符合需求也是可以自定义触发器。