目录
1、通过添加随机前缀打散它们的分布,使得数据不会集中在几个 Task 中
2、调用分区方法 rebalance、rescale 操作,使数据分布均匀
4、聚合统计前,先进行预聚合,例如两阶段聚合(加盐局部聚合+去盐全局聚合)
1、通过添加随机前缀打散它们的分布,使得数据不会集中在几个 Task 中
Flink 对数据分布不均匀添加随机前缀的目的,是为了打散分布,减小数据的倾斜程度,提高计算性能。
实现方式很简单,可以通过 map
方法添加随机前缀。具体实现可以参考下面的示例代码:
DataStream<Tuple2<String, Integer>> keyedStream = // 从数据源中获取 KeyedStream
DataStream<Tuple2<String, Integer>> prefixStream = keyedStream
.map(new RichMapFunction<Tuple2<String, Integer>, Tuple2<String, Integer>>() {
private ValueState<Integer> prefixState;
@Override
public void open(Configuration parameters) throws Exception {
super.open(parameters);
ValueStateDescriptor<Integer> prefixDescriptor = new ValueStateDescriptor<>("prefix", Integer.class);
prefixState = getRuntimeContext().getState(prefixDescriptor);
}
@Override
public Tuple2<String, Integer> map(Tuple2<String, Integer> value) throws Exception {
// 生成随机前缀
int prefix = prefixState.value();
if (prefix == null) {
prefix = ThreadLocalRandom.current().nextInt();
prefixState.update(prefix);
}
// 在第一个字段前添加前缀
String prefixedKey = prefix + value.f0;
return new Tuple2<>(prefixedKey, value.f1);
}
});
在这个示例代码中,我们在 map
方法中定义了一个 ValueState
,用来保存随机前缀。在 map
函数中,我们先从 ValueState
中读取前缀,如果没有,则生成一个新的随机前缀并保存到 ValueState
中。然后,我们将前缀添加到第一个字段前面,得到一个新的 key,并将原来的 value 传递下去。这样,相同的 key 会得到不同的前缀,从而达到打散数据的效果。
接着,对于打散后的数据流,我们可以继续使用 Flink 提供的聚合算子进行计算。需要注意的是,由于添加了随机前缀,所以在进行聚合计算时,需要先将前缀截取掉,然后再在全局聚合的时候把它们合并起来。
Flink 对数据分布不均匀添加随机前缀的目的,是为了打散分布,减小数据的倾斜程度,提高计算性能。