场景:
如果有1000万订单,和20万以上的商家。现在我需要计算每个商家的订单数量,所以我使用以下方法(见代码)。这是正确的吗?因为会有很多键,我不知道Flink是否会对里面的每个键进行尺寸标注,是否会导致OOM?
//商家 merchantId
orderStream.keyby(merchantId)
.reduce(new ReduceFunction<Integer>() {
@Override
public Integer reduce(Integer value1, Integer value2)
throws Exception {
return value1 + value2;
}
});
在这种情况下,Flink将维护一个Integer值作为托管的键控状态。因此,一旦看到每个商家的一个或多个订单,Flink的状态后端将拥有20多万家商家的数据。
Flink具有高度的可伸缩性,因此拥有大量的键并不是问题。keyBy对流进行分区,这样每个任务管理器(worker)将只处理键的一个子集的事件。(这是一个分片的键/值存储。)此外,你可以选择一个基于堆的状态后端,将状态保存在内存中,或者在每个任务管理器上使用一个嵌入式RocksDB实例,将状态保存在每个任务管理器的本地磁盘上。
底线:200000个整数不是很状态。不用担心,即使只有一个任务管理器。
所以答案是可以的,上述问答是翻译自https://stackoverflow.com/questions/65609392/is-it-correct-to-use-flink-keyby-with-a-large-number-of-keys,供大家参考;
描述下我们具体实践的场景:
- 我们是在建设数仓模型dws聚合层的时候,做了keyby 维度+事件时间(分钟)+基于processtime开窗计算pv这样的计算逻辑;
- 因为是曝光,我们的聚合后的数据量级在1000w/min,与此同时我们的服务器配置如下:
topic 是160Partition2Replica,kafka带宽20M/S;flink job资源160C/700G;checkpoint 1min一次; backend FsStateBackend; - 平时正常流量checkpoint情况:耗时2s钟,state size 2MB左右,Buffered During Alignment 0B;
- 活动流量高峰时checkpoint情况:最高耗时1m 36s,state size 30 GB左右,Buffered During Alignment 1.04 GB;
- 在这时交代下我们是开启kafka事务的,端到端精准一次生产消费;
- 我们在压测的时候遇到过如下问题:
a) sink算子导致反压,我们进行了写入topic分区的增加;
b)内存使用率过高,甚至出现过oom,进行过cpu/memory配比的调整 从1:2调整到1:4;
c)生产端限速,导致checkpoint,写入速度慢,反压,甚至是checkpoint失败。我们进行了 生产提速;参考我的另外一个文章:https://blog.csdn.net/qq_31451711/article/details/122672955
由于我们开启事务以及开窗的原因,在数据积压时,会呈现梯形状递增;
还请各位大佬多多指教!