Flink 原理详解

时间:2022-07-22
本文章向大家介绍Flink 原理详解,主要内容包括其使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。

Flink 是一个流处理框架,支持流处理和批处理,特点是流处理有限,可容错,可扩展,高吞吐,低延迟。

流处理是处理一条,立马下一个节点会从缓存中取出,在下一个节点进行计算

批处理是只有处理一批完成后,才会经过网络传输到下一个节点

流处理的优点是低延迟 批处理的优点是高吞吐

flink同时支持两种,flink的网络传输是设计固定的缓存块为单位,用户可以设置缓存块的超时值来决定换存块什么时候进行传输。 数据大于0 进行处理就是流式处理。 如果设置为无限大就是批处理模型。

Flink 集群包括 JobManager 和 TaskManager .

JobManager 主要负责调度 Job 并协调 Task 做 checkpoint,职责上很像 Storm 的 Nimbus。从 Client 处接收到 Job 和 JAR 包 等资源后,会生成优化后的执行计划,并以 Task 的单元调度到各个 TaskManager 去执行。

TaskManager 在启动的时候就设置好了槽位数(Slot),每个 slot 能启动一个 Task,Task 为线程。从 JobManager 处接收需要 部署的 Task,部署启动后,与自己的上游建立 Netty 连接,接收数据并处理。

flinkyarn.png

flink on yarn 是由client 提交 app到 RM 上, 然后RM 分配一个 AppMaster负责运行 Flink JobManager 和 Yarn AppMaster, 然后 AppMaster 分配 容器去运行 Flink TaskManger

3. SparkStreaming 架构

SparkStreaming 是将流处理分成微批处理的作业, 最后的处理引擎是spark job

Spark Streaming把实时输入数据流以时间片Δt (如1秒)为单位切分成块,Spark Streaming会把每块数据作为一个RDD,并使用RDD操作处理每一小块数据。每个块都会生成一个Spark Job处理,然后分批次提交job到集群中去运行,运行每个 job的过程和真正的spark 任务没有任何区别。

JobScheduler, 负责 Job的调度通过定时器每隔一段时间根据Dstream的依赖关系生一个一个DAG图

ReceiverTracker负责数据的接收,管理和分配 ReceiverTracker在启动Receiver的时候他有ReceiverSupervisor,其实现是ReceiverSupervisorImpl, ReceiverSupervisor本身启 动的时候会启动Receiver,Receiver不断的接收数据,通过BlockGenerator将数据转换成Block。定时器会不断的把Block数据通会不断的把Block数据通过BlockManager或者WAL进行存储,数据存储之后ReceiverSupervisorlmpl会把存储后的数据的元数据Metadate汇报给ReceiverTracker,其实是汇报给ReceiverTracker中的RPC实体ReceiverTrackerEndpoin

4. Spark on Yarn
sparkstream.jpg

spark on yarn 的cluster模式, Spark client 向RM提交job请求, RM会分配一个 AppMaster, driver 和 运行在AppMAster节点里, AM然后把Receiver作为一个Task提交给Spark Executor 节点, Receive启动接受数据,生成数据块,并通知Spark Appmaster, AM会根据数据块生成相应的Job, 并把Job 提交给空闲的 Executor 去执行。

对比Flink和spark streaming的cluster模式可以发现,都是AM里面的组件(Flink是JM,spark streaming是Driver)承载了task的分配和调度,其他 container承载了任务的执行(Flink是TM,spark streaming是Executor),不同的是spark streaming每个批次都要与driver进行 通信来进行重新调度,这样延迟性远低于Flink。
flinkvs.png

实时框架如何选择

1:需要关注流数据是否需要进行状态管理 2:At-least-once或者Exectly-once消息投递模式是否有特殊要求 3:对于小型独立的项目,并且需要低延迟的场景,建议使用storm 4:如果你的项目已经使用了spark,并且秒级别的实时处理可以满足需求的话,建议使用sparkStreaming 5:要求消息投递语义为 Exactly Once 的场景;数据量较大,要求高吞吐低延迟的场景;需要进行状态管理或窗口统计的场景,建议使用flink

Flink 提供的Api右 DataStream 和 DataSet ,他们都是不可变的数据集合,不可以增加删除中的元素, 通过 Source 创建 DataStream 和 DataSet

  1. 获取运行时
流处理: StreamingExecutionEnvironment 
批处理: ExecutionEnvironment

在创建运行时有:

createLocalEnvironment 和 createRemoteEnvironment
  1. 添加外部数据源
env.addSource(...)
  1. 定义算子
input.map{}
  1. 定义Sink
stats.addSink(...)
  1. 启动程序
env.execute()

Flink的每一个Operator称为一个任务, Operator 的每一个实例称为子任务,每一个任务在JVM线程中执行。可以将多个子任务链接成一个任务,减少上下文切换的开销,降低延迟。

source 和 算子map 如果是 one by one 的关系,他们的数据交换可以通过缓存而不是网络通信

TaskManager 为控制执行任务的数量,将计算资源划分多个slot,每个slot独享计算资源,这种静态分配利于任务资源隔离。

同一个任务可以共享一个slot, 不同作业不可以。

  1. 调度策略
env.addSource(...).setParallelism(4)
   .map(...).setParallelism(4)
   .reduce(...).setParallelism(3)

这里因为 Source 和 Map 并行度都是4 采用直连方式,他们的数据通信采用缓存形式

所以一共需要两个TaskManager source,Map 一个,reduce一个, 每个TaskManager 要3个slot

  1. 作业控制

JobManager 将 JobGraph 部署 ExecutionGraph

  1. JobGraph 由 Operator和传输通道的数据缓存组成。 Operator 是计算图中的顶点 JobVertex
  2. ExecutionGraph 由 ExecutionVertex 和 中间结果的多个分区组成。
flinkgr.jpg
flinkgraph.png

设置的并行度,可以让一个ExecJobVertex 对应 多个并行的ExecVertex 实例。

Flink通过状态机管理 ExecGraph的作业执行进度。

Flink 将对象序列化为固定数量的预先分配的内存段,而不是直接把对象放在堆内存上。 Flink TaskManager 是由几个内部组件组成的:actor 系统(负责与 Flink master 协调)、IOManager(负责将数据溢出到磁盘并将其读取回来)、MemoryManager(负责协调内存使用。

流处理API

数据源:

env.readTextFile("/path")
env.readFile(inputFormat,"path")

env.socketTextStream("localhost", port,'n')

env.fromElements(data: T*)

env.addSource(new FlinkKafkaConsumer08)

Sink:

windowCounts.writeAsCsv()
windowCounts.print().setParallelism(1)
windowCounts.addSink()
windowCounts.writeToSocket()

时间:

处理时间:取自Operator的机器系统时间

事件时间: 由数据源产生

进入时间: 被Source节点观察时的系统时间

    env.setStreamTimeCharacteristic(TimeCharacteristic.EventTime)
    env.setStreamTimeCharacteristic(TimeCharacteristic.IngestionTime)
    env.setStreamTimeCharacteristic(TimeCharacteristic.ProcessingTime)

水印

如果数据源没有自己正确创建水印,程序必须自己生成水印来确保基于事件的时间窗口可以正常工作。。

DataStream 提供了 周期性水印,间歇式水印,和递增式水印