有状态的流式计算框架
可以处理源源不断的实时数据,数据以event为单位,就是一条数据。
先获取执行环境env,然后添加source数据源,转换成datastream,然后使用各种算子进行计算,使用sink算子指定输出的目的地,最后调用execute方法执行。
per-job和application区别:
应用模式是生产上主要提交模式,单作业模式和应用模式都是一个job启动一个集群,所以可以做到资源隔离,而会话模式是多个job分享一个集群,适合小作业共享。
JobManager
管理节点,任务切分分配
dispatcher:将job传递给Jobmaster
resourManager:申请资源
JobMaster:切分任务
Checkpointcoordinator:向数据源注入barrier
TaskManager
执行任务计算
资源最小单位slot ,算子就是我们task任务
一个算子(map,filter,flatmap)就是一个task
算子并行子任务就是subtask
一个task的子任务不能在一个slot中执行
一个slot中可以执行不同算子的subtask
算子 > 全局env > 提交命令行 > 配置文件
多个subtask组成一个大的subtask
条件:
算子合并优点和缺点 ?
如何禁用算子链?
env.disableOperatorChaining()
如何设置不同的共享槽?
.slotSharingGroup("aa")
产生 | 发送 | 做了什么事情 | |
---|---|---|---|
StreamGraph | Client | Client | 代码解析 |
JobGraph | Client | JM | 算子链的合并 |
ExecutionGraph | JM | TM | 并行子任务显示 |
物理执行图 |
kafkasource(算子状态,保存offset)
kafkasink,dorissink, jdbcsink, filesink
逻辑时钟,单调递增,解决乱序迟到问题
场景题:上游算子发生数据倾斜,某一个subtask没有数据,水位线无法抬升怎么办?
解决办法:
调用withIdleness()方法,如果某一个subtask没有数据,超过了空闲等待时间,那么放弃使用这个subtask的水位线。
当前最大时间戳 - 乱序时间 - 1ms
概念:无界流切分为有界流, 集合中是一个个的桶
场景问题:表的字段有mid timestamp price ,要求算当前累积GMV, 5分钟输出一次
解决方案:
划分(数据属于哪个窗口)
开一个5s滚动窗口 数据是3s 会落到哪个窗口:0-5 3-8
结论:窗口的向下取整
timestamp - (timestamp - offset) % windowSize
生命周期
创建:属于窗口第一条数据到来
销毁:事件时间 >= 窗口长度 +允许迟到时间
左闭右开
endtime -1ms
5s滚动窗口 乱序时间设置2s 销毁时间5s (7s数据过来时候,时间推进到5s)
5s滚动窗口 窗口延迟关闭2s 销毁时间7s (7s数据过来时候,时间推进到7s)
结论:
设置乱序时间,并不会影响窗口销毁时间,影响时间推进规则,窗口延迟关闭时间影响窗口的关闭时间。
举个栗子:
10s滚动窗口,设置乱序时间5s,窗口延迟关闭时间5s
窗口销毁:水位线15s时候销毁, 数据携带20s及以上过来触发窗口销毁
概念:用户定义的一些变量
状态数据是交由Flink托管的,考虑程序数据的恢复
本地 | 远端 | |
---|---|---|
hashmap | TM堆内存 | hdfs |
rocksdb | rocksdb | hdfs |
使用场景:rocksdb存储数据量级别比hashmap大
企业中大状态场景选用的rocksdb ,大状态场景优化
举个例子:
用户新老访客修复 1000w用户 1k ≈ 10G
rocksdb支持:增量检查点 、 本地恢复 、预定义选项
状态的过期时间是由哪个类设置的:
StateTttlConfig
源头:offset可重发
Flink:checkpoint
sink:事务(2pc 预写日志) 幂等
场景:程序升级 (算子增加,算子减少)
增加uid
Flinksql如何转化成底层的api?
使用calcite解析语法树
sql转化 ast语法树 逻辑执行 物理执行 底层api执行
bin/flink run
-d 后台运行
-D 并行度 5
-D JM内存 1~4 G
-D TM内存 4~8 G
-D TM的slot个数 3(1~4)
-c 主类
./jar包
如果并行设置为5个,slot个数设置为3个,那么会启动2个TM
FLink充当客户端, ds的worker节点都需要部署
如果是streampark:需要部署一台
Flink | sparkstreaming | |
---|---|---|
模型 | 流式 | 微批次 |
时间 | 丰富 | 处理时间 |
乱序 | 解决 | 不能解决 |
窗口 | 多灵活 | 窗口长度必须是批次整数倍 |
容错机制 | 有 | 没有 |
状态 | 有 | 没有 |
底层调用的是keyby + connect ,处理逻辑:
(1)判断是否迟到(迟到就不处理了,直接return)
(2)每条流都存了一个Map类型的状态(key是时间戳,value是List存数据)
(3)任一条流,来了一条数据,遍历对方的map状态,能匹配上就发往join方法
(4)使用定时器,超过有效时间范围,会删除对应Map中的数据(不是clear,是remove)
Interval join不会处理join不上的数据,如果需要没join上的数据,可以用 coGroup+join算子实现,或者直接使用flinksql里的left join或right join语法。
分组和分区在 Flink 中具有不同的含义和作用:
分区:分区(Partitioning)是将数据流划分为多个子集,这些子集可以在不同的任务实例上进行处理,以实现数据的并行处理。
数据具体去往哪个分区,是通过指定的 key 值先进行一次 hash 再进行一次 murmurHash,通过上述计算得到的值再与并行度进行相应的计算得到。
分组:分组(Grouping)是将具有相同键值的数据元素归类到一起,以便进行后续操作(如聚合、窗口计算等)。key 值相同的数据将进入同一个分组中。
注意:数据如果具有相同的 key 将一定去往同一个分组和分区,但是同一分区中的数据不一定属于同一组。