Flink多连接优化问题

如同数据库中的join操作,有内连接(inner join)、外连接(outer join)、交叉连接(cross join,笛卡尔积)等,本文主要涉及内连接。
常用来实现连接的算法有:hash join、sort-merge join 以及 nested loop join,下面我们对这三种算法进行简单介绍。

join 算法

Hybrid-hash join

hash join 分为两个阶段,build和probe

  • build:为参与连接的两个数据集中较小的数据及准备好哈希表,哈希表中的记录包含着 连接的属性以及对应的行,从而能够快速访问给定连接属性对应的行。如果内存不够用,部分hash表会写到磁盘上去。
  • probe:一旦哈希表构建完成,会扫描更大的数据及并通过更小的数据集匹配哈希表以发现相关的行。如果在对probe输入端的数据的连接属性进行hash映射时,发现对应的hash table的数据有部分在磁盘中,就会把这个数据也写入磁盘中,否则直接就可以与匹配的行join。如果hash table全部在内存中,那么probe输入端的数据消费完就join完 了,否则(也就是磁盘中还有数据,注意的是此时probe端的输入只剩下之前写入到磁盘中的数据了)就要把当前的hash table drop 掉,然后从利用磁盘中的 数据重新build 一个hash table,并用磁盘中的probe端数据再进行 probe过程,重复这个过程直到所有数据消费完。
    在这里插入图片描述

sort-merge join

  • sort:对两个数据集在它们的连接键属性上进行排序。如果内存不够用,会使用外部排序算法进行排序。
  • merge:合并排过序的数据集
    在这里插入图片描述

nested loop join

用两层嵌套循环分别作用于两个参与连接的数据集,一般用于 cross join

在Flink的DataSet API中,hash和sort-merge算法都可被选择用于实现join和outerJoin,而nested loop只用于实现cross join。

通过hash join 来进行join操作时,需要确定哪个输入端作为build端,哪个输入端作为probe端,这是影响其执行效率的因素之一。当使用sort-merge 算法那来实现连接时,不会区分输入端的特殊职责。

执行策略

为了理清算法跟参与连接的输入端的关系,Flink将它们分成不同的策略:本地策略与传输策略。其中传入策略表示如何移动两个输入端中的数据使得它们具备连接的条件;本地策略则指两个已在本地的输入端数据集所执行的连接算法。

传输策略

flink提供两种传输策略,假设有两个待连接的数据集(R和S)。

  • Broadcast-Forward strategy (BF): 该策略会将一个完整的数据集,比如R,广播到数据集S的每个分区上,而数据集S的所有数据则一直处于本地,无需网络传输;
  • Repartition-Repartition strategy(RR):以相同的分区函数以及用于连接的键属性区分两个数据集R、S,每个分区仅分配给一个并行连接实例

本地策略

本地策略也有两种,即前文说的 Sort-Merge-Join strategy (SM) 和Hybrid-Hash-Join strategy (HH)。

Flink 如何选择join 策略

传输和本地策略是独立的,因此组合一下就有4种策略。如果将传输策略中的BF输入端以及本地策略中的HH输入端作区分,也可以认为是9种策略。每种策略根据数据大小以及内存大小的不同,会有不同的表现。
如果一个数据集非常大,一个非常小,则使用BF传输策略比较好,然后用小的数据集作为HH的输入。如果所有的数据都比较大或者join操作在很多并行的实例上执行,使用RR策略传输。

多连接优化问题

本质上是多连接的顺序选择问题,例如有四个数据集R、S、T、U需要做连接,那么可行的连接策略通常有左深树、右深树、浓密树(除左、右深树外的其它树结构都是浓密树,因此浓密树本身可能不止一个)这三种。
在这里插入图片描述

由于连接的参数顺序也属于变量,因此某颗树的参数顺序排列就有n!个,一般情况下会选用左深树,这是因为:

  1. 对于给定树叶的可能左深树的数量是很大(n!),但不会比所有树的数量那样大[T(n) * n],其中T(n)为树结构的数量,即T(1) =
    1, T (n) = Sum(T(i) * T(n-i)), i为1到n
  2. 左深树可以和一般的连接算法很好地交互,尤其是嵌套循环链接和一趟连接。左深树相对于其他树更加有效。
  3. 浓密树的搜索代价太大了。

左深树的连接操作是一种链式操作,其并发度仅限于两个关系连接时的并发,而稠密树在特殊情况下也会有优势,就是它的并行度可以比较高,从而带来时间上的收益,当然计算资源开销是比较大的。

这里需要补充一下关于连接运算大小的估计,这是优化器用于优化的核心依据之一,一般使用一下公式进行计算。假设 R(X,Y) JOIN S(Y,Z) ,card(R,Y)表示R中Y属性不同取值的个数。
T R ⋈ S = T ( R ) T ( S ) / m a x ( c a r d ( R , Y ) , c a r d ( S , Y ) ) T_{R \Join S} = T(R)T(S)/max(card(R,Y),card(S,Y)) TRS=T(R)T(S)/max(card(R,Y),card(S,Y))

贪心算法选择连接顺序

这是最好理解的方式了

  • 基础:以估算连接大小的最小关系开始;
  • 归约:在没有包含进来的关系中选择与当前树进行连接能得到估计大小最小的关系,被选中的关系作为右参数。然后将新树不断进行归约,最终得到完整的左深树。

其它方法

  • 动态规划 (可以参考这篇),比较适合连接的关系不多的情况,否则也比较耗时,毕竟是蛮算。然后由于代价评估公式也不一定准,所以最后结果可能也不太好
  • 遗传算法
  • 蚁群算法

参考:

  1. https://flink.apache.org/news/2015/03/13/peeking-into-Apache-Flinks-Engine-Room.html
  2. https://yq.aliyun.com/articles/259073
  3. https://www.weizhuannet.com/p-505743.html
  4. https://zhuanlan.zhihu.com/p/56597480

猜你喜欢

转载自blog.csdn.net/Fei20140908/article/details/108461986