Flink – process watermark
WindowOperator.processElement
主要的工作,将当前的element的value加到对应的window中,
windowState.setCurrentNamespace(window);
windowState.add(element.getValue()); triggerContext.key = key;
triggerContext.window = window; TriggerResult triggerResult = triggerContext.onElement(element);
调用triggerContext.onElement
这里的Context只是一个简单的封装,
public TriggerResult onElement(StreamRecord<IN> element) throws Exception {
return trigger.onElement(element.getValue(), element.getTimestamp(), window, this);
}
EventTimeTrigger
onElement
@Override
public TriggerResult onElement(Object element, long timestamp, TimeWindow window, TriggerContext ctx) throws Exception {
if (window.maxTimestamp() <= ctx.getCurrentWatermark()) {
// if the watermark is already past the window fire immediately
return TriggerResult.FIRE;
} else {
ctx.registerEventTimeTimer(window.maxTimestamp());
return TriggerResult.CONTINUE;
}
}
如果当前window.maxTimestamp已经小于CurrentWatermark,直接触发
否则将window.maxTimestamp注册到TimeService中,等待触发
WindowOperator.Context
public void registerEventTimeTimer(long time) {
internalTimerService.registerEventTimeTimer(window, time);
}
InternalTimerService
在AbstractStreamOperator
public abstract class AbstractStreamOperator<OUT>
implements StreamOperator<OUT>, Serializable, KeyContext {
注意这里实现了KeyContext
所以AbstractStreamOperator实现了
public Object getCurrentKey() {
if (keyedStateBackend != null) {
return keyedStateBackend.getCurrentKey();
} else {
throw new UnsupportedOperationException("Key can only be retrieven on KeyedStream.");
}
}
在AbstractStreamOperator初始化InternalTimeServiceManager
private transient InternalTimeServiceManager<?, ?> timeServiceManager;
@Override
public final void initializeState(OperatorStateHandles stateHandles) throws Exception { if (getKeyedStateBackend() != null && timeServiceManager == null) {
timeServiceManager = new InternalTimeServiceManager<>(
getKeyedStateBackend().getNumberOfKeyGroups(),
getKeyedStateBackend().getKeyGroupRange(),
this,
getRuntimeContext().getProcessingTimeService());
}
WindowOperator中InternalTimerService初始化,
internalTimerService =
getInternalTimerService("window-timers", windowSerializer, this);
在AbstractStreamOperator调用,
public <K, N> InternalTimerService<N> getInternalTimerService(
String name,
TypeSerializer<N> namespaceSerializer,
Triggerable<K, N> triggerable) { checkTimerServiceInitialization(); // the following casting is to overcome type restrictions.
TypeSerializer<K> keySerializer = (TypeSerializer<K>) getKeyedStateBackend().getKeySerializer();
InternalTimeServiceManager<K, N> keyedTimeServiceHandler = (InternalTimeServiceManager<K, N>) timeServiceManager;
return keyedTimeServiceHandler.getInternalTimerService(name, keySerializer, namespaceSerializer, triggerable);
}
其实就是调用InternalTimeServiceManager.getInternalTimerService
最终得到HeapInternalTimerService
HeapInternalTimerService.registerEventTimeTimer
@Override
public void registerEventTimeTimer(N namespace, long time) {
InternalTimer<K, N> timer = new InternalTimer<>(time, (K) keyContext.getCurrentKey(), namespace);
Set<InternalTimer<K, N>> timerSet = getEventTimeTimerSetForTimer(timer);
if (timerSet.add(timer)) {
eventTimeTimersQueue.add(timer);
}
}
创建InternalTimer,包含,time(window.maxTimestamp), key(keyContext.getCurrentKey), namespace(window)
getEventTimeTimerSetForTimer
private Set<InternalTimer<K, N>> getEventTimeTimerSetForTimer(InternalTimer<K, N> timer) {
checkArgument(localKeyGroupRange != null, "The operator has not been initialized.");
int keyGroupIdx = KeyGroupRangeAssignment.assignToKeyGroup(timer.getKey(), this.totalKeyGroups);
return getEventTimeTimerSetForKeyGroup(keyGroupIdx);
}
private Set<InternalTimer<K, N>> getEventTimeTimerSetForKeyGroup(int keyGroupIdx) {
int localIdx = getIndexForKeyGroup(keyGroupIdx);
Set<InternalTimer<K, N>> timers = eventTimeTimersByKeyGroup[localIdx];
if (timers == null) {
timers = new HashSet<>();
eventTimeTimersByKeyGroup[localIdx] = timers;
}
return timers;
}
先找到key所对应的,keygroup,每个keygroup对应于一个Timer集合
这样设计的目的,因为最终timer也是要checkpoint的,而checkpoint的最小单位是keygroup,所以不同keygroup所对应的timer需要分离开
最终把timer加到eventTimeTimersQueue,
private final PriorityQueue<InternalTimer<K, N>> eventTimeTimersQueue;
PriorityQueue是堆实现的,所以只要在InternalTimer里面实现compareTo,就可以让timer排序
AbstractStreamOperator.processWatermark
public void processWatermark(Watermark mark) throws Exception {
if (timeServiceManager != null) {
timeServiceManager.advanceWatermark(mark);
}
output.emitWatermark(mark);
}
timeServiceManager.advanceWatermark
public void advanceWatermark(Watermark watermark) throws Exception {
for (HeapInternalTimerService<?, ?> service : timerServices.values()) {
service.advanceWatermark(watermark.getTimestamp());
}
}
HeapInternalTimerService.advanceWatermark
public void advanceWatermark(long time) throws Exception {
currentWatermark = time;
InternalTimer<K, N> timer;
while ((timer = eventTimeTimersQueue.peek()) != null && timer.getTimestamp() <= time) {
Set<InternalTimer<K, N>> timerSet = getEventTimeTimerSetForTimer(timer);
timerSet.remove(timer);
eventTimeTimersQueue.remove();
keyContext.setCurrentKey(timer.getKey());
triggerTarget.onEventTime(timer);
}
}
从eventTimeTimersQueue从小到大取timer,如果小于传入的water mark,那么说明这个window需要触发
设置operater的current key,keyContext.setCurrentKey(timer.getKey())
这里注意watermarker是没有key的,所以当一个watermark来的时候是会触发所有timer,而timer的key是不一定的,所以这里一定要设置keyContext,否则就乱了
最终触发triggerTarget.onEventTime
triggerTarget就是WindowOperator
WindowOperator.onEventTime
windowState.setCurrentNamespace(triggerContext.window);
ACC contents = null;
if (windowState != null) {
contents = windowState.get();
}
if (contents != null) {
TriggerResult triggerResult = triggerContext.onEventTime(timer.getTimestamp());
if (triggerResult.isFire()) {
emitWindowContents(triggerContext.window, contents);
}
if (triggerResult.isPurge()) {
windowState.clear();
}
}这里调用triggerContext.onEventTime,得到TriggerResult
如果fire,走到这,这个肯定满足的,emitWindowContents
如果purge,就把windowState清空
emitWindowContents,调用用户定义的windowFunction来处理window的contents
private void emitWindowContents(W window, ACC contents) throws Exception {
timestampedCollector.setAbsoluteTimestamp(window.maxTimestamp());
processContext.window = window;
userFunction.process(triggerContext.key, window, processContext, contents, timestampedCollector);
}Flink – process watermark的更多相关文章
- flink的watermark机制你学会了吗?
大家好,今天我们来聊一聊flink的Watermark机制. 这也是flink系列的的第一篇文章,如果对flink.大数据感兴趣的小伙伴,记得点个关注呀. 背景 flink作为先进的流水计算引擎, ...
- [白话解析] Flink的Watermark机制
[白话解析] Flink的Watermark机制 0x00 摘要 对于Flink来说,Watermark是个很难绕过去的概念.本文将从整体的思路上来说,运用感性直觉的思考来帮大家梳理Watermark ...
- [Flink] Flink的waterMark的通俗理解
导读 Flink 为实时计算提供了三种时间,即事件时间(event time).摄入时间(ingestion time)和处理时间(processing time). 遇到的问题: 假设在一个5秒的T ...
- Flink中watermark为什么选择最小一条(源码分析)
昨天在社区群看到有人问,为什么水印取最小的一条?这里分享一下自己的理解 首先水印一般是设置为:(事件时间 - 指定的值) 这里的作用是解决迟到数据的问题,从源码来看一下它如何解决的 先来看下wind ...
- [源码分析] 从源码入手看 Flink Watermark 之传播过程
[源码分析] 从源码入手看 Flink Watermark 之传播过程 0x00 摘要 本文将通过源码分析,带领大家熟悉Flink Watermark 之传播过程,顺便也可以对Flink整体逻辑有一个 ...
- 老板让阿粉学习 flink 中的 Watermark,现在他出教程了
1 前言 在时间 Time 那一篇中,介绍了三种时间概念 Event.Ingestin 和 Process, 其中还简单介绍了乱序 Event Time 事件和它的解决方案 Watermark 水位线 ...
- Flink Program Guide (5) -- 预定义的Timestamp Extractor / Watermark Emitter (DataStream API编程指导 -- For Java)
本文翻译自Pre-defined Timestamp Extractors / Watermark Emitter ------------------------------------------ ...
- Flink DataStream API Programming Guide
Example Program The following program is a complete, working example of streaming window word count ...
- <译>Flink编程指南
Flink 的流数据 API 编程指南 Flink 的流数据处理程序是常规的程序 ,通过再流数据上,实现了各种转换 (比如 过滤, 更新中间状态, 定义窗口, 聚合).流数据可以来之多种数据源 (比如 ...
随机推荐
- 【iCore4 双核心板_FPGA】例程十五:基于单口RAM的ARM+FPGA数据存取实验
实验现象: 写RAM命令格式:write:地址(0-255),数据(0-65535)\cr\lf 读RAM命令格式:read:地址(0-255)\cr\lf 核心代码: int main(void) ...
- qt在GUI显示时,将调试信息输出到控制台的设置
1. 在.pro文件中添加一下设置: CONFIG += console 2. 项目的[构建和运行]中,需要勾选[Run in terminal]:
- 关于Unity的两种调试方法
Unity的两种调试方法 1.Debug.Log()输出语句调试,平时经常用这个 2.把MonoDevelop和Unity进行连接后断点调试 先把编辑器选择为MonoDevelop,Edit----& ...
- 【转帖】流程与IT管理部——IT支撑业务变革的必然趋势
流程与IT管理部——IT支撑业务变革的必然趋势 1前言 伴随着中国企业的信息化进程, IT部门.IT专职人员已经在大部分企业获得了一席之地,电脑.网络.软件的维护都离不开这个部门:不过“一席之地”并不 ...
- Java Web项目中连接Access数据库的配置方法
本文是对前几天的"JDBC连接Access数据库的几种方式"这篇的升级.因为在做一些小项目的时候遇到的问题,因此才决定写这篇博客的.昨天已经将博客公布了.可是后来经过一些验证有点问 ...
- CALayer 知识:创建带阴影效果的圆角图片图层和创建自定义绘画内容图层
效果如下: KMLayerDelegate.h #import <UIKit/UIKit.h> @interface KMLayerDelegate : NSObject @end KML ...
- [Understanding] Compressive Sensing and Deep Model
低维模型与深度模型的殊途同归 有助理解核心,陌生概念需要加强理解. 对于做机器学习,和做图像视觉的研究者来说,过去的十年是非常激动人心的十年.以我个人来讲,非常有幸接触了两件事情: 第一件是压缩感知( ...
- 九、K3 WISE 开发插件《工业单据老单序时薄插件工具栏按钮开发实例》
=============================== 目录: 1.添加工具栏按钮 2.查询被添加工具栏按钮的业务单据的FMenuID和FID 3.添加工具栏按钮和业务单据的映射关系 4.工具 ...
- css - 兼容适配坑点总结(。。。)
1. transform为代表的这些css3属性一定要写-webkit-,不然低版本(目前遇到的是8)的苹果,不支持. 2. x的适配 /* x */ @media only screen and ( ...
- win2008在组件服务中未找到office组件服务
在win2003系统,cmd中输入 dcomcnfg ,组件服务里面找到office的组件服务,但win2008 R2 64位操作系统需要输入comexp.msc -32 tks:http://www ...