package com.chenxiang.flink.demo;

import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Scanner; /**
* @author 闪电侠
*/
public class IOServer { public static void main(String[] args) throws Exception {
ServerSocket serverSocket = new ServerSocket(9999); // (1) 接收新连接线程
new Thread(() -> {
while (true) {
try {
// (1) 阻塞方法获取新的连接
Socket socket = serverSocket.accept(); // (2) 每一个新的连接都创建一个线程,负责读取数据
new Thread(() -> {
try {
while (true) {
socket.getOutputStream().write(new Scanner(System.in).next().getBytes());
}
} catch (IOException e) {
}
}).start(); } catch (IOException e) {
} }
}).start();
}
}

首先window的时间范围是一个自然时间范围,比如你定义了一个

TumblingEventTimeWindows.of(Time.seconds(3))
窗口,那么会生成类似如下的窗口(左闭右开):

[2018-03-03 03:30:00,2018-03-03 03:30:03)

[2018-03-03 03:30:03,2018-03-03 03:30:06)

...

[2018-03-03 03:30:57,2018-03-03 03:31:00)

当一个event time=2018-03-03 03:30:01的消息到来时,就会生成[2018-03-03 03:30:00,2018-03-03 03:30:03)这个窗口(而不是[2018-03-03 03:30:01,2018-03-03 03:30:04)这样的窗口),然后将消息buffer在这个窗口中(此时还不会触发窗口的计算),

