Flink

简单介绍

Flink时apache的顶级项目,使用java语言编写!(在这个scala泛滥的时代还真是令人感动呢)

支持流处理,也支持批处理。Flink最大的原则就是,以流处理为根本。Flink认为批处理应该在流处理上实现。通过插入barrier事件来标记微批,收到该事件后,进行checkpoint快照。发现处理失败,就根据快照恢复然后进行流重放。

在这里插入图片描述

flink的checkpoint机制非常轻量,barrier不会打断streaming的流动,而且做checkpoint操作也是异步的。其次,相比storm需要ack每条data,flink做的是相当于small batch的checkpoint,容错的代价相对要低很多。最重要的是flink的checkpoint机制能保证exactly once。(装作Trident不存在一脸无辜的我)。

Flink 架构

在这里插入图片描述
JobManager 主要负责调度 Job 并协调 Task 做 checkpoint,职责上很像 Storm 的 Nimbus。从 Client 处接收到 Job 和 JAR 包等资源后,会生成优化后的执行计划,并以 Task 的单元调度到各个 TaskManager 去执行。
TaskManager 在启动的时候就设置好了槽位数(Slot),每个 slot 能启动一个 Task,Task 为线程。从 JobManager 处接收需要部署的 Task,部署启动后,与自己的上游建立 Netty 连接,接收数据并处理。

对于相同机器之间的task通信
在这里插入图片描述
对于不同task机器通信
在这里插入图片描述

Flink On Yarn

在这里插入图片描述

  1. FlinkYarnSessionCli 启动的过程中首先会检查Yarn上有没有足够的资源去启动所需要的container,如果有,则上传一些flink的jar和配置文件到HDFS,这里主要是启动AM进程和TaskManager进程的相关依赖jar包和配置文件。

  2. 接着yarn client会首先向RM申请一个container来启动ApplicationMaster(YarnApplicationMasterRunner进程),然后RM会通知其中一个NM(node manager)启动这个container,被分配到启动AM的NM会首先去HDFS上下载第一步上传的jar包和配置文件到本地,接着启动AM;在这个过程中会启动JobManager,因为JobManager和AM在同一进程里面,它会把JobManager的地址重新作为一个文件上传到HDFS上去,TaskManager在启动的过程中也会去下载这个文件获取JobManager的地址,然后与其进行通信;AM还负责Flink的web 服务,Flink里面用到的都是随机端口,这样就允许了用户能够启动多个yarn session。

  3. AM 启动完成以后,就会向AM申请container去启动TaskManager,启动的过程中也是首先从HDFS上去下载一些包含TaskManager(yarn模式的话这里就是YarnTaskManager )主类 的jar和启动过程依赖的配置文件,如JobManager地址所在的文件,然后利用java cp的方式去启动YarnTaskManager ,一旦这些准备好,就可以接受任务了。这个和spark on yarn的yarn cluster模式其实差不多,也是分为两个部分,一个是准备工人和工具(spark是启动sc的过程,flink是初始化ENV的过程),另外一个就是给工人分配具体工作(都是执行具体的操作,action什么的触发)

Chandy-Lamport算法(一种分布式快照算法)

算法是有前提的,就是默认节点永远可以正确处理网络通信(节点不崩溃,网络不中断,通信不乱序,等等)根据CAP,如果我们不需要保证P,那么我们肯定可以找到一种高可用而且一致性的方案。当然,既然要高可用,就一定不能依赖全局的共享存储和全局时钟。这里的所谓一致性,也是强一致性的概念,系统时时刻刻保持一致性。


原paper的例子是两个节点传递令牌,任何时候,令牌只存在于P,Q两个节点或两个节点之间的通信C和C’中。
每个节点都会记录自己的state,和所有自己的incoming channel的state。
算法总体流程如下

  • 任何节点的snapshot由本地状态snapshot和节点的input channel snapshot组成
  • 任何src可以任意时间决定take本地状态snapshot,take完本地snapshot,广播一个marker给所有下游
  • 任意没有take本地snapshot的节点(注意这个算法里src也是可以接受别人的msg的),假设从第x个channel收到第+ 一个marker的时候,take本地状态snapshot(且take接受到第一个marker的input channel-x的channel snapshot为空),然后给所有output channel广播这个marker
  • 从收到第一个marker并take完本地snapshot之后,记录所有input channel的msg到log里,直到从所有的input channel都收到这个marker. 作为这些input channel的channel snapshot。

