订阅更新

某个Partition消息量是其他的10倍——Kafka数据倾斜怎么解决?

Kafka手册 第 13 题 约 7 分钟读完

本文目录
  1. 先说结论
  2. 为什么会倾斜?——Key分区机制
  3. 怎么发现倾斜?
  4. 解法一:打散热点Key(最常用)
  5. 解法二:过滤无效数据(治本之道)
  6. 解法三:自定义分区策略
  7. 三种解法对比
  8. 面试高频追问
  9. 总结

先说结论

Kafka数据倾斜的根因是:某些Key的消息量远大于其他Key,而这些热点Key集中在同一个Partition。解决思路有三种:打散热点Key、过滤无效数据、自定义分区策略。

先把这段讲顺;面试官追问时,再展开下面的原理和细节。

详细讲解

数据倾斜不只是Spark和Flink的问题,Kafka也会有。在某知名出海硬件品牌做数据平台时,有一个设备事件的Topic,某个测试设备的device_id占了整个Topic 30%的数据量,导致对应的Partition消息量是其他Partition的10倍。下游Flink只有这个并行度在疯狂工作,其他并行度几乎空闲,整体消费效率极低。

为什么会倾斜?——Key分区机制

Kafka的默认分区策略:有Key的消息按hash(Key) % partitionNum分配Partition。如果某个Key的消息量特别大,它的所有消息都进同一个Partition,就造成了倾斜。

# 数据倾斜的典型场景
#
# 场景一:热点用户/设备
#   某测试设备device_id占30%的事件数据
#   hash(device_id) % 6 = 3 → 全部进Partition-3
#   Partition-3消息量是其他Partition的10倍
#
# 场景二:NULL Key
#   部分消息没有Key → 轮询分配
#   部分消息有Key → Hash分配
#   没问题,但如果NULL Key的消息也需要有序处理就麻烦了
#
# 场景三:Key分布不均
#   按国家做Key,美国占60%数据 → 美国所在Partition压力巨大

怎么发现倾斜?

# 用kafka-consumer-groups查看每个Partition的Lag
kafka-consumer-groups.sh --bootstrap-server broker1:9092 \
    --describe --group flink-device-event
 
# 如果某个Partition的Lag远大于其他 → 大概率倾斜
# PARTITION  CURRENT-OFFSET  LOG-END-OFFSET  LAG
# 0          1000000         1020000         20000   ← 正常
# 1          990000          1010000         20000   ← 正常
# 2          980000          1005000         25000   ← 正常
# 3          800000          1200000         400000  ← 倾斜!消息量是其他10倍
# 4          995000          1015000         20000   ← 正常
# 5          1000000         1018000         18000   ← 正常
 
# 进一步确认:看Partition-3的消息速率
# Know Streaming上可以直接看每个Partition的Bytes In Rate

解法一:打散热点Key(最常用)

在Producer端给热点Key加随机后缀,把消息分散到多个Partition:

// 打散热点Key
String originalKey = deviceId;  // 比如 "test-device-001"
 
// 判断是否是热点Key(可以维护一个热点Key列表)
if (hotKeys.contains(originalKey)) {
    // 加随机后缀打散到4个Partition
    String scatteredKey = originalKey + "_" + random.nextInt(4);
    producer.send(new ProducerRecord<>(topic, scatteredKey, value));
} else {
    producer.send(new ProducerRecord<>(topic, originalKey, value));
}
 
// 打散后:test-device-001_0, test-device-001_1, ...
// 分散到4个不同的Partition
// 但注意:同一个device_id的消息不再保证有序!
// 如果需要有序 → 用解法三(自定义分区器)

适用场景:热点Key的消息不需要严格有序,只需要减轻倾斜。比如测试设备的事件、爬虫行为日志等。

解法二:过滤无效数据(治本之道)

很多时候倾斜是因为无效数据。我在出海硬件品牌遇到的就是这种情况——某个测试设备占30%数据量,这些数据对分析完全没用。

// 在Producer端直接过滤无效数据,不让它进Kafka
if (isTestDevice(deviceId)) {
    // 测试设备数据直接丢弃或写入专门的测试Topic
    producer.send(new ProducerRecord<>("device_event_test", deviceId, value));
    return;  // 不写入正式Topic
}
producer.send(new ProducerRecord<>("device_event", deviceId, value));
 
// 好处:
// ① 正式Topic不再有倾斜问题
// ② 减少30%的消息量 → 节省存储和带宽
// ③ 测试数据有独立通道,不影响正式数据

在出海硬件品牌,这个优化效果非常明显:过滤掉测试设备后,Flink对应的处理任务从40分钟降到了8分钟。当然这个数字不只是Kafka层面的优化,AQE也帮了忙,但源头过滤是最根本的解决方案。

解法三:自定义分区策略

// 自定义Partitioner:热点Key特殊处理
public class SmartPartitioner implements Partitioner {
    @Override
    public int partition(String topic, Object key, byte[] keyBytes,
                         Object value, byte[] valueBytes, Cluster cluster) {
        int numPartitions = cluster.partitionCountForTopic(topic);
        if (key == null) {
            return ThreadLocalRandom.current().nextInt(numPartitions);
        }
        String keyStr = (String) key;
        // 热点Key分散到前一半Partition
        if (hotKeys.contains(keyStr)) {
            return Math.abs(keyStr.hashCode()) % (numPartitions / 2);
        }
        // 普通Key分配到后一半Partition
        return (numPartitions / 2) +
               Math.abs(keyStr.hashCode()) % (numPartitions / 2);
    }
}

适用场景:热点Key需要保持有序但要控制倾斜程度。把热点Key限定在一部分Partition中,给这些Partition配更多的Consumer资源。

三种解法对比

解法原理优点缺点
打散热点Key加随机后缀分散简单有效热点Key不再有序
过滤无效数据源头不让脏数据进入治本不适用于有效热点数据
自定义Partitioner热点Key特殊分配灵活可控开发维护复杂

面试高频追问

追问一:Kafka倾斜和Spark/Flink倾斜有什么关系?

Kafka的倾斜会直接传导到下游。Kafka某个Partition数据量大 → Flink消费这个Partition的SubTask数据量大 → 这个SubTask处理慢、反压 → 整体消费延迟。所以在Kafka层面解决倾斜,等于在源头解决了下游的倾斜问题。

追问二:怎么动态识别热点Key?

两种方式:① 离线统计:定期分析Kafka消息的Key分布,找出占比超过某个阈值(比如10%)的Key加入热点列表;② 实时检测:在Producer端维护一个滑动窗口计数器,某个Key在窗口内超过阈值就自动打散。

总结

Kafka数据倾斜面试答清楚三点:① 怎么发现(看Partition的Lag分布或消息速率);② 根因(热点Key集中在同一个Partition);③ 三种解法(打散Key、过滤无效数据、自定义分区器)。能讲出真实的倾斜案例和解决过程,面试官会觉得你有端到端的数据链路思维。

下一篇聊一个经典对比题:Kafka vs RocketMQ vs Pulsar,为什么大数据场景几乎都选Kafka?

你们遇到过Kafka数据倾斜吗?用什么方法解决的?评论区聊聊~

关注「Wood聊大数据」| 9年大数据老兵,聊技术、聊职场、聊成长

刷题进度保存在当前浏览器