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 的流数据处理程序是常规的程序 ,通过再流数据上,实现了各种转换 (比如 过滤, 更新中间状态, 定义窗口, 聚合).流数据可以来之多种数据源 (比如 ...
随机推荐
- 开始逐步补充下相关Web知识,很多年没搞了....
<script type="text/javascript"> $(function(){ ShowProduct(); $("#ShowUserInfo&q ...
- RNN,LSTM,GRU简单图解:
一篇经典的讲解RNN的,大部分网络图都来源于此:http://colah.github.io/posts/2015-08-Understanding-LSTMs/ 每一层每一时刻的输入输出:https ...
- default listener is not configured in grid infrastructure home
Oracle Restart enable database creation requries Default listener configured and running in Grid Inf ...
- tomcat启动时非常慢,启动时 一直卡在Root WebApplicationContext: initialization completed
每次重启自己的服务tomcat都需要卡住很长时间,每次都是日志停在 Root WebApplicationContext: initialization completed in 744 ms这个地方 ...
- maven 打jar 被引用后 出现 cannot resolve symbol 错误 生成jar包形式代码文件组织格式 非springboot文件组织格式
项目A引用项目B A项目中pom引入没有报错,但是:1,idea里面查找到b项目中的代码时,会提示b代码中的引用不正确.提示无法解析语法 解压B的jar,发现目录是: springboot文件组织格式 ...
- Vue获取DOM元素的属性值
项目中需要做一个小弹层,如下图: 我需要知道点击元素距离顶部的值,再计算弹层的top值,如下图: 在vue中如何获取到DOM元素距离窗口顶部的值呢? 1.通过$event获取 html: <di ...
- JavaScript高级用法一之事件响应与网页交互
综述 本篇的主要内容来自慕课网,事件响应与网页交互,主要内容如下 1 什么是事件 2 鼠标单击事件( onclick ) 3 鼠标经过事件(onmouseover) 4 鼠标移开事件(onmouseo ...
- Java如何从文件中打印与给定模式匹配的所有字符串?
在Java编程中,如何从文件中打印与给定模式匹配的所有字符串? 以下示例显示了如何使用Util.regex类的Patternname.matcher()方法从文件中打印与给定模式匹配的所有字符串. p ...
- SharePreferences
SharePreferences是一种轻量级的数据存储方式,它是以key-value的形式保存在 data/data/<packagename>/shared_prefs 下的xml文件中 ...
- Android图片处理(Matrix,ColorMatrix)
转发说明:原文链接http://www.cnblogs.com/leon19870907/articles/1978065.html 在编程中有时候需要对图片做特殊的处理,比如将图片做出黑白的,或者老 ...