深入浅出Flink 10之 WaterMark机制原理

1 WaterMark的定义

使用eventTime的时候如何处理乱序数据?
我们知道,流处理从事件产生,到流经source,再到operator,中间是有一个过程和时间的。虽然大部
分情况下,流到operator的数据都是按照事件产生的时间顺序来的,但是也不排除由于网络延迟等原
因,导致乱序的产生,特别是使用kafka的话,多个分区的数据无法保证有序。所以在进行window计算
的时候,我们又不能无限期的等下去,必须要有个机制来保证一个特定的时间后,必须触发window去
进行计算了。这个特别的机制,就是watermark,watermark是用于处理乱序事件的。watermark可以
翻译为水位线

WaterMark是一种度量event Time进度的机制,
watermark作为数据流中的一部分在Stream中流动,
并携带time stamp 一个WaterMark(t) 表明在流中处理的EventTime已经到达了t,
那么在流中就不会再有Event Time小于 t的时间产生了。

有序的流的watermarks
在这里插入图片描述
多并行度流的watermarks
在这里插入图片描述

2 需求(深入理解WaterMark)

得到并打印每隔 3 秒钟统计相同的 key 的所有的事件(string)
相当于就是单词计数,每3s统计一次
背景:里面的数据可能就是乱序 = window + watermark

在这里插入图片描述
代码开发

/*** 得到并打印每隔 3 秒钟统计前 3 秒内的相同的 key 的所有的事件 3秒统计一卡。 单词计数 */ 
public class WaterMarkWindowWordCount { 
public static void main(String[] args) throws Exception{ 
StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment(); 
env.setParallelism(1); 
//步骤一:设置时间类型 env.setStreamTimeCharacteristic(TimeCharacteristic.EventTime); 
//设置waterMark产生的周期为1s 
env.getConfig().setAutoWatermarkInterval(1000); 
DataStreamSource<String> dataStream = env.socketTextStream("hadoop1", 8888);

dataStream.map(new MapFunction<String, Tuple2<String,Long>>() { 
@Override public Tuple2<String, Long> map(String line) throws Exception { 
		String[] fields = line.split(","); 
		return new Tuple2<>(fields[0],Long.valueOf(fields[1])); 
	}
//步骤二:获取数据里面的event Time 
}).assignTimestampsAndWatermarks(new EventTimeExtractor() ) 
.keyBy(0) 
	.timeWindow(Time.seconds(3)) 
	.process(new SumProcessWindowFunction()) 
	.print().setParallelism(1); 
	env.execute("TimeWindowWordCount");
 }
/**
* IN, OUT, KEY, W 
* IN:输入的数据类型 
* OUT:输出的数据类型 
* Key:key的数据类型(在Flink里面,String用Tuple表示) 
* W:Window的数据类型 */ 
public static class SumProcessWindowFunction extends ProcessWindowFunction<Tuple2<String,Long>,String,Tuple,TimeWindow> { 
FastDateFormat dateFormat = FastDateFormat.getInstance("HH:mm:ss");
/**
* 当一个window触发计算的时候会调用这个方法 
* @param tuple key
* @param context operator的上下文 
* @param elements 指定window的所有元素 
 * @param out 用户输出 */
 @Override public void process(Tuple tuple, Context context, Iterable<Tuple2<String, Long>> elements, Collector<String> out) {
 	System.out.println("处理时间:" + 	dateFormat.format(context.currentProcessingTime())); 
 	System.out.println("window start time : " + 	dateFormat.format(context.window().getStart())); 
		 List<String> list = new ArrayList<>(); 
 for (Tuple2<String, Long> ele : elements) { 
		 list.add(ele.toString() + "|" + dateFormat.format(ele.f1)); 
 }
	 out.collect(list.toString()); 
 		System.out.println("window end time : " + 							dateFormat.format(context.window().getEnd()));
 		 }
   }
private static class EventTimeExtractor implements AssignerWithPeriodicWatermarks<Tuple2<String, Long>> { 
FastDateFormat dateFormat = FastDateFormat.getInstance("HH:mm:ss");
 private long currentMaxEventTime = 0L; 
 private long maxOutOfOrderness = 10000;
 // 最大允许的乱序时间 1
  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值