当watermark(可以翻译成水位线,只会不断上升,不会下降,用来保证在水位线之前的数据一定都到达,org.apache.flink.streaming.api.datastream.DataStream#assignTimestampsAndWatermarks(org.apache.flink.streaming.api.functions.AssignerWithPeriodicWatermarks<T>)来定制水位线生成策略)超过窗口的endTime时,才会真正触发窗口计算逻辑,然后清除掉该窗口。这样后续再有在该窗口区间内的数据到来时(延迟到来的数据),将被丢弃不被处理。有时候我们希望可以容忍一定时间的数据延迟,我们可以通过org.apache.flink.streaming.api.datastream.WindowedStream#allowedLateness方法来指定一个允许的延迟时间,比如allowedLateness(Time.seconds(5))允许5秒延迟,还是用上面的样例距离,当watermark到达2018-03-03 03:30:03时,将不会移除窗口,但是会触发窗口计算函数,由于窗口还在,所以当还有延迟的消息时间落在该窗口范围内时,比如又有一条消息2018-03-03 03:30:02到来(已经小于水位线时间2018-03-03 03:30:03),将会再次触发窗口计算函数。

那么什么时候这个窗口会被移除后续的延迟数据将不被处理呢?比如[2018-03-03 03:30:00,2018-03-03 03:30:03)这个窗口,当允许延迟5秒时,将在watermark到达2018-03-03 03:30:08时(即[watermark-5秒=2018-03-03 03:30:03]到达窗口的endTime时),[2018-03-03 03:30:00,2018-03-03 03:30:03)这个窗口将被移除,后续再有事件时间落在该窗口的数据到来,将丢弃不处理。

附一个demo测试程序:

package windowing;

import org.apache.flink.api.common.functions.MapFunction;
import org.apache.flink.api.java.tuple.Tuple;
import org.apache.flink.api.java.tuple.Tuple2;
import org.apache.flink.streaming.api.TimeCharacteristic;
import org.apache.flink.streaming.api.datastream.DataStream;
import org.apache.flink.streaming.api.environment.StreamExecutionEnvironment;
import org.apache.flink.streaming.api.functions.AssignerWithPeriodicWatermarks;
import org.apache.flink.streaming.api.functions.windowing.WindowFunction;
import org.apache.flink.streaming.api.watermark.Watermark;
import org.apache.flink.streaming.api.windowing.assigners.TumblingEventTimeWindows;
import org.apache.flink.streaming.api.windowing.time.Time;
import org.apache.flink.streaming.api.windowing.windows.TimeWindow;
import org.apache.flink.util.Collector; import java.text.SimpleDateFormat;
import java.util.Comparator;
import java.util.Date;
import java.util.LinkedList; /**
*
* @author : xiaojun
* @since 9:47 2018/4/2
*/
public class WatermarkTest {
public static void main(String[] args) throws Exception { //2018/3/3 3:30:0
Long baseTimestamp = 1520019000000L; StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment();
env.setStreamTimeCharacteristic(TimeCharacteristic.EventTime);
env.getConfig().setAutoWatermarkInterval(2000);
env.setParallelism(1); DataStream<Tuple2<String, Long>> raw = env.socketTextStream("localhost", 9999, "\n").map(new MapFunction<String, Tuple2<String, Long>>() {
@Override
public Tuple2<String, Long> map(String value) throws Exception {
//每行输入数据形如: key1@0,key1@13等等,即在baseTimestamp的基础上加多少秒,作为当前event time
String[] tmp = value.split("@");
Long ts = baseTimestamp + Long.parseLong(tmp[1]) * 1000;
return Tuple2.of(tmp[0], ts);
}
}).assignTimestampsAndWatermarks(new MyTimestampExtractor(Time.seconds(10))); //允许10秒乱序,watermark为当前接收到的最大事件时间戳减10秒 DataStream<String> window = raw.keyBy(0)
//窗口都为自然时间窗口,而不是说从收到的消息时间为窗口开始时间来进行开窗,比如3秒的窗口,那么窗口一次是[0,3),[3,6)....[57,0),如果10秒窗口,那么[0,10),[10,20),...
.window(TumblingEventTimeWindows.of(Time.seconds(3)))
// 允许5秒延迟
//比如窗口[2018-03-03 03:30:00,2018-03-03 03:30:03),如果没有允许延迟的话,那么当watermark到达2018-03-03 03:30:03的时候,将会触发窗口函数并移除窗口,这样2018-03-03 03:30:03之前的数据再来,将被丢弃
//在允许5秒延迟的情况下,那么窗口的移除时间将到watermark为2018-03-03 03:30:08,在watermark没有到达这个时间之前,你输入2018-03-03 03:30:00这个时间,将仍然会触发[2018-03-03 03:30:00,2018-03-03 03:30:03)这个窗口的计算
.allowedLateness(Time.seconds(5))
.apply(new WindowFunction<Tuple2<String, Long>, String, Tuple, TimeWindow>() {
@Override
public void apply(Tuple tuple, TimeWindow window, Iterable<Tuple2<String, Long>> input, Collector<String> out) throws Exception {
LinkedList<Tuple2<String, Long>> data = new LinkedList<>();
for (Tuple2<String, Long> tuple2 : input) {
data.add(tuple2);
}
data.sort(new Comparator<Tuple2<String, Long>>() {
@Override
public int compare(Tuple2<String, Long> o1, Tuple2<String, Long> o2) {
return o1.f1.compareTo(o2.f1);
}
});
SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
String msg = String.format("key:%s, window:[ %s , %s ), elements count:%d, elements time range:[ %s , %s ]", tuple.getField(0)
, format.format(new Date(window.getStart()))
, format.format(new Date(window.getEnd()))
, data.size()
, format.format(new Date(data.getFirst().f1))
, format.format(new Date(data.getLast().f1))
);
out.collect(msg); }
});
window.print(); env.execute(); } public static class MyTimestampExtractor implements AssignerWithPeriodicWatermarks<Tuple2<String, Long>> { private static final long serialVersionUID = 1L; /**
* The current maximum timestamp seen so far.
*/
private long currentMaxTimestamp; /**
* The timestamp of the last emitted watermark.
*/
private long lastEmittedWatermark = Long.MIN_VALUE; /**
* The (fixed) interval between the maximum seen timestamp seen in the records
* and that of the watermark to be emitted.
*/
private final long maxOutOfOrderness; private SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); public MyTimestampExtractor(Time maxOutOfOrderness) {
if (maxOutOfOrderness.toMilliseconds() < 0) {
throw new RuntimeException("Tried to set the maximum allowed " +
"lateness to " + maxOutOfOrderness + ". This parameter cannot be negative.");
}
this.maxOutOfOrderness = maxOutOfOrderness.toMilliseconds();
this.currentMaxTimestamp = Long.MIN_VALUE + this.maxOutOfOrderness;
} public long getMaxOutOfOrdernessInMillis() {
return maxOutOfOrderness;
} @Override
public final Watermark getCurrentWatermark() {
// this guarantees that the watermark never goes backwards.
long potentialWM = currentMaxTimestamp - maxOutOfOrderness;
if (potentialWM >= lastEmittedWatermark) {
lastEmittedWatermark = potentialWM;
}
System.out.println(String.format("call getCurrentWatermark======currentMaxTimestamp:%s , lastEmittedWatermark:%s", format.format(new Date(currentMaxTimestamp)), format.format(new Date(lastEmittedWatermark))));
return new Watermark(lastEmittedWatermark);
} @Override
public final long extractTimestamp(Tuple2<String, Long> element, long previousElementTimestamp) {
long timestamp = element.f1;
if (timestamp > currentMaxTimestamp) {
currentMaxTimestamp = timestamp;
}
return timestamp;
}
}
}

