本文的整体结构为 一些概念 6个问题 2个demo 一次解答
dataflow 流处理的基本概念和名词
-
dataflow基本概念,首先至少包含一个数据源和一个数据汇,即输入和输出,如下图
图1-1
-
数据,任务并行
- 数据并行 图 1-1就是数据并行
- 任务并行 如果数据源也并行 数据汇也并行 那么全任务均并行 就是任务并行
-
数据交换策略
- 转发
- 发送端和接收端任务一对一传输 如果两个任务在同一台物理机可以避免数据交换(由任务调度器决定)
- 广播
- 将数据分发到下游的全部算子 数据会被复制多份 并涉及网络通信 代价昂贵
- 键值
- 同广播 不过不全部复制 仅根据键值复制 减少开销 将同键值的数据交给同一个任务处理 如图3-1图书分类就是根据键值分类 保证统计的准确性
- 随机
- 将数据均匀分布到下游算子 实现任务负载均衡
- 转发
-
窗口类型 桶
-
滚动窗口(不重叠count-based time-based)
- 场景 每分钟 流量统计
- 图1-3-1
- 场景 每分钟 流量统计
-
滑动窗口(重叠count-based time-based)
- 两个参数 偏移量和间隔
- 场景 每隔10分钟 统计1小时内的平均温度
- 图1-3-2
-
会话窗口(一组事件为一个会话 可以设置非活动最大等待时间)
- 根据一个事件key分组打开窗口
- 用户行为分析
-
-
时间语义
-
处理时间
- 场景 实时监控仪表盘
- 特性 低延迟 速度快
-
事件时间
- 场景 用户行为分析 用户网络突然中断 当网络恢复后 可以完整有序的重放用户行为
- 特性 允许延迟 支持乱序
-
-
状态
- 某间隔一段时间 基于一定个数的事件 积累状态 有状态算子同时使用传入的事件和内部状态计算输出
- 场景 高温烟雾预警 高温10分钟内 产生烟雾则告警
- 特性 注意避免状态无限增长因为流是无限的 通常保存的是摘要(数量值或者累加值)
- 某间隔一段时间 基于一定个数的事件 积累状态 有状态算子同时使用传入的事件和内部状态计算输出
-
故障
- 任务故障 ①接收事件并保存在本地缓存区 ②选择性更新状态 ③产生输出 任意节点都将会产生故障 这些故障如何恢复
- 结果保障 主要强调引擎内部状态一致 输出一致需要靠事务或重试保证(数据汇写出的数据不受保护)
- 至多一次 其实就是没保障 数据丢了也不需要重放
- 至少一次 事件不丢失 可能重复多次 正确性仅依赖数据完整度 可以依赖事件重放或者ack(rabbitmq就是ack)即完成后回调确认
- 精确一次 最困难最严格的保障 在至少一次的基础上实现 可以通过事务但是会有极大开销 flink支持精确一次 但是根据轻量级的检查点机制(需满足数据可回放,且可在上次故障点之后回放) 在统计出现次数的时候很有必要
flink是什么
Apache Flink 是一个框架和分布式处理引擎,用于在【无边界】和【有边界】数据流上进行【有状态】的计算。Flink 能在所有常见集群环境中运行,并能以【内存速度】和【任意规模】进行计算
-
有边界和无边界的数据流 【window】
- 流应用数据源源不断 有时候需要通过窗口的形式对数据划分边界 并针对窗口进行统计 窗口支持time,count,session划分 比如每分钟的访问量等
-
支持事件时间
- process time 当前系统时间
- event time 事件产生时间 在窗口计算的时候 乱序的数据可以还原原本的时序性
-
有状态
- 将计算的结果保存在内存或者文件系统中 这样下一次计算事件来了 可以直接根据上一次的计算结果进行计算 避免将历史数据都导出来重写算一遍 比如 topN排名
-
内存速度
- 有状态的 Flink 程序针对本地状态访问进行了优化。任务的状态始终保留在内存中,如果状态大小超过可用内存,则会保存在能高效访问的磁盘数据结构中。任务通过访问本地(通常在内存中)状态来进行所有的计算,从而产生非常低的处理延迟。Flink 通过定期和异步地对本地状态进行持久化存储来保证故障场景下精确一次的状态一致性。
- 任务合并
-
任意规模
- Flink 旨在任意规模上运行有状态流式应用。因此,应用程序被并行化为可能数千个任务,这些任务分布在集群中并发执行。所以应用程序能够充分利用无尽的 CPU、内存、磁盘和网络 IO。而且 Flink 很容易维护非常大的应用程序状态。其异步和增量的检查点算法对处理延迟产生最小的影响,同时保证精确一次状态的一致性。
-
支持精确一次
在这里我们带着几个问题去看flink
-
①状态
- flink的状态是如何管理的
- 状态存在了哪
-
②故障
- 如何保证精确的状态一致性(exactly-once) 即每条数据只被处理一次
-
③事件时间是如何支持的
- 如何支持乱序的
- 迟到太多了怎么处理
-
并行
- ④对于一个并行任务cpu和内存是被如何分配的
-
反压
- ⑤当吞吐不够的时候 是如何处理数据的
-
任务合并
- 什么是任务合并如何组织任务合并⑥
flink的架构
- 首先flink是一个【并行化】【流处理】【分布式】系统
- 分配管理集群计算资源
- 进程协调
- 故障恢复
- 持久且高可用的数据存储(hdfs,s3,文件系统,内存)
-
分布式(zookeeper,k8s高可用)
图3-2
-
flink的组件
- jobManager(job)
- 主进程,JobManager控制单个应用程序执行 将任务分发给taskManager的处理槽执行 负责所有需要集中协调的操作 如 检查点,状态,保存点的创建
- taskManager
- 通常需要多个 每个taskManager提供一定数量的处理槽 同应用不同任务的taskManager需要进行数据交换
- resourceManager
- 不同提供者有不同实现(k8s,yarn等)负责告知jobManager目前有多少处理槽,当处理槽不够自动创建taskManager,任务空闲的时候自动终止taskManager释放计算资源
- dispatcher
- flink rest接口的提供方 提供一个WEB UI
- jobManager(job)
-
应用部署
- 框架模式
- flink应用会打成一个jar包 通过客户端提交任务
- 如果任务提交到jobManager则任务直接执行,如果提交到YARN ResourceManager和Dispatcher则会创建一个jobManager并执行
- 库模式
- 没包含在官方文档 不做具体讲解 大概是将flink跟应用绑在一个docker里面
- 框架模式
结合图例和demo问题解答
- 问题解答
-
①状态,②故障,⑥任务合并 先跑demo BasicTransformations演示正常流程,演示服务异常后重启服务①
-
状态
- 理解为每个算子自己保存在flink中的一些变量
-
检查点
-
检查点是故障恢复的核心
-
检查点生成过程
- 检查点根据配置周期性生成
-
检查点图例
图4-1-2
-
故障恢复
- 从图4-1-2中不难看出要想保证至少一次 那么数据源需要支持任意游标的重放,如果在此基础上,数据汇写入支持幂等或事务则可保证精确一次
-
-
保存点
- 生成逻辑同检查点
- 手动生成
- 可以运行到不同集群上(系统迁移)
- 可以在不同并行度运行(所扩容)
- 可以启动一个不相同但是兼容的应用(修改应用bug)
- 何为兼容
- 生成保存点的时候 会将所有算子的状态cp到保存点上
- 恢复的时候也根据算子id进行恢复 flink默认会为每个算子生成一个id 但是当应用内新增算子后 算子id将会发生变化 所以如果想要修改应用结构 而还可以通过保存点兼容恢复 我们最好是手动生成算子id
- 何为兼容
-
任务合并
- demo BasicTransformations 演示任务合并③
-
-
③事件时间是如何支持的 ⑤并行时cpu和内存的分配 先跑demo BasicTransformations 演示事件时间如何定义,当事件时间不再更新后 水位线也不更新②
-
滚动聚合根据code分组 并对code进行sum
- 发现根据key自动做了键值数据传输,同键的数据会放到一个算子中
-
事件时间是如何支持的
- flink如何定义事件时间
- 事件时间的乱序如何处理 引入水位线
- 水位线
- 根据当前最大事件时间为根基 水位线=当前最大事件时间-延迟时间
- 非延迟水位线
- 图4-2-1
- 延迟水位线
- 图4-2-2
- 水位线时间是根据事件最大时间为根 计算得出的 如果事件时间不更新则水位线不更新
- 迟到太多了怎么处理
- 丢弃(默认)
- 写到旁路输出 自定义进行更新
- 重新计算
- 设置延迟容忍度 当延迟容忍度未到时 窗口虽然执行了但是还依然保留
- 非延迟水位线
- 根据当前最大事件时间为根基 水位线=当前最大事件时间-延迟时间
- 水位线
-
-
网友评论