在任何时候系统崩溃,所有src广播maker前发送事件在分布式系统内都是可以被恢复的。系统崩溃后,各节点加载自己的状态的SNAPSHOT,然后src重新发送maker就行。(防止在src记录snapshot到发送maker之间系统崩溃。
A,B,C,D代表4个process.有向线段代表FIFO的channel.绿色圆形代表普通message,橙色矩形代表marker.蓝色的节点和线段代表已经记录state的process和channel
Process A启动snapshot算法,A执行marker sending rule(记录自身state,然后发送marker):
在这里插入图片描述
Process B接收到marker,执行marker receiving rule:将channel AB的state记为空集,然后记录自身state并向下发送marker:
在这里插入图片描述
Process C接收到marker, 执行marker receiving rule:将channel AC的state记为空集,然后记录自身state并向下发送marker:
在这里插入图片描述
Process D接收到来自于process B的marker, 执行marker receiving rule:将channel BD的state记为空集,然后记录自身state并向下发送marker:
在这里插入图片描述
Process D接收到来自于process C的marker, 执行marker receiving rule:这是process D第二次接收到marker,将channel CD的state记为{5},不会向下发送marker:
在这里插入图片描述
自此process A,B,C,D的local state和所有Channel的state都记录完毕. 将这些local state组合,所得到的就是global state

节点在不断发消息的同时做local snapshot和发送marker(Flink中称为barrier个人觉得更加直观),然后所有节点都处理marker前的数据,marker后的数据先缓存记录,等所有节点都处理完marker前的数据并且都导出自己的local snapshot后,这个global snapshot就完成了,而且保证所有节点都处理完marker前的数据。

Flink的算法 ---- Asynchronous Barrier Snapshotting(ABS)

每个节点都要记录所有income channel state。这种做法有好处,就是事件可以随到随处理。但是也有不好的地方,那就是每个节点都要记录income channel state和自己的state,我们要得知目前系统的状态,就必须查询节点的记录。然而,在实际生产中,我们希望的是在sink端就可以得知目前系统的状态。所以,Flink做了一点改变。

A是JobManager, B C是source,D是普通task。JobManager发起一次snapshot:向所有source发送barrier.
在这里插入图片描述
每个Barrier先后到达各自的source.Source在收到barrier后记录自身state,然后向下游节点发送barrier
在这里插入图片描述
Barrier (from)B 到达process D,但不会进行snapshot
在这里插入图片描述
Barrier (from)B已经到达process D,

所以当来自于channel BD的record 6 7到达后,process D不会处理它们,而是将它们放入input buffer.

而Barrier (from)C尚未到达process D,所以当来自于channel CD的record 4到达后,process D会处理它.
在这里插入图片描述
Barrier C也到达process D.

这样,process D已经接收到了所有上游process的barrier.process D记录自身state,然后向下游节点发送barrier
在这里插入图片描述

如果上述过程中不准备input buffer而是对6,7事件进行直接处理,那么就是实现了At Least Once语义。因为恢复时系统无法判定6,7是否被处理,所以选择进行重发。

Flink中端到端的Exactly Once实现

上述算法只能Flink内部在任何时候状态都是一致的。但是,如果涉及到外部系统,问题则依然存在。
在这里插入图片描述

上图中,如果下面的路径处理失败,但是SinkA已经把offset提交到外部系统了。这是不可能回滚的。
2PC还是如期而至了

  • Phase 1: Pre-commit
    Flink的JobManager向source注入checkpoint barrier以开启这次snapshot.
    barrier从source流向sink.
    每个进行snapshot的算子成功snapshot后,都会向JobManager发送ACK.
    当sink完成snapshot后, 向JobManager发送ACK的同时向kafka进行pre-commit.
  • Phase 2:Commit
    当JobManager接收到所有算子的ACK后,就会通知所有的算子这次checkpoint已经完成.
    Sink接收到这个通知后, 就向kafka进行commit,正式把数据写入到kafka

Flink CEP

CEP(Complex Event Processing)就是在无界事件流中检测事件模式,让我们掌握数据中重要的部分。flink CEP是在flink中实现的复杂事件处理库。
在这里插入图片描述
一个结束
https://www.jianshu.com/p/2e4caf0d2cd7?utm_campaign=shakespeare

WaterMark

Flink在流处理程序支持不同的时间概念。分别为Event Time/Processing Time/Ingestion Time,也就是事件时间、处理时间、提取时间。

从时间序列角度来说,发生的先后顺序是:

  • 事件时间(Event Time)----> 提取时间(Ingestion Time)----> 处理时间(Processing Time)

    • Event Time 是事件在现实世界中发生的时间,它通常由事件中的时间戳描述。
    • Ingestion Time 是数据进入Apache Flink流处理系统的时间,也就是Flink读取数据源时间。
    • Processing Time 是数据流入到具体某个算子 (消息被计算处理) 时候相应的系统时间。也就是Flink程序处理该事件时当前系统时间。
窗口触发机制

假如我们设置10s的时间窗口(window),那么0~10s,10~20s都是一个窗口,以0~10s为例,0为start-time,10s为end-time。假如有4个数据的event-time分别是8(A),12.5(B),9©,13.5(D),我们设置Watermarks为当前所有到达数据event-time的最大值减去延迟值3.5秒

当A到达的时候,Watermarks为max{8}-3.5=8-3.5 = 4.5 < 10,不会触发计算
当B到达的时候,Watermarks为max(12.5,8)-3.5=12.5-3.5 = 9 < 10,不会触发计算
当C到达的时候,Watermarks为max(12.5,8,9)-3.5=12.5-3.5 = 9 < 10,不会触发计算
当D到达的时候,Watermarks为max(13.5,12.5,8,9)-3.5=13.5-3.5 = 10 = 10,触发计算

常见实践
  • 采用系统时间减去一定时间
  • 采用Event Time减去一定时间做watermark
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值