聊聊flink水位线

本文深入探讨Flink中的水位线(水印)机制,解释了水位线作为逻辑时钟的概念,如何动态计算以及其在处理事件时间和窗口闭合中的作用。通过案例分析,展示了水位线如何触发窗口操作和定时任务执行,以及如何处理迟到数据。
摘要由CSDN通过智能技术生成

1、概述

flink中比较重要的是时间和状态,学习flink的过程中对水位线的理解一直模糊,经过一段时间的消化,在此总结总结。本文主要把水位线是什么,怎么来的,有什么用描述清楚。

2、不太好理解的水位线

有些人喜欢把水位线叫成水印,不管是水印还是水位线,中文翻译过来一点都不贴切我们的生活,比较抽象,让人难得理解。在我们生活中水位线类似家中挂在墙上的一个挂钟,类似我们的手表。下面来聊聊如下的话题:
1,到底是如何产生。
2,既然是一个挂钟,钟表有哪些特点呢,钟表每隔1s秒针往前走一小步,时间是不是越来越大,这些特点水位线是不是也有呢。
3,挂钟有什么用处啊?晚上看看手表发现12点,我们肯定自我暗示:“应该睡觉了”,通过时间让我们知道什么时间该干什么事情。

3、什么叫水位线

3.1、水位线的定义
水位线就是一个逻辑时钟,为什么叫逻辑时钟?正常时间是有cpu产生的,周期而固定的往前走,但是我们这个时钟的时间是程序员计算出来,根据"事件时间"动态计算出来(至于什么是时间事件,有什么使用场景这里就不讲了),如某一时刻计算的结果为x,x值为2022-10-10 10:10:10对应的时间戳为1665367810000,x的值随着事件时间的变大而变大,可能的结果为x,x+1,x+2,x+3,x+4 … 连续的越来越大的时间戳是不是类似钟表每隔1s往前走一步呢。
3.2、水位线(逻辑时钟)的组成
水位线由一串连续的时间戳组成,越来越大,每个时间戳都是根据事件时间动态计算出来的。时钟也是由一连续的时间组成,也是越来越大,如2022-10-10 10:10:10,2022-10-10 10:10:11,2022-10-10 10:10:12,2022-10-10 10:10:13 。。。等,水位线就是类似生活中的时钟,所以我把这个水位线称为逻辑时钟,逻辑时钟就是水位线,水印机制。
3.3、逻辑时钟当前时间
类似时钟的当前时间,此处此刻为几点几分几秒,这个当前时间比较重要,窗口的闭合,定时任务的触发都是根据当前时间来判断的。
当前值特点:越来越大,流刚刚产生的时候插入负无穷大值,结束是插入正无穷大的值。

个人觉得这个当前值类似一个指针类型的变量,他的指向是不停的变化的(个人理解)。

3.4、当前时间的计算公式
时钟的"当前时间"对应一个具体的时间戳。时钟的当前值xxx = 事件时间 - 最大延迟时间 - 1毫秒。
3.5、来一个案例
案例描述:从socket读取数据,并打印当前水位的具体值。

package com.deepexi.sql;

​

import org.apache.flink.api.common.eventtime.SerializableTimestampAssigner;

import org.apache.flink.api.common.eventtime.WatermarkStrategy;

import org.apache.flink.api.common.typeinfo.Types;

import org.apache.flink.api.java.tuple.Tuple2;

import org.apache.flink.streaming.api.environment.StreamExecutionEnvironment;

import org.apache.flink.streaming.api.functions.KeyedProcessFunction;

import org.apache.flink.util.Collector;

​

import java.time.Duration;

​

public class ExampleTest {
   

​

    public static void main(String[] args) throws Exception {
   

        StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment();

        env.setParallelism(1);

        env

                //从socket读取数据

                .socketTextStream("192.168.117.211", 9999)

                .map(r -> Tuple2.of(r.split(" ")[0], Long.parseLong(r.split(" ")[1])))

                .returns(Types.TUPLE(Types.STRING, Types.LONG))

                .assignTimestampsAndWatermarks(

                        //5s延迟时间

                        WatermarkStrategy.<Tuple2<String, Long>>forBoundedOutOfOrderness(Duration.ofSeconds(5))

                                .withTimestampAssigner(new SerializableTimestampAssigner<Tuple2<String, Long>>() {
   

                                    @Override

                                    public long extractTimestamp(Tuple2<String, Long> element, long recordTimestamp) {
   

                                        //提取事件时间

                                        return element.f1;

                                    }

                                })

                )

                //分流

                .keyBy(r -> r.f0)

                .process(new KeyedProcessFunction<String, Tuple2<String, Long>, String>() {
   

                    @Override

                    public void processElement(Tuple2<String, Long> value, Context ctx, Collector<String> out) throws Exception {
   

                        out.collect("当前的水位线是:" + ctx.timerService().currentWatermark());

                    }

                })

                .print();

​

        env.execute();

    }

​

}

nc -lk 9999 开启socket服务,监听9999端口
命令行输入:a 1000
[root@localhost ~]# nc -lk 9999 a 1000
idea控制台打印
当前的水位线是:-9223372036854775808 //-9223372036854775808是一个无穷大的数字

命令行输入:a 2000
idea控制台打印:
当前的水位线是:-4001 //当前水位线的值 = 事件时间 - 最大延迟时间 -1 = 1000 - 5000 -1 = -4000
为什么用1000- 5000 -1而用2000 - 5000 -1? flink会周期往流中插入水位线,水位线也是流中的一个元素,还是看下图理解吧。

命令行输入:a 3000
idea控制台打印:当前的水位线是:-3001 //2000 - 5000 -1 = -2000

命令行输入:a 10000
idea控制台打印:当前的水位线是:-2001 //3000 - 5000 -1 = -2000

命令行输入:a 1000
idea控制台打印:当前的水位线是:4999 //10000 - 5000 -1 = 4999

命令行输入:a 1000
idea控制台打印:当前的水位线是:4999 //10000 - 5000 -1 = 4999

命令行输入:a 2000
idea控制台打印:当前的水位线是:4999 //10000 - 5000 -1 = 4999

通过控制台的打印结果发现水位线的和钟表一样,值总是越来越大的,随着事件时间的变化而变化,但是不会变小,也可能会停止某一刻,如输入a 1000后在输入a 1000,a 2000水位线的值始终是4999。

整个打印过程
命令行窗口:

[root@master ~]# nc -lk 9999

a 1000

a 2000

a 3000

a 10000

a 1000

a 1000

a 2000

idea打印:

当前的水位线是:-9223372036854775808

当前的水位线是:-4001

当前的水位线是:-3001

当前的水位线是:-2001

当前的水位线是:4999

当前的水位线是:4999

当前的水位线是:4999

在这里插入图片描述

4、如何产生的

水位线本质就是一个时间戳,这个时间戳是程序员根据事件时间动态计算出来,直接来一个案例吧。
案例1
自定义水位线的产生逻辑,实现WatermarkStrategy接口,flink会每隔200毫秒的调用onPeriodicEmit方法。

public class ExampleTest2 {
   
  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值