数据交换策略(Data Exchange Strategy)定义了数据如何被分配到物理数据流图的 Task 中的。数据交换策略可以由执行引擎根据算子的语义自动选择,也可以由数据流程序显式施加。因此,我们简要回顾下常见的几种数据交换策略:
分区转换对应于数据交换策略。该操作定义了事件如何被分配到 Task。当使用 DataStream API 构建应用程序时,系统自动地选择数据分区策略,并依据操作语义和配置的并发度将数据路由到正确的 Task。有时有必要在应用程序层面控制分区策略,或者自定义分区器。例如,如果我们已经知道 DataStream 的并行分区的负载是倾斜的,我们可能希望重新平衡数据,以便均匀地分配后续操作符的计算负载。或者,应用程序逻辑要求执行的所有 Task 都接收相同的数据,又或者要求事件按照自定义的策略分布。在本节中,我们将展示用户可以操作的 DataStream 方法或者定义他们自己的方法。
注意:KeyBy() 和本节讨论的分区转换是不同的。本节讨论的转换都会产生一个 DataStream,而 KeyBy() 产生的是 KeyedStream,并可以在它上应用访问 Keyed-state 的转换。
Random 数据交换策略通过 DataStream.shuffle() 实现。该方法按照均匀分配的原则,随机地将数据分配到下游算子的并行 Task 中。
rebalance() 方法对输入流进行分区,以便以 Round-Robin 方式将事件均匀地分配到下下游 Task。
rescale() 也以 Round-Robin 的方式分配数据,但是它只分配给下游 Task 的子集。本质上,当发送者和接收者的 Task 数量不同时,Rescale 策略提供了一种执行轻量级负载重新均衡的方式。如果接收者的 Task 数量是发送者的 Task 数量的倍数,则 Rescale 转换会更有效,反之亦然。
rebalance() 和 rescale() 本质的不同在于 Task 的连接方式上。rebalance() 在所有发送 Task 和接收 Task 间创建通信通道,而 rescale() 仅仅创建从每个 Task 到下游算子的某些 Task 通信通道。
broadcast() 复制输入数据流,为了将所有数据发送到下游算子的所有并行的 Task 上。
globa() 发送所有输入数据流到下游算子的第一个并行 Task。该分区策略必须谨慎使用,因为将所有数据路由到同一个 Task 可能会影响应用程序性能。
当预定义的分区策略没有一个适合使用时,你可以使用 partitionCustom() 定义自己的策略。该方法接收一个 Partitioner 对象,该对象实现分区逻辑和在被分区流上的字段或键的位置。