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的更多相关文章

  1. flink的watermark机制你学会了吗?

    大家好,今天我们来聊一聊flink的Watermark机制. 这也是flink系列的的第一篇文章,如果对flink.大数据感兴趣的小伙伴,记得点个关注呀. 背景 ​ flink作为先进的流水计算引擎, ...

  2. [白话解析] Flink的Watermark机制

    [白话解析] Flink的Watermark机制 0x00 摘要 对于Flink来说,Watermark是个很难绕过去的概念.本文将从整体的思路上来说,运用感性直觉的思考来帮大家梳理Watermark ...

  3. [Flink] Flink的waterMark的通俗理解

    导读 Flink 为实时计算提供了三种时间,即事件时间(event time).摄入时间(ingestion time)和处理时间(processing time). 遇到的问题: 假设在一个5秒的T ...

  4. Flink中watermark为什么选择最小一条(源码分析)

    昨天在社区群看到有人问,为什么水印取最小的一条?这里分享一下自己的理解 首先水印一般是设置为:(事件时间 - 指定的值)  这里的作用是解决迟到数据的问题,从源码来看一下它如何解决的 先来看下wind ...

  5. [源码分析] 从源码入手看 Flink Watermark 之传播过程

    [源码分析] 从源码入手看 Flink Watermark 之传播过程 0x00 摘要 本文将通过源码分析,带领大家熟悉Flink Watermark 之传播过程,顺便也可以对Flink整体逻辑有一个 ...

  6. 老板让阿粉学习 flink 中的 Watermark,现在他出教程了

    1 前言 在时间 Time 那一篇中,介绍了三种时间概念 Event.Ingestin 和 Process, 其中还简单介绍了乱序 Event Time 事件和它的解决方案 Watermark 水位线 ...

  7. Flink Program Guide (5) -- 预定义的Timestamp Extractor / Watermark Emitter (DataStream API编程指导 -- For Java)

    本文翻译自Pre-defined Timestamp Extractors / Watermark Emitter ------------------------------------------ ...

  8. Flink DataStream API Programming Guide

    Example Program The following program is a complete, working example of streaming window word count ...

  9. <译>Flink编程指南

    Flink 的流数据 API 编程指南 Flink 的流数据处理程序是常规的程序 ,通过再流数据上,实现了各种转换 (比如 过滤, 更新中间状态, 定义窗口, 聚合).流数据可以来之多种数据源 (比如 ...

随机推荐

  1. vue子父组件的通信

    Element使用的是Vue2.0版本,众所周知在Vue 1.0升级到2.0中去除了$broadcast和$dispatch方法. 1.父组件向子组件传值 a.app.vue父组件 <templ ...

  2. [转]MySql 5.7关键字和保留字-附表

    原文地址:https://www.cnblogs.com/Z-Fanghan/p/6892944.html 现在使用navicat图形界面或者Hibernate做映射生成表的时候,渐渐的会忽视掉关键字 ...

  3. STM32F103VET6 ADC采集64点做FFT变换

    http://www.stmcu.org/module/forum/thread-598459-1-11.html http://bbs.21ic.com/icview-589756-1-1.html ...

  4. JVM 内部原理(五)— 基本概念之 Java 虚拟机官方规范文档,第 7 版

    JVM 内部原理(五)- 基本概念之 Java 虚拟机官方规范文档,第 7 版 介绍 版本:Java SE 7 每位使用 Java 的程序员都知道 Java 字节码在 Java 运行时(JRE - J ...

  5. ssh-remote-port-forwarding

    1.ssh免密码登录(A登录到B) 1.1.在A上执行并在~/.ssh下生成id_rsa和id_rsa.pub两个文件 ssh-keygen -t rsa -P '' 1.2.拷贝id_rsa.pub ...

  6. Android 5.0 Phone初始化分析

    已经更新至个人blog:http://dxjia.cn/2015/07/android-5-0-phone-init-analysis/ persistent属性 要想了解phone的框架,首先需要了 ...

  7. JavaScript高级用法一之事件响应与网页交互

    综述 本篇的主要内容来自慕课网,事件响应与网页交互,主要内容如下 1 什么是事件 2 鼠标单击事件( onclick ) 3 鼠标经过事件(onmouseover) 4 鼠标移开事件(onmouseo ...

  8. C++ 智能指针四

    /* 智能指针enable_shared_from_this模板类使用 */ #include <iostream> #include <string> #include &l ...

  9. [Tensorflow] RNN - 01. Spam Prediction with BasicRNNCell

    Ref: http://blog.csdn.net/mebiuw/article/details/60780813 Ref: https://medium.com/@erikhallstrm/hell ...

  10. 网络编程 -- RPC实现原理 -- NIO多线程 -- 迭代版本V2

    网络编程 -- RPC实现原理 -- 目录 啦啦啦 V2——增加WriteQueue队列,存放selectionKey.addWriteEventToQueue()添加selectionKey并唤醒阻 ...