Flink 是一个流处理框架,支持流处理和批处理,特点是流处理有限,可容错,可扩展,高吞吐,低延迟。
流处理是处理一条,立马下一个节点会从缓存中取出,在下一个节点进行计算
批处理是只有处理一批完成后,才会经过网络传输到下一个节点
流处理的优点是低延迟 批处理的优点是高吞吐
flink同时支持两种,flink的网络传输是设计固定的缓存块为单位,用户可以设置缓存块的超时值来决定换存块什么时候进行传输。 数据大于0 进行处理就是流式处理。 如果设置为无限大就是批处理模型。
Flink Strom Spark Streaming
1. Flink 基本架构
Flink 集群包括 JobManager 和 TaskManager .
JobManager 主要负责调度 Job 并协调 Task 做 checkpoint,职责上很像 Storm 的 Nimbus。从 Client 处接收到 Job 和 JAR 包 等资源后,会生成优化后的执行计划,并以 Task 的单元调度到各个 TaskManager 去执行。
TaskManager 在启动的时候就设置好了槽位数(Slot),每个 slot 能启动一个 Task,Task 为线程。从 JobManager 处接收需要 部署的 Task,部署启动后,与自己的上游建立 Netty 连接,接收数据并处理。
2. Flink On Yarn 结构
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
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。
实时框架如何选择
1:需要关注流数据是否需要进行状态管理 2:At-least-once或者Exectly-once消息投递模式是否有特殊要求 3:对于小型独立的项目,并且需要低延迟的场景,建议使用storm 4:如果你的项目已经使用了spark,并且秒级别的实时处理可以满足需求的话,建议使用sparkStreaming 5:要求消息投递语义为 Exactly Once 的场景;数据量较大,要求高吞吐低延迟的场景;需要进行状态管理或窗口统计的场景,建议使用flink
Flink 编程结构
Flink 提供的Api右 DataStream 和 DataSet ,他们都是不可变的数据集合,不可以增加删除中的元素, 通过 Source 创建 DataStream 和 DataSet
- 获取运行时
流处理: StreamingExecutionEnvironment
批处理: ExecutionEnvironment
在创建运行时有:
代码语言:javascript复制createLocalEnvironment 和 createRemoteEnvironment
- 添加外部数据源
env.addSource(...)
- 定义算子
input.map{}
- 定义Sink
stats.addSink(...)
- 启动程序
env.execute()
Flink 优化与调度策略
Flink的每一个Operator称为一个任务, Operator 的每一个实例称为子任务,每一个任务在JVM线程中执行。可以将多个子任务链接成一个任务,减少上下文切换的开销,降低延迟。
source 和 算子map 如果是 one by one 的关系,他们的数据交换可以通过缓存而不是网络通信
TaskManager 为控制执行任务的数量,将计算资源划分多个slot,每个slot独享计算资源,这种静态分配利于任务资源隔离。
同一个任务可以共享一个slot, 不同作业不可以。
Flink 使用 slot来隔离多个作业任务。
- 调度策略
env.addSource(...).setParallelism(4)
.map(...).setParallelism(4)
.reduce(...).setParallelism(3)
这里因为 Source 和 Map 并行度都是4 采用直连方式,他们的数据通信采用缓存形式
所以一共需要两个TaskManager source,Map 一个,reduce一个, 每个TaskManager 要3个slot
- 作业控制
JobManager 将 JobGraph 部署 ExecutionGraph
- JobGraph 由 Operator和传输通道的数据缓存组成。 Operator 是计算图中的顶点 JobVertex
- ExecutionGraph 由 ExecutionVertex 和 中间结果的多个分区组成。
设置的并行度,可以让一个ExecJobVertex 对应 多个并行的ExecVertex 实例。
Flink通过状态机管理 ExecGraph的作业执行进度。
Flink 如何管理内存
Flink 将对象序列化为固定数量的预先分配的内存段,而不是直接把对象放在堆内存上。 Flink TaskManager 是由几个内部组件组成的:actor 系统(负责与 Flink master 协调)、IOManager(负责将数据溢出到磁盘并将其读取回来)、MemoryManager(负责协调内存使用。
流处理API
数据源:
代码语言:javascript复制env.readTextFile("/path")
env.readFile(inputFormat,"path")
env.socketTextStream("localhost", port,'n')
env.fromElements(data: T*)
env.addSource(new FlinkKafkaConsumer08)
Sink:
代码语言:javascript复制windowCounts.writeAsCsv()
windowCounts.print().setParallelism(1)
windowCounts.addSink()
windowCounts.writeToSocket()
时间:
处理时间:取自Operator的机器系统时间
事件时间: 由数据源产生
进入时间: 被Source节点观察时的系统时间
代码语言:javascript复制 env.setStreamTimeCharacteristic(TimeCharacteristic.EventTime)
env.setStreamTimeCharacteristic(TimeCharacteristic.IngestionTime)
env.setStreamTimeCharacteristic(TimeCharacteristic.ProcessingTime)
水印
如果数据源没有自己正确创建水印,程序必须自己生成水印来确保基于事件的时间窗口可以正常工作。。
DataStream 提供了 周期性水印,间歇式水印,和递增式水印