知道大数据的同学也应该知道 Flink 吧,最近在中国的热度比较高,在社区的推动下,Flink 技术栈在越来越多的公司开始得到应用。
Flink 到底火不火?
据不完全统计,Flink 在中国公司的采用情况(部分)
其中, 他们用 Flink 做了什么?
- Alibaba 使用 Flink 的分支版本 Blink 来优化实时搜索排名。eg: 当商品商家一个商品之后,实时计算引擎(Flink)在秒级别 build 商品索引,优化商品搜索。
- 腾讯利用 Apache Flink 构建了一个内部平台(Oceanus),以提高开发和操作实时应用程序的效率。
- 快手使用了 Apache Flink 搭建了一个实时监控平台,监控短视频和直播的质量。
- 利用 Apache Flink 构建了实时数据仓库,用于即时分析运营活动效果及用户短期兴趣。
- 华为云提供基于 Flink 的云服务。
- 滴滴使用 Apache Flink支持了实时监控、实时特征抽取、实时ETL等业务。
- Ebay 的监控平台由 Flink 提供支持,可在指标和日志流上计算上千条自定义报警规则。
- 爱立信使用 Flink 构建了一个实时异常检测器,通过大型基础设施进行机器学习。
- Uber 在 Apache Flink 上构建了基于 SQL 的开源流媒体分析平台 AthenaX。
- Yelp 利用 Flink 为其数据连接器生态系统和流处理基础架构提供支持。
- 财富 500 强金融服务公司 Capital One 使用 Flink 进行实时活动监控和报警。
- ...
!! https://cwiki.apache.org/confluence/display/FLINK/Powered by Flink更多公司查看点这里
上面我们看到很多公司在用 Flink,构建了不少的应用,接下来用数据说话,在 Google Trends 上查看关键词 ,看一下 Flink 的搜索用户画像,如图:
国内热度一只独秀,中国的开发者对 Flink 的热情更高。国内的公司更愿意拥抱新鲜事物,用于尝试。
回到百度指数,查看 Flink 关键次在全国城市的搜索热度分布。(额,数据可能不是很准确,大部分程序员可能不用百度搜索)
再回到 Google 搜索,查看相应数据。
浙江上榜是因为阿里,阿里的程序员为社区贡献了 Blink 分支,后续会把一些优秀的特性合并到主分支上。
在这里感谢默默付出的参与者们,正是你们的开源奉献,才使得需求端(公司)能够更多的把 Flink 应用到实际的业务中,提升业务水平。同时社区积极推进 Flink 相关课程培训,培训更多的 Flink 开发者,建设人才。
一个技术火不火?除了底层的设计框架之外,参与者的热情也是一方面,大家愿意学习它,愿意使用它,更愿意维护它。我想,开源的魅力大抵如此。
搬砖、搬砖,还在等什么呢?
Flink 的相关基础知识
官网的一段话,最准确的 DenFination
!! Apache Flink is a framework and distributed processing engine for stateful computations over unbounded and bounded data streams
首先它是一个框架,框架的作用就是隐藏底层细节,使用起来更加简单,让开发者更关注与业务的实现。其次他也是分布式的处理引擎,单机的处理能力有限,那就多节点计算,这就涉及到分布式,它解决了很多分布式计的问题。有状态和有界无界的数据流,这里先买个不做介绍。
接下里 介绍 Flink 最核心的三个语义,希望读者可以深刻理解。
Stream , 翻译过来是流,那 Data Steam 就是数据流。在 Flink 中,一切数据都是 Stream,分为 unbounded (无界)和 bounded(有界)。使用过 Hive 或 Mapreduce 或 mysql 的同学应该知道,数据存在 hdfs 或其他文件系统上,并且是一个固定的大小,我们把这些数据称为一批数据。使用过 Spark Streaming 或 Storm 的同学也应该知道数据源源不断的流入,流出,计算,这个过程的数据称为数据流。但是在 Flink 里,把批/流数据全部抽象成流,分为有界的流和无界的流。
!! 注:这里在语义上的把数据统一成流,更好的实现了流批统一,底层公共一套 API,这个后面会讲到,看不明白没关系。
State , 翻译过来是状态。它是一个有状态的计算引擎,举一个例子,我们要统计一个用户最近一个小时的访问次数, Flink 会在系统内部会把这个 count 值保存成状态,一直累加或删除。状态就像记忆,而且这个份记忆是保存在自身的。
它的优势:
- 多种状态基础类型:Flink 为多种不同的数据结构提供了相对应的状态基础类型,例如原子值(value),列表(list)以及映射(map)。开发者可以基于处理函数对状态的访问方式,选择最高效、最适合的状态基础类型。
- 插件化的State Backend: State Backend 负责管理应用程序状态,并在需要的时候进行 checkpoint。Flink 支持多种 state backend,可以将状态存在内存或者 RocksDB。RocksDB 是一种高效的嵌入式、持久化键值存储引擎。Flink 也支持插件式的自定义 state backend 进行状态存储。
- 精确一次语义: Flink 的 checkpoint 和故障恢复算法保证了故障发生后应用状态的一致性。因此,Flink 能够在应用程序发生故障时,对应用程序透明,不造成正确性的影响。
- 超大数据量状态:Flink 能够利用其异步以及增量式的 checkpoint 算法,存储数 TB 级别的应用状态。
- 可弹性伸缩的应用:Flink 能够通过在更多或更少的工作节点上对状态进行重新分布,支持有状态应用的分布式的横向伸缩。
!! 注: 使用 storm 或 spark streaming 计算累加值的最常用做法都是利用第三方存储来做,比如使用 redis 来累加值。而 Flink 支持有状态的计算,这个状态自己保管。
Time,即时间。Flink 有三种时间,分别是 event time ,数据产生的时间。ingestion time 数据到达 Flink DateFlow 的时间。processing time 数据到达每个算子的时间。
Flink 提供了丰富的时间语义支持。
- 事件时间模式: 使用事件时间语义的流处理应用根据事件本身自带的时间戳进行结果的计算。因此,无论处理的是历史记录的事件还是实时的事件,事件时间模式的处理总能保证结果的准确性和一致性。
- Watermark 支持: Flink 引入了 watermark 的概念,用以衡量事件时间进展。Watermark 也是一种平衡处理延时和完整性的灵活机制。
- 迟到数据处理: 当以带有 watermark 的事件时间模式处理数据流时,在计算完成之后仍会有相关数据到达。这样的事件被称为迟到事件。Flink 提供了多种处理迟到数据的选项,例如将这些数据重定向到旁路输出(side output)或者更新之前完成计算的结果。
- 处理时间模式: 除了事件时间模式,Flink 还支持处理时间语义。处理时间模式根据处理引擎的机器时钟触发计算,一般适用于有着严格的低延迟需求,并且能够容忍近似结果的流处理应用。
!! 注:Flink 为什么引入了时间的概念呢?因为在 Flink 内部数据是流,需要有一个来度量流计算处理进度的标识。所以引入了时间这个概念。
接下来,我们来简单了解下 Flink 的分层 API
如图,Flink 根据抽象程度分层了三层,提供了三种不同的 API。每一种 API 在简洁性和表达力上有着不同的侧重,并且针对不同的应用场景。
ProcessFunction 是 Flink 所提供的最具表达力的接口。下面这个例子充分展现了 KeyedProcessFunction 强大的表达力,也因此是一个实现相当复杂的接口。下面这个例子充分展现了 KeyedProcessFunction
强大的表达力,也因此是一个实现相当复杂的接口。
/**
* 将相邻的 keyed START 和 END 事件相匹配并计算两者的时间间隔
* 输入数据为 Tuple2<String, String> 类型,第一个字段为 key 值,
* 第二个字段标记 START 和 END 事件。
*/
public static class StartEndDuration
extends KeyedProcessFunction<String, Tuple2<String, String>, Tuple2<String, Long>> {
private ValueState<Long> startTime;
@Override
public void open(Configuration conf) {
// obtain state handle
startTime = getRuntimeContext()
.getState(new ValueStateDescriptor<Long>("startTime", Long.class));
}
/** Called for each processed event. */
@Override
public void processElement(
Tuple2<String, String> in,
Context ctx,
Collector<Tuple2<String, Long>> out) throws Exception {
switch (in.f1) {
case "START":
// set the start time if we receive a start event.
startTime.update(ctx.timestamp());
// register a timer in four hours from the start event.
ctx.timerService()
.registerEventTimeTimer(ctx.timestamp() 4 * 60 * 60 * 1000);
break;
case "END":
// emit the duration between start and end event
Long sTime = startTime.value();
if (sTime != null) {
out.collect(Tuple2.of(in.f0, ctx.timestamp() - sTime));
// clear the state
startTime.clear();
}
default:
// do nothing
}
}
/** Called when a timer fires. */
@Override
public void onTimer(
long timestamp,
OnTimerContext ctx,
Collector<Tuple2<String, Long>> out) {
// Timeout interval exceeded. Cleaning up the state.
startTime.clear();
}
}
DataStream API 为许多通用的流处理操作提供了处理原语。DataStream API 支持 Java 和 Scala 语言,预先定义了例如map()
、reduce()
、aggregate()
等函数。你可以通过扩展实现预定义接口或使用 Java、Scala 的 lambda 表达式实现自定义的函数。
!! 用过 spark 的同学看到这里一定很熟悉。
下面的代码示例展示了如何捕获会话时间范围内所有的点击流事件,并对每一次会话的点击量进行计数。
代码语言:javascript复制// 网站点击 Click 的数据流
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);
}
})
// 以 userId (field 0) 作为 key
.keyBy(0)
// 定义 30 分钟超时的会话窗口
.window(EventTimeSessionWindows.withGap(Time.minutes(30L)))
// 对每个会话窗口的点击进行计数,使用 lambda 表达式定义 reduce 函数
.reduce((a, b) -> Tuple2.of(a.f0, a.f1 b.f1));
Flink 支持两种关系型的 API,Table API和 SQL 。这两个 API 都是批处理和流处理统一的 API,这意味着在无边界的实时数据流和有边界的历史记录数据流上,关系型 API 会以相同的语义执行查询,并产生相同的结果。
代码语言:javascript复制SELECT userId, COUNT(*)
FROM clicks
GROUP BY SESSION(clicktime, INTERVAL '30' MINUTE), userId
Flink 架构优势
最后,这几点 Flink 的架构方面的设计,或许是你说服别人使用 Flink 的理由。
- 处理有界和无界的数据。任何类型的数据都可以形成一种事件流。信用卡交易、传感器测量、机器日志、网站或移动应用程序上的用户交互记录,所有这些数据都形成一种流。
Flink 擅长处理无界和有界数据流,得益于精确的时间控制和状态化。
- 部署灵活。Flink 集成了所有常见的集群资源管理器,例如 Hadoop YARN、 Apache Mesos 和 Kubernetes,但同时也可以作为独立集群运行。
- 极高的可伸缩性。阿里去年双十一的数据处理峰值 17亿条/秒
- 极致的流式处理性能。
如图,数据经过计算,会被保存在state中。这里 Flink 做了优化,计算结果一开始保存在内存中,如果超出一定大小,就会保存在可高效访问的磁盘结构中。也就是说,Flink 本地状态尽可能的保存在内存中。为了保证容错和数据准确性,Flink 也会定期和异步的把本地状态进行持久化存储来保证故障场景下精确一次的状态一致性。(有点绕!其实就是解决分布式场景下数据不一致的问题)
Flink 稳定吗?
Flink 非常注重流数据处理的可运维性。下面介绍 Flink 的故障恢复机制,并介绍其管理和监控应用的功能。
在分布式系统中,服务故障是常有的事,如何保证服务能够7*24小时稳定运行?
!! 就两个需求:任务失败了可以重启;重启之后还会和没发生故障一样。
Flink通过几下多种机制维护应用可持续运行及其一致性:
- 检查点的一致性: Flink的故障恢复机制是通过建立分布式应用服务状态一致性检查点实现的,当有故障产生时,应用服务会重启后,再重新加载上一次成功备份的状态检查点信息。结合可重放的数据源,该特性可保证_精确一次(exactly-once)_的状态一致性。
- 高效的检查点: 如果一个状态信息很大,势必会带来延迟性,Flink采用异步及增量的方式构建检查点服务。
- 端到端的精确一次: Flink 为某些特定的存储支持了事务型输出的功能,即使在发生故障的情况下,也能够保证精确一次的输出。
- 集成多种集群管理服务: Flink已与多种集群管理服务紧密集成,如 Hadoop YARN, Mesos, 以及 Kubernetes。当集群中某个流程任务失败后,一个新的流程服务会自动启动并替代它继续执行。
- 内置高可用服务: Flink内置了为解决单点故障问题的高可用性服务(HA)模块,此模块是基于Apache ZooKeeper 技术实现的,Apache ZooKeeper是一种可靠的、交互式的、分布式协调服务组件。
小结
Flink 作为一个优秀的实时计算框架,不可能仅凭一篇文章就能全部讲清楚,所以遵循循序渐进的原则,本文主要介绍一些了Flink在全球的趋势,为什么火,基础语义,架构等基础知识作为入门,更好的理解它的设计初衷,真正明白 Flink 到底好在哪?如果您看完本文能够了解这些,点赞(再看)转发走一波,谢谢支持。