Flink学习3-API介绍
0x00 系列文章目录
0x01 摘要
本文主要是介绍Flink的不同层次(level)API抽象,学习怎么通过API高效处理有状态性的计算无界和有界的数据流。
0x02 基本概念
在Flink流式处理框架中,有几个很重要的概念即streams,state,time。 下面我们解释下这几个基本概念,并会分析Flink怎么运用他们。
2.1 Streams
Stream流,就是流式处理中的基本概念。虽然流数据分为各种不同特征的类型,但是Flink可以巧妙高效的进行处理:
2.1.1 有界流和无界流
Flink的设计哲学最擅长于处理无界数据,但是对于有界数据也提供了高效的操作方式。
2.1.2 实时流和记录型流
一般来说处理这类流数据的方式有两种:
- 数据一旦生成就立刻实时处理
- 先将流数据持久化到存储系统(如文件系统等),稍后再处理它们。
2.2 State
每个有价值的流式应用一般都是有状态的。
运行基本业务逻辑的任何应用程序都需要记下事件或中间结果,以便在以后的时间点访问它们:例如在收到下一个事件时或在特定持续时间之后。
应用程序的State(状态)是很重要的一个概念,Flink中有很多feature来处理状态。
- 多种多样的状态元语:Flink有多种数据结构来提供状态原语,例如原子值,列表或映射,我们可以根据这个function访问方式来选择合适的状态元语类型
- 可插拔的状态后端:应用的状态是由一个可插拔的状态后端服务管理和设置检查点的,我们可以选择用内存或
RocksDB(一个高效的嵌入式磁盘数据存储)甚至是自定义的状态后端插件来存储应用状态 - 精准一次的状态一致性:Flink的检查点和恢复算法可以保证在失败时应用状态的一致性。所以,这些失败对应用来说是透明的,不会影响正确性
- 巨大的状态信息维护:Flink通过异步和增量检查点算法可维护TB级别的应用状态
- 可扩展的应用:Flink通过对应用弹性分配worker数量来实现应用可扩展
2.3 Time
Time是流式应用状态中的一个重要概念。
大多流式数据本身就有时间语义,因为每个事件都是在特定的时间点上产生的。而且通常流式计算是以时间为基础的。在流式处理中很重要的方面是应用程序如何去测量时间即event-time 和processing-time的差别:
- Event-time 模式:处理具有事件时间语义的流的应用程序是基于事件的时间戳来计算结果。 因此,无论是处理记录型还是实时的流事件,通过
event-time处理都会得到准确和一致的结果。 - Processing-time模式:除
event time模式外,Flink还支持Processing-time语义,该语义执行由处理机器的时钟时间来触发的计算。 该模式适用于具有严格的低延迟要求的应用,但也必须容忍并不精确、近似的结果。
当选择event-time模式时有两个重要概念:
- 水位:Flink使用水位来推断
event-time应用中的时间。此外,水位也是一种灵活的机制,可以在结果的延迟和完整性间做出权衡。 - 延迟数据处理:当使用水位在
event-time模式下处理流时,可能发生在所有相关事件到达之前就已完成了计算,这类事件称为延迟事件。 Flink具有多种处理延迟事件的选项,如重新路由它们以及更新此前已经完成的结果。
0x03 Flink多层API
Flink提供了三个不同层次的API,每种API在简洁和易表达间有自己的权衡,适用于不同的场景:
可以看到Flink一共有三个抽象层次的API,目测应该前两个会用的比较多,他们更加简洁但是表达性比较差。下面自底向上分别简要介绍下这三个API。
3.1 ProcessFunctions
看了上面的图我们知道ProcessFunctions最具表现力但是简洁性最差,是最底层的抽象API,他被主要用来处理包含单独事件的一个或两个输入流或者是分组到一个窗口类的事件,所以提供了对时间和状态的细粒度控制。ProcessFunctions可强制修改state、重注册未来某时触发回调函数的timer,所以可以实现复杂事件处理逻辑,这正适合很多有状态的事件驱动应用程序。
因为最近作者调研主要涉及FLink流式SQL API,这里没有详看,想要了解的请参见最后参考文档中给出的连接学习。
3.2 DataStream API
DataStream API提供了若干常用的流处理操作,如窗口等。
有Java何Scala的API可选,都是依赖一些基本的方法如map/aggregate等实现的。
下面示例展示session化一个click流然后对每个session中的点击数计数:
// 网站的点击流
DataStream<Click> clicks = ...
DataStream<Tuple2<String, Long>> result = clicks
// 将点击数与userId匹配,每一个点击就加1
.map(
// 定义一个实现了MapFunction接口的方法
new MapFunction<Click, Tuple2<String, Long>>() {
@Override
public Tuple2<String, Long> map(Click click) {
return Tuple2.of(click.userId, 1L);
}
})
// key by userId (field 0)
.keyBy(0)
// 定义30分钟间隙的session窗口
.window(EventTimeSessionWindows.withGap(Time.minutes(30L)))
// 对每个session点击计数,并定义为lambda函数
.reduce((a, b) -> Tuple2.of(a.f0, a.f1 + b.f1));
3.3 SQL&Table API
Flink高层API有两种:Table级别和SQL级别。两种API都是统一的处理批和六十数据,也就是说对于无界、实时的流或者有界、记录型的流有着同样的处理语义,产生同样的结果。
Table和SQL API采用了Apache Calcite进行语句解析、验证和查询调优。
他们可以和DataStream及DataSet API无缝集成,并支持用户自定义的标量,聚合和表值函数。
Flink的关系型API旨在简化数据分析,数据管道和ETL应用程序。
下面这个示例功能和DataStreamAPI中的相同,也是展示一个SQL查询将一个点击流session化,然后对每个session中的点击数计数:
SELECT userId, COUNT(*)
FROM clicks
GROUP BY SESSION(clicktime, INTERVAL '30' MINUTE), userId
这个SQL就是个流式处理SQL,简洁,高效。
0x04 库
Flink对常见的流式处理场景提供了若干内库,他们通常嵌入到API中,并非完全独立。 因此,他们可以从API的所有特性中受益,并与其他库集成:
4.1 Complex Event Processing (CEP)
该内库提供API来指定不同事件的模式,就像正则表达式或是状态机。模式识别是非常常见的事件流处理场景。
CEP库的应用包括网络入侵检测,业务流程监控和欺诈检测。
4.2 DataSet API
DataSet API是Flink的核心API,用来应对批处理应用。
4.3 Gelly
Gelly是一个可扩展的图形处理和分析库,他在DataSet API之上集成实现。
Gelly具有内置算法,如标签传播,三角枚举和页面排名,但也提供了一个简化自定义图算法实现的Graph API。
0xFE 总结
这篇文章主要讲了一些Flink编程中用到的基本概念和API,为了更加深入理解,还要多学习下Example才行,请点击这里。