广东医院项目Flink开发需求:定时定量窗口触发器(从入门到精通)

广东医院项目Flink开发需求:定时定量窗口触发器(从入门到精通)

背景

最近有局点客户有这么一个场景:利用Flink CDC读取MySql数据binlog日志,然后使用窗口进行聚合统计,遇到的问题就是Flink现有窗口的触发机制(定时或者定量)、不满足他们的实际需求(定时和定量)。温故而知新,可以为师矣。本文基于官网和源码梳理Flink现有窗口的类型、触发机制等内容。最后,基于自定义触发器实现定时定量触发机制解决该局点客户的实际场景问题。

Flink窗口分类

窗口是处理无限实时流的核心,将无界数据流切分为逻辑概念的桶、进行实际计算逻辑。

分类方法一

从窗口是否分组来说,Flink窗口分为两类:分组窗口(Keyed Windows)、非分组窗口(Non-Keyed Windows),单从概念上看,区别就是前者用于keyed streams(即keyby操作后的DataStream)、后者直接用于DataStream。

实际区别很大:keyed streams因为按照指定key(keyselector)进行分组、相同key的元素发送到相同subtask,所以keyed windows允许在多个subtask中并行化计算;而non-keyed streams不进行分组,所有non-keyed windows计算逻辑只能在单个stask中处理,即并行度只能为1。

分类方法二

从窗口属性来说,Flink窗口分为两类:基于时间的窗口(滚动窗口-Tumbling Window、滑动窗口-Sliding Window、会话窗口-Session Window)、基于计数的窗口(全局窗口-GlobalWindow)。很明显时间窗口与时间相关、每个窗口都有开始时间和结束时间;计数窗口与数据条数相关、与时间无关。内置的这几种窗口的详细介绍,后续单独发文描述。

两种分类相关性

两种分类方式的关系是什么呢?

从窗口是否分组的图中我们可以知道Keyed Windows使用window方法、Non-Keyed Windows使用windowAll方法,我们可以看下源码中这两个方法的使用情况。

这两个方法的入参都为WindowAssigner抽象类。

上图红线部分可以看出,window方法和windowAll方法都可以使用时间窗口和计数窗口;

上图标黄部分可以看出,window方法和windowAll方法可以使用相同的WindowAssigner(即TumblingWindow、SlidingWindow、GlobalWindow);

细心读者可能会发现,为何没有SessionWindows的踪影?

我们继续看下WindowAssigner抽象类的子类,一目了然、豁然开朗:

客户需求

客户原本是需要数据条数达到时触发后续操作,但是发现某些时间段(如非高峰期)数据条数长时间达不到以至于不触发后续操作。所以,需要本文开头所说的定量触发基础上加上定时触发。很显然,从上面介绍的Flink窗口分类来看,内置的这几类窗口类型并不满足(时间窗口属于定时触发、计数窗口属于定量触发)。

自定义触发器

那么,到底是选择计数窗口+自定义时间触发器还是时间窗口+自定义计数触发器?

根据现有Flink API架构上说,时间窗口+自定义计数触发器是唯一选择。

Trigger触发器决定了窗口function何时对窗口进行运算,自定义Trigger触发器需要继承实现Trigger抽象类。

该类包括抽象方法如下:

TriggerResult onElement(T element, long timestamp, W window, TriggerContext ctx)

TriggerResult onProcessingTime(long time, W window, TriggerContext ctx)

TriggerResult onEventTime(long time, W window, TriggerContext ctx)

boolean canMerge()

void onMerge(W window, OnMergeContext ctx)

void clear(W window, TriggerContext ctx)

该类有多种类型的实现子类,感兴趣可以自行阅读,方便自己实现自定义触发器:

案例实践:计数窗口

完整代码见github:

https://github.com/felixzh2020/felixzh-learning-flink/blob/master/MyWindowTrigger/src/main/java/CountWindowDemo.java

StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment();env.setParallelism(1);DataStream socket = env.socketTextStream(“felixzh”, 4444, “”);socket.windowAll(TumblingProcessingTimeWindows.of(Time.seconds(5)))//.windowAll(TumblingEventTimeWindows.of(Time.seconds(5))).process(new ProcessAllWindowFunction() {@Overridepublic void process(Context context, Iterable elements, Collector out) throws Exception {elements.forEach(value -> out.collect(value + ” ” + new Date()));}}).print();env.execute();

数据源:nc –l 4444

首先输入5个1(注意别忘回车)和1个2,过一会再输入4个2。

