4

不一样的Flink入门教程

 3 years ago
source link: https://zhuanlan.zhihu.com/p/313280875
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

不一样的Flink入门教程

公众号:Java3y

微信搜【Java3y】关注这个朴实无华的男人,点赞关注是对我最大的支持!
文本已收录至我的GitHubhttps://github.com/ZhongFuCheng3y/3y,有300多篇原创文章,最近在连载面试和项目系列!

在前段时间写了一篇《Storm》入门的文章,很多同学给我说:“大人,时代变了”。

v2-61e876b0afedec2614167b0f30dac386_720w.jpg

最近公司要把Storm集群给下线啦,所以我们都得把Storm的任务都改成Flink

于是最近入门了一把Flink,现在来分享一下Flink入门的相关知识。

(写上面这一段话的时候,到发文章这个时候已经过了一个季度了,不好意思,我这篇文章拖了一个季度)

不得不说,Flink这两年是真的火 这篇文章主要讲讲Flink入门时一些可能看不太懂的点又或是看官方介绍看不太懂的点(API我就不细说了,多用用应该都能看懂)。

什么是Flink?

在Flink的官网上,可以把官方文档语言设置为中文,于是我们可以看到官方是这样介绍的:

上面的图我们每个字都能看得懂,但连起来就看不懂了。

不管怎么样,我们可以了解到:Flink是一个分布式的计算处理引擎

  • 分布式:「它的存储或者计算交由多台服务器上完成,最后汇总起来达到最终的效果」。
  • 实时:处理速度是毫秒级或者秒级的
  • 计算:可以简单理解为对数据进行处理,比如清洗数据(对数据进行规整,取出有用的数据)

基于官网的一句话介绍,我们就可以联想出很多东西

这篇文章可以带你简单认识一下Flink的一些基础概念,等你真正用到的时候就可以依据这篇文章来对Flink进行入门,现在Storm都被很多人给抛弃掉了,那么Flink优于Storm的地方有哪些呢?接下来我们一起来看看Flink吧。

什么是有边界和无边界?

Apache Flink 是一个框架和分布式处理引擎,用于在无边界和有边界数据流上进行有状态的计算。

官方其实也有介绍,但对初学者来说不太好理解,我来幼儿园化一下。

大家学到Flink了,消息队列肯定有用过吧?那你们是怎么用消息队列的呢?Producer生产数据,发给BrokerConsumer消费,完事。

在消费的时候,我们需要管什么Producer什么时候发消息吗?不需要吧。反正来一条,我就处理一条,没毛病吧。

这种没有做任何处理的消息,默认就是无边界的。

那有边界就很好理解了:无边界的基础上加上条件,那就是有边界的。加什么条件呢?比如我要加个时间:我要消费从8月8号到8月9号的数据,那就是有边界的。

什么时候用无边界,什么时候用有边界?那也很好理解。我做数据清洗:来一条,我处理一条,这种无边界的就好了。我要做数据统计:每个小时的pv(page view)是多少,那我就设置1小时的边界,攒着一小时的数据来处理一次。

Flink上,设置“边界”这种操作叫做开窗口(Windows),窗口可简单分为两种类型:

  • 时间窗口(TimeWindows):按照时间窗口进行聚合,比如上面所讲得攥着一个小时的数据处理一次。
  • 计数窗口(CountWindows):按照指定的条数来进行聚合,比如每来了10条数据处理一次。

看着就非常人性化(妈妈再也不用担心我需要聚合了)...

不仅如此,在Flink使用窗口聚合的时候,还考虑到了数据的准确性问题。比如说:现在我在11:06分产生了5条数据,在11:07分 产生了4条数据,我现在是按每分钟的维度来进行聚合计算。

理论上来讲:Flink应该是在06分聚合了5条数据,在07分聚合了4条数据。但是,可能由于网络的延迟性等原因,导致06分3条数据在07分Flink才接收到。如果不做任何处理,那07分有可能处理了7条条数据。

某些需要准确结果的场景来说,这就不太合理了。所以Flink可以给我们指定”时间语义“,不指定默认是「数据到Flink的时间」Processing Time来进行聚合处理,可以给我们指定聚合的时间以「事件发生的时间」Event Time来进行处理。

事件发生的时间指的就是:日志真正记录的时间

2020-11-22 00:00:02.552 INFO  [http-nio-7001-exec-28] c.m.t.rye.admin.web.aop.LogAspect

虽然指定了聚合的时间为「事件发生的时间」Event Time,但还是没解决数据乱序的问题(06分产生了5条数据,实际上06分只收到了3条,而剩下的两条在07分才收到,那此时怎么办呢?在06分时该不该聚合,07分收到的两条06分数据怎么办?)

Flink又可以给我们设置水位线(waterMarks),Flink意思就是:存在网络延迟等情况导致数据接收不是有序,这种情况我都能理解。你这样吧,根据自身的情况,你可以设置一个「延迟时间」,等延迟的时间到了,我再聚合统一聚合。

比如说:现在我知道数据有可能会延迟一分钟,那我将水位线waterMarks设置延迟一分钟。

解读:因为设置了「事件发生的时间」Event Time,所以Flink可以检测到每一条记录发生的时间,而设置了水位线waterMarks设置延迟一分钟,等到Flink发现07分:59秒的数据来到了Flink,那就确信06分的数据都来了(因为设置了1分钟延迟),此时才聚合06分的窗口数据。