赋windows上的nc工具:

https://download.csdn.net/download/xiao_jun_0820/10322207

启动本地9999端口:nc -l -p 9999
监听本地9999端口:nc localhost 9999

结果

1)
.assignTimestampsAndWatermarks(new MyTimestampExtractor(Time.seconds(0))); //允许0秒乱序,watermark为当前接收到的最大事件时间戳减10秒
.window(TumblingEventTimeWindows.of(Time.seconds(3)))
.allowedLateness(Time.seconds(5))
[2018-03-03 03:30:00, 2018-03-03 03:30:03)
[2018-03-03 03:30:03, 2018-03-03 03:30:06)
[2018-03-03 03:30:06, 2018-03-03 03:30:09)
key1@1
key1@3 //触发窗口[2018-03-03 03:30:00,2018-03-03 03:30:03)计算
key:key1, window:[ 2018-03-03 03:30:00 , 2018-03-03 03:30:03 ), elements count:1, elements time range:[ 2018-03-03 03:30:01 , 2018-03-03 03:30:01 ]
key1@2
call getCurrentWatermark======currentMaxTimestamp:2018-03-03 03:30:03 , lastEmittedWatermark:2018-03-03 03:30:03
======extractTimestamp======,currentMaxTimestamp:2018-03-03 03:30:03 , lastEmittedWatermark:2018-03-03 03:30:03
key:key1, window:[ 2018-03-03 03:30:00 , 2018-03-03 03:30:03 ), elements count:2, elements time range:[ 2018-03-03 03:30:01 , 2018-03-03 03:30:02 ]
call getCurrentWatermark======currentMaxTimestamp:2018-03-03 03:30:03 , lastEmittedWatermark:2018-03-03 03:30:03
key1@1
call getCurrentWatermark======currentMaxTimestamp:2018-03-03 03:30:03 , lastEmittedWatermark:2018-03-03 03:30:03
======extractTimestamp======,currentMaxTimestamp:2018-03-03 03:30:03 , lastEmittedWatermark:2018-03-03 03:30:03
key:key1, window:[ 2018-03-03 03:30:00 , 2018-03-03 03:30:03 ), elements count:3, elements time range:[ 2018-03-03 03:30:01 , 2018-03-03 03:30:02 ]
call getCurrentWatermark======currentMaxTimestamp:2018-03-03 03:30:03 , lastEmittedWatermark:2018-03-03 03:30:03 key1@4
call getCurrentWatermark======currentMaxTimestamp:2018-03-03 03:30:03 , lastEmittedWatermark:2018-03-03 03:30:03
======extractTimestamp======,currentMaxTimestamp:2018-03-03 03:30:04 , lastEmittedWatermark:2018-03-03 03:30:03
call getCurrentWatermark======currentMaxTimestamp:2018-03-03 03:30:04 , lastEmittedWatermark:2018-03-03 03:30:04
key1@6
======extractTimestamp======,currentMaxTimestamp:2018-03-03 03:30:06 , lastEmittedWatermark:2018-03-03 03:30:04
call getCurrentWatermark======currentMaxTimestamp:2018-03-03 03:30:06 , lastEmittedWatermark:2018-03-03 03:30:06
key:key1, window:[ 2018-03-03 03:30:03 , 2018-03-03 03:30:06 ), elements count:2, elements time range:[ 2018-03-03 03:30:03 , 2018-03-03 03:30:04 ]
call getCurrentWatermark======currentMaxTimestamp:2018-03-03 03:30:06 , lastEmittedWatermark:2018-03-03 03:30:06
key1@1
call getCurrentWatermark======currentMaxTimestamp:2018-03-03 03:30:06 , lastEmittedWatermark:2018-03-03 03:30:06
======extractTimestamp======,currentMaxTimestamp:2018-03-03 03:30:06 , lastEmittedWatermark:2018-03-03 03:30:06
key:key1, window:[ 2018-03-03 03:30:00 , 2018-03-03 03:30:03 ), elements count:4, elements time range:[ 2018-03-03 03:30:01 , 2018-03-03 03:30:02 ]
call getCurrentWatermark======currentMaxTimestamp:2018-03-03 03:30:06 , lastEmittedWatermark:2018-03-03 03:30:06 key1@8 //因为5秒延迟,上一个窗口不触发并销毁
call getCurrentWatermark======currentMaxTimestamp:2018-03-03 03:30:06 , lastEmittedWatermark:2018-03-03 03:30:06
======extractTimestamp======,currentMaxTimestamp:2018-03-03 03:30:08 , lastEmittedWatermark:2018-03-03 03:30:06
call getCurrentWatermark======currentMaxTimestamp:2018-03-03 03:30:08 , lastEmittedWatermark:2018-03-03 03:30:08
key1@1
call getCurrentWatermark======currentMaxTimestamp:2018-03-03 03:30:08 , lastEmittedWatermark:2018-03-03 03:30:08
======extractTimestamp======,currentMaxTimestamp:2018-03-03 03:30:08 , lastEmittedWatermark:2018-03-03 03:30:08
call getCurrentWatermark======currentMaxTimestamp:2018-03-03 03:30:08 , lastEmittedWatermark:2018-03-03 03:30:08
key1@9
call getCurrentWatermark======currentMaxTimestamp:2018-03-03 03:30:08 , lastEmittedWatermark:2018-03-03 03:30:08
======extractTimestamp======,currentMaxTimestamp:2018-03-03 03:30:09 , lastEmittedWatermark:2018-03-03 03:30:08
call getCurrentWatermark======currentMaxTimestamp:2018-03-03 03:30:09 , lastEmittedWatermark:2018-03-03 03:30:09
key:key1, window:[ 2018-03-03 03:30:06 , 2018-03-03 03:30:09 ), elements count:2, elements time range:[ 2018-03-03 03:30:06 , 2018-03-03 03:30:08 ]
call getCurrentWatermark======currentMaxTimestamp:2018-03-03 03:30:09 , lastEmittedWatermark:2018-03-03 03:30:09
key1@5
======extractTimestamp======,currentMaxTimestamp:2018-03-03 03:30:09 , lastEmittedWatermark:2018-03-03 03:30:09
key:key1, window:[ 2018-03-03 03:30:03 , 2018-03-03 03:30:06 ), elements count:3, elements time range:[ 2018-03-03 03:30:03 , 2018-03-03 03:30:05 ]
call getCurrentWatermark======currentMaxTimestamp:2018-03-03 03:30:09 , lastEmittedWatermark:2018-03-03 03:30:09 2)
.assignTimestampsAndWatermarks(new MyTimestampExtractor(Time.seconds(10))); //允许10秒乱序,watermark为当前接收到的最大事件时间戳减10秒
.window(TumblingEventTimeWindows.of(Time.seconds(3)))
.allowedLateness(Time.seconds(5))
[2018-03-03 03:30:00, 2018-03-03 03:30:03)
[2018-03-03 03:30:03, 2018-03-03 03:30:06)
[2018-03-03 03:30:06, 2018-03-03 03:30:09)
key1@1
call getCurrentWatermark======currentMaxTimestamp:292269055-12-03 00:47:14 , lastEmittedWatermark:292269055-12-03 00:47:04
======extractTimestamp======,currentMaxTimestamp:2018-03-03 03:30:01 , lastEmittedWatermark:292269055-12-03 00:47:04
call getCurrentWatermark======currentMaxTimestamp:2018-03-03 03:30:01 , lastEmittedWatermark:2018-03-03 03:29:51
key1@3
call getCurrentWatermark======currentMaxTimestamp:2018-03-03 03:30:01 , lastEmittedWatermark:2018-03-03 03:29:51
======extractTimestamp======,currentMaxTimestamp:2018-03-03 03:30:03 , lastEmittedWatermark:2018-03-03 03:29:51
call getCurrentWatermark======currentMaxTimestamp:2018-03-03 03:30:03 , lastEmittedWatermark:2018-03-03 03:29:53
key1@13
call getCurrentWatermark======currentMaxTimestamp:2018-03-03 03:30:03 , lastEmittedWatermark:2018-03-03 03:29:53
======extractTimestamp======,currentMaxTimestamp:2018-03-03 03:30:13 , lastEmittedWatermark:2018-03-03 03:29:53
call getCurrentWatermark======currentMaxTimestamp:2018-03-03 03:30:13 , lastEmittedWatermark:2018-03-03 03:30:03
key:key1, window:[ 2018-03-03 03:30:00 , 2018-03-03 03:30:03 ), elements count:1, elements time range:[ 2018-03-03 03:30:01 , 2018-03-03 03:30:01 ]
call getCurrentWatermark======currentMaxTimestamp:2018-03-03 03:30:13 , lastEmittedWatermark:2018-03-03 03:30:03
key1@1
call getCurrentWatermark======currentMaxTimestamp:2018-03-03 03:30:13 , lastEmittedWatermark:2018-03-03 03:30:03
======extractTimestamp======,currentMaxTimestamp:2018-03-03 03:30:13 , lastEmittedWatermark:2018-03-03 03:30:03
key:key1, window:[ 2018-03-03 03:30:00 , 2018-03-03 03:30:03 ), elements count:2, elements time range:[ 2018-03-03 03:30:01 , 2018-03-03 03:30:01 ]
call getCurrentWatermark======currentMaxTimestamp:2018-03-03 03:30:13 , lastEmittedWatermark:2018-03-03 03:30:03

---------------------
原文:https://blog.csdn.net/xiao_jun_0820/article/details/79786517

flink中对于window和watermark的一些理解的更多相关文章

  1. Flink中的window、watermark和ProcessFunction

    一.Flink中的window 1,window简述  window 是一种切割无限数据为有限块进行处理的手段.Window 是无限数据流处理的核心,Window 将一个无限的 stream 拆分成有 ...

  2. 彻底搞清Flink中的Window

    窗口 在流处理应用中,数据是连续不断的,因此我们不可能等到所有数据都到了才开始处理.当然我们可以每来一个消息就处理一次,但是有时我们需要做一些聚合类的处理,例如:在过去的1分钟内有多少用户点击了我们的 ...

  3. Flink中的多source+event watermark测试

    这次需要做一个监控项目,全网日志的指标计算,上线的话,计算量应该是百亿/天 单个source对应的sql如下 最原始的sql select pro,throwable,level,ip,`count` ...

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

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

  5. Flink 中极其重要的 Time 与 Window 详细解析(深度好文,建议收藏)

    前言 Flink 是流式的.实时的 计算引擎 上面一句话就有两个概念,一个是流式,一个是实时. 流式:就是数据源源不断的流进来,也就是数据没有边界,但是我们计算的时候必须在一个有边界的范围内进行,所以 ...

  6. 如何在 Apache Flink 中使用 Python API?

    本文根据 Apache Flink 系列直播课程整理而成,由 Apache Flink PMC,阿里巴巴高级技术专家 孙金城 分享.重点为大家介绍 Flink Python API 的现状及未来规划, ...

  7. 「Flink」Flink中的时间类型

    Flink中的时间类型和窗口是非常重要概念,是学习Flink必须要掌握的两个知识点. Flink中的时间类型 时间类型介绍 Flink流式处理中支持不同类型的时间.分为以下几种: 处理时间 Flink ...

  8. Flink学习(二)Flink中的时间

    摘自Apache Flink官网 最早的streaming 架构是storm的lambda架构 分为三个layer batch layer serving layer speed layer 一.在s ...

  9. 《从0到1学习Flink》—— Flink 中几种 Time 详解

    前言 Flink 在流程序中支持不同的 Time 概念,就比如有 Processing Time.Event Time 和 Ingestion Time. 下面我们一起来看看这几个 Time: Pro ...