从上图可以看出,每5条数据触发一次窗口计算,效果与实际代码预期相符。

实际代码详见countWindowAll内部使用的CountTrigger触发器

public AllWindowedStream countWindowAll(long size) {return windowAll(GlobalWindows.create()).trigger(PurgingTrigger.of(CountTrigger.of(size)));}

案例实践:时间窗口

完整代码见github:

https://github.com/felixzh2020/felixzh-learning-flink/blob/master/MyWindowTrigger/src/main/java/TimeWindowDemo.java

StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment();env.setParallelism(1);DataStream socket = env.socketTextStream(“felixzh”, 4444, “”);socket.windowAll(TumblingProcessingTimeWindows.of(Time.seconds(5)))//.windowAll(TumblingEventTimeWindows.of(Time.seconds(5))).process(new ProcessAllWindowFunction() {@Overridepublic void process(Context context, Iterable elements, Collector out) throws Exception {elements.forEach(value -> out.collect(value + ” ” + new Date()));}}).print();env.execute();

数据源:nc –l 4444

首先输入任意字符如felixzh,然后分别5秒内和5秒后输入。

从上图可以看出,每5秒触发一次窗口计算,效果与实际代码预期相符。

实际代码详见TumblingProcessingTimeWindows内部使用的ProcessingTimeTrigger触发器。

案例实践:时间窗口+CountTrigger

乐于思考的朋友很容易想到,既然有时间窗口也有CountTrigger触发器,直接组合不就解决背景所述的定时定量触发了吗?不需要自定义计数触发器了吧?

该思路下的完整代码见github:

https://github.com/felixzh2020/felixzh-learning-flink/blob/master/MyWindowTrigger/src/main/java/TimeWindowAddCountTriggerDemo.java

StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment();env.setParallelism(1);DataStream socket = env.socketTextStream(“felixzh”, 4444, “”);CountTrigger countTrigger = CountTrigger.of(5);socket.windowAll(TumblingProcessingTimeWindows.of(Time.seconds(30))).trigger(countTrigger)//.windowAll(TumblingEventTimeWindows.of(Time.seconds(5))).process(new ProcessAllWindowFunction() {@Overridepublic void process(Context context, Iterable elements, Collector out) throws Exception {elements.forEach(value -> out.collect(value + ” ” + new Date()));}}).print();env.execute();

数据源:nc –l 4444

输入任意6行字符

从上图可以看出,即使等待30秒之后,实际效果并非预期。

预期的定时定量触发:即5条数据达到触发条件,就要触发计算,这点没毛病。

而30秒达到触发条件,并没有触发计算。

究其原因:ProcessingTimeTrigger触发器onProcessingTime方法返回TriggerResult.FIRE;而CountTrigger触发器onProcessingTime方法返回TriggerResult.CONTINUE。

看完TriggerResult枚举类,相信你会一目了然:

/** No action is taken on the window. */CONTINUE(false, false),/** {@code FIRE_AND_PURGE} evaluates the window function and emits the window result. */FIRE_AND_PURGE(true, true),/*** On {@code FIRE}, the window is evaluated and results are emitted. The window is not purged,* though, all elements are retained.*/FIRE(true, false),/*** All elements in the window are cleared and the window is discarded, without evaluating the* window function or emitting any elements.*/PURGE(false, true);

简而言之一句话:FIRE会触发计算,CONTINUE不会触发计算。

案例实践:时间窗口+自定义计数触发器

经过上述描述,我们还是需要实现自定义的计数触发器,需要区分事件时间和处理时间。

当然,思路还是借鉴CountTrigger触发器的已有内容。

定义MyCountTrigger自定义触发器继承Trigger,完整代码见github:

https://github.com/felixzh2020/felixzh-learning-flink/blob/master/MyWindowTrigger/src/main/java/MyCountTrigger.java

https://github.com/felixzh2020/felixzh-learning-flink/blob/master/MyWindowTrigger/src/main/java/TimeWindowAddMyCountTriggerDemo.java

案例实践代码如下:

StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment();env.setParallelism(1);DataStream socket = env.socketTextStream(“felixzh”, 4444, “”);socket.windowAll(TumblingProcessingTimeWindows.of(Time.seconds(30))).trigger(MyCountTrigger.of(5)).process(new ProcessAllWindowFunction() {@Overridepublic void process(Context context, Iterable elements, Collector out) throws Exception {elements.forEach(value -> out.collect(value + ” ” + new Date()));}}).print();env.execute();

数据源:nc –l 4444

输入任意6行字符

