【每天一个知识点】Flink 回撤流

1,043 阅读2分钟

回撤流是flink Table/SQL api处理动态表(流表)的独特机制,为了保证计算的正确性上游算子会发送回撤流给下游算子

回撤流是由一对记录组成:

撤回记录:表明当前记录值失效

新增记录:表示新的有效结果

举一个例子,我们对订单表统计一个用户的有效订单的总金额计算,其中status=1代表有效,订单流是一个变更流,status状态会发生改变,也会其他属性的更新或消息重复,这说明一个订单可能有多条记录

所以根据上面的场景如果我们想正确的统计用户有效订单的总金额,需要先对订单流进行开窗去重复,在进行统计

create table order_source () with{...}//省略创建source

//去重复
create view valid_order_detail as
select * from (
  select 
    * ,
    row_number() over ((PARTITION BY order_id ORDER BY update_time DESC) as rnk
 from order_source  
) as a 
where a.rnk = 1
and a.status = 1

//计算用户有效订单的总金额
create view user_order_amount as 
select 
    o.user_id,
    sum(o.amount)
from 
valid_order_detail as o
group by o.user_id

如果订单流来两条记录

user_idorder_idamountstatusupdate_time
u_1o_11011711421644000
u_1o_21001711421643000

去除重复后

row_number算子只会下发

u_1 | o_1 | 10 | 1 | 1711421644000

此时 统计的结果

u_1 | 10

当来一条新纪录的时候,又将状态更新成0

u_1 | o_1 | 10 | 0 | 1711421645000

这个时候row_number算子就需要下发一个回撤流,通知下游聚合算子重新计算

-(u_1 | o_1 | 10 | 1 | 1711421644000)

+(u_1 | o_1 | 10 | 0 | 1711421645000)

统计的结果就会修正为正确的

在这个例子中我了解的回撤的基本原理,那么到底是谁产生回撤消息,而又是谁消费回撤消息?

flink回撤机制

简单来讲,基于key的动态表动态更新的场景下需要回撤,所谓动态表就是具有组件的source表或者join/group by阐述的动态表也就是例子中的valid_order_detail和

user_order_amount,

算子分为模式,分别是Accumulating Mode (AccMode) 和 Accumulating and Retracting (AccRetractMode)

AccMode只处理 acc message 而AccRetractMode的算子可以处理回撤消息

所以flink会根据上游的动态表来决定算子的模式。在例子中rank 算子和count算子都是AccRetractMode的算子。