什么叫做有状态?

Apache Flink 是一个框架和分布式处理引擎,用于在无边界和有边界数据流上进行有状态的计算。

什么是有状态,什么是无状态?

无状态我们可以简单认为:每次的执行都不依赖上一次或上N次的执行结果,每次的执行都是独立的。

有状态我们可以简单认为:执行需要依赖上一次或上N次的执行结果,某次的执行需要依赖前面事件的处理结果。

比如,我们现在要统计文章的阅读PV(page view),现在只要有一个点击了文章,在Kafka就会有一条消息。现在我要在流式处理平台上进行统计,那此时是有状态的还是无状态的?

假设我们要在Storm做,那我们可能将每次的处理结果放到一个“外部存储”中,然后基于这个“外部存储”进行计算(这里我们不用Storm Trident),那此时Storm是无状态的。

比如说:我存储将每次得到的数据存储到 Redis中,来一条数据,我就先查一下Redis目前的值是多少,跟Redis的值和现在的值做一次累加就完事了。

假设要在Flink做,Flink本身就提供了这种功能给我们使用,我们可以依赖Flink的“存储”,将每次的处理结果交由Flink管理,执行计算的逻辑。

可以简单的认为:Flink本身就给我们提供了”存储“的功能,而我们每次执行是可以依赖Flink的”存储”的,所以它是有状态的。

Flink是把这些有状态的数据存储在哪的呢?

主要有三个地方:

  • 文件系统(HDFS)
  • 本地数据库


如果假设Flink挂了,可能内存的数据没了,磁盘可能存储了部分的数据,那再重启的时候(比如消息队列会重新拉取),就不怕会丢了或多了数据吗?

看到这里,你可能在会在别的地方看过Flink的另外一个比较出名的特性:精确一次性

(简单来说就是:Flink遇到意外事件挂了以后,有什么机制来尽可能保证处理数据不重复和不丢失的呢)

什么是精确一次性(exactly once)?

众所周知,流的语义性有三种:

  • 精确一次性(exactly once):有且只有一条,不多不少
  • 至少一次(at least once):最少会有一条,只多不少
  • 最多一次(at most once):最多只有一条,可能会没有

Flink实现了精确一次性,这个精确一次性是什么意思呢?

Flink的精确一次性指的是:状态只持久化一次最终的存储介质中(本地数据库/HDFS...)

以上面的图为例:Source数据流有以下数字21,13,8,5,3,2,1,1,然后在Flink需要做累加操作(求和)

现在处理完2,1,1了,所以累加的值是4,现在Flink把累积后的状态4已经存储起来了(认为前面2,1,1这几个数字已经完全处理过了)。

程序一直往下走,处理了5,3,现在累加的值是12,但现在Flink还没来得及把12存储到最终的介质,此时系统挂掉了。

Flink重启后会重新把系统恢复到累加的值是4的状态,所以5,3得继续计算一遍,程序继续往下走。

看文章有的同学可能会认为:精确一次性指的不是某一段代码只会执行一次,不会执行多次或不执行。这53这两个数,你不是重复计算了吗?怎么就精确一次了?

显然,代码只执行一次肯定是不可能的嘛。我们无法控制系统在哪一行代码挂掉的,你要是在挂的时候,当前方法还没执行完,你还是得重新执行该方法的。

所以,状态只持久化一次最终的存储介质中(本地数据库/HDFS),在Flink下就叫做exactly once(计算的数据可能会重复(无法避免),但状态在存储介质上只会存储一次)。

那么Flink是在多长时间存储一次的呢?这个是我们自己手动配置的。

所谓的CheckPoint其实就是Flink会在指定的时间段上保存状态的信息,假设Flink挂了可以将上一次状态信息再捞出来,重放还没保存的数据来执行计算,最终实现exactly once

CheckPonit是怎么办到的呢?想想我们在Kafka在业务上实现「至少一次」是怎么做的?我们从Kafka把数据拉下来,处理完业务了以后,手动提交offset (告诉Kafka我已经处理完了)

我们是做完了业务规则才将offset进行commit的,checkponit其实也是一样的(等拉下来该条数据所有的流程走完,才进行真正的checkponit)。

问题又来了,那checkpoint是怎么知道拉下来的数据已经走完了呢?Flink在流处理过程中插入了barrier,每个环节处理到barrier都会上报,等到sink都上报了barrier就说明这次checkpoint已经走完了。

要注意的是,Flink实现的精确一次性只是保证内部的状态是精确一次的,如果想要端到端精确一次,需要端的支持

  • 数据源需要可回放,发证故障可以重新读取未确认的数据
  • Flink需要把数据存到磁盘介质(不能用内存),发生故障可以恢复
  • 发送源需要支持事务(从读到写需要事务的支持保证中途不失败)

这篇文章对Flink做了一次简单的介绍,希望对大家在入门的时候有所帮助。后续打算会再写一篇Flink文章对CheckPoint机制做更加深入的了解,有兴趣的同学可以点个关注第一时间能接收到。

三歪把【大厂面试知识点】、【简历模板】、【原创文章】全部整理成电子书,共有1263页!

PDF文档的内容均为手打,有任何的不懂都可以直接来问我




About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK