避坑指南系列之——Flink双流JOIN
我们在实时场景开发过程中经常用到两种JOIN类型,一种是维表JOIN,另外一种是双流JOIN。本文将重点介绍这两种JOIN方式。
当维表是一张不断变化的表时,在JOIN时需指明该条记录关联维表快照的时刻,一般使用Temporal Table Join,即加上FOR SYSTEM_TIME AS OF PROCTIME(),表示JOIN维表当前时刻所看到的每条数据。
对于双流JOIN,一般经常用到的有LEFT JOIN和INNER JOIN。
先给大家普及一下实时计算知识
1、流处理与批处理
2、流表对偶性
3、动态表
4、持续查询
5、增量计算
接下来我们重点介绍双流JOIN
1、双流JOIN与传统数据库表JOIN的区别?
- 数据集合:传统数据库左右两个表的数据集合是有限的,双流JOIN的数据会源源不断的流入
- 结果更新:传统数据库表JOIN是一次执行产生最终结果后退出,双流JOIN会持续不断的产生新的结果
- 计算驱动:双流JOIN由于左右两边的流的速度不一样,需要状态存储,双流驱动
2、双流JOIN怎么进行数据Shuffle
分布式流计算所有数据会进行Shuffle,怎么才能保障左右两边流的要JOIN的数据会在相同的节点进行处理呢?在双流JOIN的场景,我们会利用JOIN中ON的联接key进行partition,确保两个流相同的联接key会在同一个节点处理。
3、Temporal Table JOIN与双流JOIN的区别
- 状态管理:Temporal Table JOIN 和 双流 JOIN都可以管理State
- 计算驱动:Temporal Table JOIN是单边驱动,是被动的查询(表的更新不会触发结果的更新), 而双流JOIN是双边驱动,两边都是主动的进行JOIN计算
避坑指南
LEFT OUTER JOIN 可以简写 LEFT JOIN,语义上和INNER JOIN的区别是不论右流是否有JOIN的事件,左流的事件都需要流入下游节点,但右流没有可以JION的事件时候,右边的事件补NULL。
- 对于左流的事件,当右边没有JOIN的事件时候,将右边事件列补NULL后流向下游;
- 当右边事件流入发现左边已经有可以JOIN的key的时候,并且是第一个可以JOIN上的右边事件,需要撤回左边下发的NULL记录,并下发JOIN完整的事件到下游。
这里关于INNER JOIN的语义和大家强调两点:
1、INNER JOIN只有符合JOIN条件时候才会有JOIN结果流出到下游,如果关联不上,流入时候没有任何输出,因为左边还没有可以JOIN的事件;
2、INNER JOIN两边的数据不论如何乱序,都能够保证和传统数据库语义一致,因为我们保存了左右两个流的所有事件到state中。
当我们使用双流JOIN时需要注意上面提到的问题:
由于LEFT JOIN的语义是匹配不上左表数据补null,那这个时候就会输出很多中间状态的脏数据(即便内部的数据撤回机制会最终输出正确的结果),如果我们分组统计后,这种脏数据对应的主键与最终正确的数据对应的主键是不一样的,所以没有办法更新掉脏数据。对于这种场景,我们需要使INner JOIN的方式,即匹配不上会等待,不会向下游输出,这个时候肯定会保证最终结果的一致性。
总结
回归到两种JOIN方式上面,对于LETF JOIN而言,如果左流的事件没能匹配到右边JOIN的事件时候,将右边事件列补NULL后流向下游。对于JOIN而言,INNER JOIN只有符合JOIN条件时候才会有JOIN结果流出到下游,如果关联不上,流入时候没有任何输出,因为左边还没有可以JOIN的事件,但是对于分组统计类型的计算需要考虑脏数据无法撤回导致结果统计错误问题。