目录
Flink流应用程序的构建块(流、状态、时间、分层API)
流应用程序的构建块
可以使用流处理框架构建和执行的应用程序类型由框架控制流、状态和时间的程度来定义
流
流是流处理的一个基本方面。但是,流可以具有不同的特性,这些特性会影响流的处理方式和应该如何处理。Flink是一个通用的处理框架,可以处理任何类型的流。
(1)有界和无界流
流可以是无界或有界的,即固定大小的数据集。Flink具有处理无界流的复杂功能,但也有专门的运算符来有效地处理有界流
(2)实时和记录流
所有数据都以流的形式生成。有两种处理数据的方法。在生成流时对其进行实时处理或将流持久化到存储系统(文件系统或对象存储),并在以后对其进行处理。Flink应用程序可以处理录制的或实时的流
状态
每个重要的流应用程序都是有状态的,即只有对单个事件应用转换的应用程序才不需要状态。任何运行基本业务逻辑的应用程序都需要记住事件或中间结果,以便在稍后的时间点访问它们。
例如:在接收到下一个事件时或在特定持续时间之后
应用程序状态是Flink中的一个重要组成部分。通过查看Flink在状态处理上下文中提供的所有功能,可以看到这一点。
(1)多状态原语
Flink为不同的数据结构提供状态原语,例如:原子值、列表或映射。开发人员可以根据函数的访问模式选择最有效的状态原语
(2)可插拔状态后端
应用程序状态由可插拔状态后端管理和检查点。Flink具有不同的状态后端,将状态存储在内存或RocksDB中,这是一种高效的嵌入式磁盘数据存储。也可以插入自定义状态后端
(3)Exactly-once状态一致性
Flink的检查点和恢复算法保证了应用程序状态在发生故障时的一致性。因此,故障被透明地处理并且不影响应用程序的正确性
(4)超大状态
由于其异步和增量检查点算法,Flink能够维持数TB大小的应用程序状态
(5)可扩展的应用程序
Flink通过将状态重新分配给更多或更少的工作人员来支持有状态应用程序的扩展
时间
时间是流应用程序的另一个重要组成部分。大多数事件流具有固有的时间语义,因为每个事件都是在特定时间点产生的。此外,许多常见的流计算都是基于时间
例如:窗口聚合、会话化、模式检测和基于时间的连接。流处理的一个重要方面是应用程序如何测量时间,即事件时间和处理时间的差异。
(1)事件时间模式
处理具有事件时间语义的流的应用程序根据事件的时间戳计算结果。因此,无论是处理记录的事件还是实时事件,事件时间处理都允许获得准确和一致的结果
(2)水印支持
Flink使用水印来推断事件时间应用程序中的时间。水印也是一种灵活的机制,可以权衡结果的延迟和完整性
(3)后期数据处理
在事件时间模式下处理带有水印的流时,可能会发生计算在所有相关事件到达之前已经完成。此类事件称为延迟事件。Flink具有多种处理延迟事件的选项,例如通过侧输出重新路由它们和更新之前完成的结果
(4)处理时间模式
除了它的事件时间模式,Flink还支持处理时间语义,它执行由处理机器的挂钟时间触发的计算。处理时间模式可以适用于具有严格低延迟要求的某些应用程序,这些应用程序可以容忍近似结果
分层API
Flink提供了三层API。每个API在简洁性和表达性之间提供不同的权衡,并针对不同的用例
(1)过程函数:ProcessFunction
ProcessFunction是Flink提供的最具表现力的函数接口。Flink提供ProcessFunctions来处理来自一个或两个输入流的单个事件或在一个窗口中分组的事件。ProcessFunctions提供对时间和状态的细粒度控制。ProcessFunction可以任意修改其状态并注册将来会触发回调函数的计时器。因此,ProcessFunctions可以实现许多有状态事件驱动应用程序所需的复杂的每个事件的业务逻辑
import org.apache.flink.api.common.state.ValueState;
import org.apache.flink.api.common.state.ValueStateDescriptor;
import org.apache.flink.api.java.tuple.Tuple2;
import org.apache.flink.configuration.Configuration;
import org.apache.flink.streaming.api.functions.KeyedProcessFunction;
import org.apache.flink.util.Collector;
/**
* 匹配键入的开始和结束事件,并计算两者之间的差异
* <p>
* 这两个元素的时间戳。第一字符串字段是键属性,第二个字符串属性标记开始和结束事件
*
* 以下示例显示了KeyedProcessFunction对一个KeyedStream流进行操作以及匹配START和END事件。
* 当START接收到一个事件时,该函数会记住它的时间戳,并在四个小时内注册一个计时器。
* 如果END在计时器触发之前接收到事件,则该函数计算END和START事件之间的持续时间,清除状态并返回值。否则,定时器只会触发并清除状态。
*
* @author nizhihao
* @version 1.0.0
* @date 2022/8/22 22:38
*/
public class StartEndDuration extends KeyedProcessFunction<String, Tuple2<String, String>, Tuple2<String, Long>> {
private ValueState<Long> startTime;
@Override
public void open(Configuration conf) {
// 获取状态handle
startTime = getRuntimeContext()
.getState(new ValueStateDescriptor<>("startTime", Long.class));
}
/**
* 为每个已处理事件调用
*/
@Override
public void processElement(Tuple2<String, String> in, Context ctx, Collector<Tuple2<String, Long>> out) throws Exception {
switch (in.f1) {
case "START":
// 收到启动事件,设置启动时间
startTime.update(ctx.timestamp());
// 在启动事件后的四小时内注册计时器
ctx.timerService().registerEventTimeTimer(ctx.timestamp() + 4 * 60 * 60 * 1000);
break;
case "END":
// 发出开始和结束事件之间的持续时间
Long sTime = startTime.value();
if (sTime != null) {
out.collect(Tuple2.of(in.f0, ctx.timestamp() - sTime));
// 清除状态
startTime.clear();
}
default:
// do nothing
}
}
/**
* 当定时器触发时调用
*/
@Override
public void onTimer(long timestamp, OnTimerContext ctx, Collector<Tuple2<String, Long>> out) {
// 超过超时时间间隔,清理状态
startTime.clear();
}
}
(2)数据流API
DataStream API为许多常见的流处理操作提供原语
例如:窗口化、一次记录转换以及通过查询外部数据存储来丰富事件
DataStream API可用于Java和Scala,并且基于函数,例如:map()、reduce()和aggregate()。函数可以通过扩展接口或Java或Scala lambda函数来定义
(3)SQL & Table API
Flink有两个关系API,Table API和SQL。两种API都是用于批处理和流处理的统一API,即查询以相同的语义对无界的实时流或有界的记录流执行并产生相同的结果。Table API和SQL利用Apache Calcite进行解析、验证和查询优化。它们可以与DataStream和DataSet API无缝集成,并支持用户定义的标量、聚合和表值函数。
Flink的关系API指在简化数据分析、数据管道和ETL应用程序的定义
(4)Libraries(库)
Flink具有几个用于常见数据处理用例的库。这些库通常嵌入在API中,而不是完全独立的。因此,它们可以从API的所有功能中受益并与其他库集成
①复杂事件处理(CEP)
模式检测是事件流处理的一个非常常见的用例。Flink的CEP库提供了一个API来指定事件的模式(想想正则表达式或状态机)。CEP库与Flink的DataStream API集成,以便在DataStreams上评估模式。CEP库的应用包括网络入侵检测、业务流程监控和欺诈检测
②DataSet API
DataSet API是Flink用于批处理应用的核心API。DataSet API的原语包括map、 reduce、(外)join、co-group和iterate。所有操作都由算法和数据结构支持,这些算法和数据结构对内存中的序列化数据进行操作,如果数据大小超过内存预算,则会溢出到磁盘。Flink的DataSet API的数据处理算法受到传统数据库运算符的启发,例如混合哈希联接或外部合并排序
③Gelly
Gelly是一个用于可扩展图形处理和分析的库。Gelly在DataSet API之上实现并与它集成。因此,它受益于其可扩展且强大的运营商。Gelly具有内置算法,例如:标签传播、三角形枚举和页面排名,但还提供了一个Graph API,可以简化自定义图形算法的实现。