目录

一 . 你在开发Flink任务时,有没有遇到过背压问题,你是如何排查的?

二. 如何处理生产环境中的数据倾斜问题?



一 . 你在开发Flink任务时,有没有遇到过背压问题,你是如何排查的?

1. 背压产生的原因

背压常常出现在大促或者一些热门活动等场景中, 在上面这类场景中, 短时间内流量陡增导致数据的堆积,系统整体的吞吐量无法提升。

2. 监控背压方法

可以通过 Flink Web UI 发现背压问题

Flink 的 TaskManager 会每隔 50 ms 触发一次反压状态监测,共监测 100 次,并将计算结果反馈给 JobManager,最后由 JobManager 进行计算反压的比例,然后进行展示。

这个比例的计算逻辑如下:

背压程度

指标范围

备注

HIGH

0.5 < Ratio <= 1

严重

LOW

0.10 < Ratio <= 0.5

一般

OK

0 <= Ratio <= 0.10

正常

3. 反压问题的定位与处理

Flink出现背压一般可以从下面三个方面进行问题定位

a. 数据倾斜

可以在 Flink 的后台管理页面看到每个 Task 处理数据的大小。当出现数据倾斜时,可以从页面上明显的看到一个或者多个节点处理的数据量远大于其他节点。这种情况一般是在使用KeyBy等分组聚合算子时,没有考虑到可能出现的热点Key。这种情况需要用户对导致倾斜的热点Key做预处理。

b. 垃圾回收机制(GC)

不合理的设置 TaskManager 的垃圾回收参数会导致严重的 GC 问题,可以通过 -XX:+PrintGCDetails 指令查看 GC 的日志。

c. 代码本身

用户因为未深入了解算子的实现机制而错误地使用了 Flink 算子,导致性能问题。我们可以通过查看运行机器节点的 CPU 和内存情况定位问题

二. 如何处理生产环境中的数据倾斜问题?

1. 产生数据倾斜的原因主要有 2 个方面

业务上有严重的数据热点,比如一个房产网站的浏览数据中北京上海等几个一线城市二手房浏览量远远超过其他地区。 技术上如果大量使用了 KeyBy、GroupBy 等操作,且没有对分组的Key做特殊的处理,会产生数据热点问题。

2. 解决问题的思路

业务上要尽量避免热点 key 的设计,例如我们可以把上海、北京等热点城市与非热点城市划分成不同的区域,并进行单独处理; 技术上出现热点时,要调整方案打散原来的 key,避免直接聚合;此外还可以利用Flink提供的功能来避免数据倾斜。

3. Flink 任务数据倾斜场景和解决方案

(1) 两阶段聚合解决 KeyBy 热点

a. 将需要分组的 key 打散,例如添加随机的后缀

b. 对打散后的数据进行聚合

c. 将被打散的 key 还原为原始的 key

d. 二次 KeyBy 来统计最终结果并输出给下游

具体代码如下所示:

DataStream sourceStream = ...;
resultStream = sourceStream
     .map(record -> {
        Record record = JSON.parseObject(record, Record.class);
        String type = record.getType();
        record.setType(type + "_" + new Random().nextInt(100));
        return record;
      })
      // 首次聚合
      .keyBy(0)
      .window(TumblingEventTimeWindows.of(Time.minutes(5)))
      .aggregate(new CountAggregate())
      .map(count -> {
        String key = count.getKey.substring(0, count.getKey.indexOf("_"));
        return RecordCount(key,count.getCount);
      })
      //进行二次聚合
      .keyBy(0)
      .process(new CountProcessFunction);
resultStream.sink(...) 
env.execute(...)

(2)GroupBy + Aggregation 分组聚合热点问题

如果是采用FlinkSQL的方式,则可以将FlinkSQL 嵌套成两层,里层通过随机打散 若干份(如100)的方式降低数据热点,(这个打散的方式可以根据业务灵活指定)。

select date,
       city_id,
       sum(pv) as pv
from(
  select
        date,
        city_id,
        floor(rand() * 100),
        sum(count) as pv
  from kafka_table
        group by
        date,
        city_id,
        floor(rand() * 100) --随机打散为100份  
    )
    group by 
    date,
    city_id;

(3)Flink 消费 Kafka 使用并行度与Kafka分区数不一致导致的数据倾斜

Flink 消费 Kafka 的数据时,是推荐消费并行度为Kafka分区数的1倍或者整数倍的 ,即 Flink Consumer 的并行度 = Kafka 的分区数 * n (n = 1, 2 ,3 ...)。