从上图可以看出,每5条数据触发一次窗口计算,每30秒触发一次窗口计算,效果与实际代码预期相符。

结论

以上,借鉴Flink原生CountTrigger和ProcessingTimeTrigger,实现自定义Trigger触发器,解决客户现场定时定量触发窗口聚合计算的效果。

郑重声明:本文内容及图片均整理自互联网,不代表本站立场,版权归原作者所有,如有侵权请联系管理员(admin#wlmqw.com)删除。
用户投稿
上一篇 2022年6月20日 23:18
下一篇 2022年6月20日 23:19

相关推荐

  • 分享4条发微商朋友圈的方法(微商朋友圈应该怎么发)

    对于微商朋友来说,朋友圈的重要性不言而喻了。 那么微商的朋友圈到底该怎么发呢? 为什么同样是经营一个朋友圈,有的微商看起来逼格满满,实际效果也不错;而有的却动都不动就被屏蔽甚至拉黑…

    2022年11月27日
  • 广东佛山瓷砖十大品牌有哪些(瓷砖十大名牌排行榜)

    关于瓷砖品牌的选择,经常有朋友问到这样的问题:中国的十大瓷砖品牌有哪些?近几年备受追捧的大角鹿瓷砖排名第几?今天小编就来为大家解答一下。 先来说第一个问题:中国十大瓷砖品牌有哪些?…

    2022年11月27日
  • 30个无加盟费的项目(茶颜悦色奶茶店加盟费多少)

    茶颜悦色又爆了,8月18日,茶颜悦色南京门店正式开业,开张不到半小时,门店就人满为患,消费者的购买热情十分高涨,而由于人流量过大造成拥堵,茶颜悦色也不得不暂停营业。 当然,这里面排…

    2022年11月27日
  • 净利润率越高越好吗(净利润率多少合适)

    一、持续增收不增利,平均净利润率首次跌入个位数 2021年,增收不增利依旧是行业主流。具体来看,大部分企业营业收入呈增长态势,E50企业平均同比增速达到17.3%,但是利润增速则明…

    2022年11月26日
  • 抖音带货怎么做入门(抖音带货怎么做入门教学)

    相信很多小伙伴都有注意到,现在抖音已经成为大家最常光顾的一个平台了,作为一个日活破亿的流量池,如今抖音上的用户数量极大。因此,现在在抖音上带货、卖货的人也是越来越多了,那么想在抖音…

    2022年11月25日
  • 《宝可梦朱紫》梦特性怎么获得?隐藏特性获取方法推荐

    宝可梦朱紫里有很多宝可梦都是拥有梦特性会变强的宝可梦,很多玩家不知道梦特性怎么获得,下面就给大家带来宝可梦朱紫隐藏特性获取方法推荐,感兴趣的小伙伴一起来看看吧,希望能帮助到大家。 …

    2022年11月25日
  • 《宝可梦朱紫》奇鲁莉安怎么进化?奇鲁莉安进化方法分享

    宝可梦朱紫中的奇鲁莉安要怎么进化呢?很多玩家都不知道,下面就给大家带来宝可梦朱紫奇鲁莉安进化方法分享,感兴趣的小伙伴一起来看看吧,希望能帮助到大家。 奇鲁莉安进化方法分享 奇鲁莉安…

    2022年11月25日
  • 5+3疫情防控从哪天开始算(辽宁疫情防控最新政策)

    最近有关国内各地的疫情大家也都有在持续关注,目前国内各地疫情隔离时间也根据二十条防控措施有了新的调整。那么,5+3疫情防控从哪天开始算?对于密接的5+3隔离时间计算大家还是比较关心…

    2022年11月25日
  • 蓝码怎么变绿码需要几天(蓝码怎么变绿码需要几天)

    大家都知道健康码的颜色有红码、绿码、黄码,近日湖南健康码上线“蓝码”,不少小伙伴发现自己健康码变蓝了,都想赶紧恢复绿码,那么蓝码怎么变绿码需要几天?下面小编为大家带来蓝码变绿码需要…

    2022年11月25日
  • 规范透明促PPP高质量发展——16万亿元大市场迎来新规

    近日,财政部印发《关于进一步推动政府和社会资本合作(PPP)规范发展、阳光运行的通知》,从做好项目前期论证、推动项目规范运作、严防隐性债务风险、保障项目阳光运行四个方面进一步规范P…

    2022年11月25日

联系我们

联系邮箱:admin#wlmqw.com
工作时间:周一至周五,10:30-18:30,节假日休息