Flink-v1.12官方网站翻译-P009-Event-driven Applications
事件驱动的应用
处理函数
简介
ProcessFunction将事件处理与定时器和状态结合起来,使其成为流处理应用的强大构件。这是用Flink创建事件驱动应用的基础。它与RichFlatMapFunction非常相似,但增加了定时器。
例子
如果你做过 "流分析 "培训中的实战练习,你会记得它使用TumblingEventTimeWindow来计算每个司机在每个小时内的小费总和,像这样。
// compute the sum of the tips per hour for each driver
DataStream<Tuple3<Long, Long, Float>> hourlyTips = fares
.keyBy((TaxiFare fare) -> fare.driverId)
.window(TumblingEventTimeWindows.of(Time.hours(1)))
.process(new AddTips());
用KeyedProcessFunction做同样的事情是相当直接的,也是很有教育意义的。让我们先把上面的代码替换成这样。
// compute the sum of the tips per hour for each driver
DataStream<Tuple3<Long, Long, Float>> hourlyTips = fares
.keyBy((TaxiFare fare) -> fare.driverId)
.process(new PseudoWindow(Time.hours(1)));
在这段代码中,一个名为PseudoWindow的KeyedProcessFunction被应用于一个键控流,其结果是一个DataStream<Tuple3<Long,Long,Float>>(就是使用Flink内置时间窗口的实现所产生的那种流)。
PseudoWindow的整体轮廓是这样的形状。
// Compute the sum of the tips for each driver in hour-long windows.
// The keys are driverIds.
public static class PseudoWindow extends
KeyedProcessFunction<Long, TaxiFare, Tuple3<Long, Long, Float>> { private final long durationMsec; public PseudoWindow(Time duration) {
this.durationMsec = duration.toMilliseconds();
} @Override
// Called once during initialization.
public void open(Configuration conf) {
. . .
} @Override
// Called as each fare arrives to be processed.
public void processElement(
TaxiFare fare,
Context ctx,
Collector<Tuple3<Long, Long, Float>> out) throws Exception { . . .
} @Override
// Called when the current watermark indicates that a window is now complete.
public void onTimer(long timestamp,
OnTimerContext context,
Collector<Tuple3<Long, Long, Float>> out) throws Exception { . . .
}
}
需要注意的事情。
- ProcessFunctions有好几种类型--这是一个KeyedProcessFunctions,但还有CoProcessFunctions、BroadcastProcessFunctions等。
- KeyedProcessFunction是RichFunction的一种。作为一个RichFunction,它可以访问在管理键控状态下工作所需的open和getRuntimeContext方法。
- 有两个回调要实现:processElement和onTimer。"processElement "在每次传入事件时被调用;"onTimer "在定时器发射时被调用。这些定时器可以是事件时间,也可以是处理时间定时器。processElement和onTimer都提供了一个上下文对象,该对象可以用来与TimerService交互(除其他外)。这两个回调也都传递了一个可以用来发出结果的Collector。
open()方法
// Keyed, managed state, with an entry for each window, keyed by the window's end time.
// There is a separate MapState object for each driver.
private transient MapState<Long, Float> sumOfTips; @Override
public void open(Configuration conf) { MapStateDescriptor<Long, Float> sumDesc =
new MapStateDescriptor<>("sumOfTips", Long.class, Float.class);
sumOfTips = getRuntimeContext().getMapState(sumDesc);
}
由于票价事件可能会不按顺序到达,所以有时需要处理一个小时的事件,然后再完成前一个小时的结果计算。事实上,如果水印延迟比窗口长度长得多,那么可能会有许多窗口同时打开,而不是只有两个。本实现通过使用MapState来支持这一点,MapState将每个窗口结束的时间戳映射到该窗口的提示之和。
processElement()方法
public void processElement(
TaxiFare fare,
Context ctx,
Collector<Tuple3<Long, Long, Float>> out) throws Exception { long eventTime = fare.getEventTime();
TimerService timerService = ctx.timerService(); if (eventTime <= timerService.currentWatermark()) {
// This event is late; its window has already been triggered.
} else {
// Round up eventTime to the end of the window containing this event.
long endOfWindow = (eventTime - (eventTime % durationMsec) + durationMsec - 1); // Schedule a callback for when the window has been completed.
timerService.registerEventTimeTimer(endOfWindow); // Add this fare's tip to the running total for that window.
Float sum = sumOfTips.get(endOfWindow);
if (sum == null) {
sum = 0.0F;
}
sum += fare.tip;
sumOfTips.put(endOfWindow, sum);
}
}
要考虑的事情。
- 迟到的事件会怎样?在水印后面的事件(即迟到)会被丢弃。如果你想做一些比这更好的事情,可以考虑使用侧面输出,这将在下一节解释。
- 这个例子使用了一个MapState,其中键是时间戳,并为同一个时间戳设置一个Timer。这是一种常见的模式;它使得在定时器发射时查找相关信息变得简单而高效。
onTimer()方法
public void onTimer(
long timestamp,
OnTimerContext context,
Collector<Tuple3<Long, Long, Float>> out) throws Exception { long driverId = context.getCurrentKey();
// Look up the result for the hour that just ended.
Float sumOfTips = this.sumOfTips.get(timestamp); Tuple3<Long, Long, Float> result = Tuple3.of(driverId, timestamp, sumOfTips);
out.collect(result);
this.sumOfTips.remove(timestamp);
}
观察。
- 传递给onTimer的OnTimerContext上下文可以用来确定当前的密钥。
- 我们的伪窗口是在当前水印到达每个小时结束时被触发的,此时调用onTimer。这个onTimer方法从sumOfTips中删除了相关的条目,这样做的效果是无法容纳迟到的事件。这相当于在使用Flink的时间窗口时,将allowLateness设置为零。
性能考虑因素
Flink提供了针对RocksDB优化的MapState和ListState类型。在可能的情况下,应该使用这些类型来代替持有某种集合的ValueState对象。RocksDB状态后端可以追加到ListState,而不需要经过(去)序列化,对于MapState,每个键/值对都是一个独立的RocksDB对象,因此MapState可以有效地被访问和更新。
侧面输出
简介
有几个很好的理由可以让Flink操作者有一个以上的输出流,比如报告。
- 异常
- 畸形事件
- 后事
- 操作警报,如与外部服务的连接超时。
侧输出是一种方便的方式。除了错误报告之外,侧输出也是实现流的n路分割的好方法。
例子
现在,您可以对上一节中被忽略的晚期事件做些什么了。
一个侧输出通道与一个 OutputTag<T>相关联。这些标签具有与侧输出的DataStream的类型相对应的通用类型,它们具有名称。
private static final OutputTag<TaxiFare> lateFares = new OutputTag<TaxiFare>("lateFares") {};
上面展示的是一个静态的OutputTag<TaxiFare>,它既可以在PseudoWindow的processElement方法中发出晚期事件时被引用。
if (eventTime <= timerService.currentWatermark()) {
// This event is late; its window has already been triggered.
ctx.output(lateFares, fare);
} else {
. . .
}
并在访问这边的流时,在作业的主方法中输出。
// compute the sum of the tips per hour for each driver
SingleOutputStreamOperator hourlyTips = fares
.keyBy((TaxiFare fare) -> fare.driverId)
.process(new PseudoWindow(Time.hours(1))); hourlyTips.getSideOutput(lateFares).print();
另外,您也可以使用两个具有相同名称的OutputTags来引用同一侧输出,但如果您这样做,它们必须具有相同的类型。
结束语
在这个例子中,你已经看到了如何使用ProcessFunction来重新实现一个直接的时间窗口。当然,如果Flink内置的窗口API满足你的需求,无论如何,请继续使用它。但如果你发现自己在考虑用Flink的窗口做一些变形,不要害怕推出自己的窗口。
此外,ProcessFunctions对于计算分析之外的许多其他用例也很有用。下面的实践练习提供了一个完全不同的例子。
ProcessFunctions的另一个常见用例是用于过期的陈旧状态。如果你回想一下Rides和Fares练习,其中使用RichCoFlatMapFunction来计算一个简单的连接,示例解决方案假设TaxiRides和TaxiFares是完美匹配的,每个rideId是一对一的。如果一个事件丢失了,同一乘车ID的其他事件将永远保持在状态。这可以替换为一个KeyedCoProcessFunction来实现,并且可以使用一个定时器来检测和清除任何陈旧的状态。
实践
与本节配套的实战练习是长乘警报练习。
下一步阅读什么
Flink-v1.12官方网站翻译-P009-Event-driven Applications的更多相关文章
- Flink-v1.12官方网站翻译-P005-Learn Flink: Hands-on Training
学习Flink:实践培训 本次培训的目标和范围 本培训介绍了Apache Flink,包括足够的内容让你开始编写可扩展的流式ETL,分析和事件驱动的应用程序,同时省略了很多(最终重要的)细节.本书的重 ...
- Flink-v1.12官方网站翻译-P025-Queryable State Beta
可查询的状态 注意:可查询状态的客户端API目前处于不断发展的状态,对所提供接口的稳定性不做保证.在即将到来的Flink版本中,客户端的API很可能会有突破性的变化. 简而言之,该功能将Flink的托 ...
- Flink-v1.12官方网站翻译-P015-Glossary
术语表 Flink Application Cluster Flink应用集群是一个专用的Flink集群,它只执行一个Flink应用的Flink作业.Flink集群的寿命与Flink应用的寿命绑定. ...
- Flink-v1.12官方网站翻译-P008-Streaming Analytics
流式分析 事件时间和水印 介绍 Flink明确支持三种不同的时间概念. 事件时间:事件发生的时间,由产生(或存储)该事件的设备记录的时间 摄取时间:Flink在摄取事件时记录的时间戳. 处理时间:您的 ...
- Flink-v1.12官方网站翻译-P004-Flink Operations Playground
Flink操作训练场 在各种环境中部署和操作Apache Flink的方法有很多.无论这种多样性如何,Flink集群的基本构件保持不变,类似的操作原则也适用. 在这个操场上,你将学习如何管理和运行Fl ...
- Flink-v1.12官方网站翻译-P002-Fraud Detection with the DataStream API
使用DataStream API进行欺诈检测 Apache Flink提供了一个DataStream API,用于构建强大的.有状态的流式应用.它提供了对状态和时间的精细控制,这使得高级事件驱动系统的 ...
- Flink-v1.12官方网站翻译-P019-Generating Watermarks
生成水印 在本节中,您将了解 Flink 提供的 API,用于处理事件时间时间戳和水印.关于事件时间.处理时间和摄取时间的介绍,请参考事件时间的介绍. 水印策略介绍 为了使用事件时间,Flink需要知 ...
- Flink-v1.12官方网站翻译-P018-Event Time
事件时间 在本节中,您将学习如何编写时间感知的Flink程序.请看一下及时流处理,了解及时流处理背后的概念. 关于如何在Flink程序中使用时间的信息请参考windowing和ProcessFunct ...
- Flink-v1.12官方网站翻译-P016-Flink DataStream API Programming Guide
Flink DataStream API编程指南 Flink中的DataStream程序是对数据流实现转换的常规程序(如过滤.更新状态.定义窗口.聚合).数据流最初是由各种来源(如消息队列.套接字流. ...
随机推荐
- Beta冲刺——第六天
这个作业属于哪个课程 https://edu.cnblogs.com/campus/fzzcxy/2018SE1 这个作业要求在哪里 https://edu.cnblogs.com/campus/fz ...
- Linux下docker中安装宝塔面板教程
本人云服务器,装的cent os7.6,在cent os7.6已装了docker,没装的可以借鉴 https://www.cnblogs.com/xiaoyige/p/12673076.html 1. ...
- mmal商城商品模块总结
学习目标 FTP服务器的对接 SpringMVC文件上传 流读取properties配置文件 抽象POJO.BO.VO对象之间的转换关系及解决思路 joda-time快速入门 静态代码块 mybati ...
- Java 多线程读取文件并统计词频 实例 出神入化的《ThreadPoolExecutor》
重在展示多线程ThreadPoolExecutor的使用,和线程同步器CountDownLatch,以及相关CAS的原子操作和线程安全的Map/队列. ThreadPool主线程 1 import j ...
- 为啥使用innodb_flush_method=o_direct 就能减轻io压力呢
为啥使用innodb_flush_method=o_direct 就能减轻io压力呢
- +load和+initialize方法调用时机
一.+load方法什么时候调用 +load方法会在runtime加载类.分类时调用(程序运行起来会先去加载调用+load 跟你引用没有引用其头文件没有关系).每个类.分类的+load,在程序运行过程中 ...
- 使用smartform打印表单
昨天写了个smartform打印表单,在开发完成,在测试机测试OK,传到生产机,出现严重问题!无法打印,干脆就是无法调用打印图形界面,进入SMARTFORM事物,查看这个表单,发现,居然公司的LOGO ...
- 24V降压3.3V芯片,低压降线性稳压器
PW6206系列是一款高精度,高输入电压,低静态电流,高速,低压降线性稳压器具有高纹波抑制.在VOUT=5V&VIN=7V时,输入电压高达40V,负载电流高达300mA,采用BCD工艺制造.P ...
- 手动添加Ini4idea,解决pycharm无法打开ini文件
1. 查看本地pycharm的版本号 help -> about 2. 进入官网:http://plugins.jetbrains.com,选中pycharm及相关版本,搜索ini,切到版本,下 ...
- 基于源码分析Vue的nextTick
摘要:本文通过结合官方文档.源码和其他文章整理后,对Vue的nextTick做深入解析.理解本文最好有浏览器事件循环的基础,建议先阅读上文<事件循环Event loop到底是什么>. 一. ...