随机推荐

  1. Linux v4l2编程(摄像头信息采集)

    基于Linux3.4.2,自己做一点儿视频信息采集及网络传输的小实验,边做边学,一些基础知识同步整理..... 1. 定义 V4L2(Video For Linux Two) 是内核提供给应用程序访问 ...

  2. java并发编程笔记(二)——并发工具

    java并发编程笔记(二)--并发工具 工具: Postman:http请求模拟工具 Apache Bench(AB):Apache附带的工具,测试网站性能 JMeter:Apache组织开发的压力测 ...

  3. 58、salesforce学习笔记(五)

    Set集合 Set<String> set1 = new Set<String>(); set1.add('1'); set1.add('2'); Set<String& ...

  4. C#中Json转换主要使用的几种方法!

    这篇主要介绍2.4.第三种方法使用的比较局限,所以我没有深入学习. 第二种方法 我使用比较多的方式,这个方法是.NET内置的,使用起来比较方便 A.利用serializer获取json的泛型对象 利用 ...

  5. JavaScript类型和语法

    JavaScript类型和语法 一.类型 1.内置类型(null.undefined.boolean.number.string.object.symbol(es6中新增))(除对象之外,其它统称为基 ...

  6. [已解决]报错: Creating Server TCP listening socket 127.0.0.1:6379: bind: No error

    问题: windows下安装Redis第一次启动报错: [2368] 21 Apr 02:57:05.611 # Creating Server TCP listening socket 127.0. ...

  7. SQL语句的执行顺序和效率

    今天上午在开发的过程中,突然遇到一个问题,需要了解SQL语句的执行顺序才能继续,上网上查了一下相关的资料,现整理如下:一.sql语句的执行步骤: 1)语法分析,分析语句的语法是否符合规范,衡量语句中各 ...

  8. python while循坏和for循坏

    while循坏 while 条件: 条件成立,执行循坏体(注意,while循坏必须有结束条件,不然会进入死循坏) 简单做个演示: # -*- coding:utf-8 -*- # Author:覃振鸿 ...

  9. 手机作为蓝牙音频源连接到Linux时,如何通过音量键调节传入的音量大小

    背景一: 我们知道,把手机作为音频源通过蓝牙连接到电脑,就可以把手机的声音转移到电脑上. 背景二: 我喜欢带着耳机用我的Linux本刷youtube,也喜欢用我的iPhone听音乐.为了同时做这两件事 ...

  10. hbuilder 配置app为沉浸式状态栏