Kafka数据去重

Kafka数据去重

前言

Kafka 数据重复可能发生在 生产(Producer)、传输(Broker)、消费(Consumer)等多个环节。


一、Kafka 数据重复的原因?

1.Producer 端

  • 未开启幂等性(Idempotence) → 可能导致 消息重复发送。
  • ack=1 或 ack=0 → 生产者收到确认前可能重试,造成数据重复。
  • 网络异常 / 超时 → 生产者认为消息未发送成功,重新发送。

2. Broker 端

  • 副本同步失败 → Leader 切换后,可能导致 消息重复。
  • 事务未正确提交 → Producer 事务回滚或重试,可能导致重复提交。

3. Consumer 端

  • 手动提交 Offset 失败 → 可能导致 重复消费。
  • Consumer 端宕机重启 → 消费进度回滚,可能导致 消息重复处理。

二、解决方案

1.Kafka 端:幂等性 + 事务 + ack=all

  • 生产者端:开启幂等性(Idempotence)
    Kafka Producer 默认不会去重,需要手动开启幂等性:
Properties props = new Properties();
props.put("bootstrap.servers", "localhost:9092");
props.put("acks", "all"); // 确保所有副本写入,避免数据丢失
props.put("enable.idempotence", "true"); // 开启幂等性
props.put("retries", Integer.MAX_VALUE); // 无限重试
  • 幂等性(Idempotence):Kafka 生产者会为每个消息生成 唯一序列号,Broker 端会去重 相同 Producer ID + 相同序列号 的消息。

  • 事务 + 幂等性:防止跨分区重复 如果 Producer 需要跨分区事务,单纯的幂等性不足,需要Kafka 事务:

props.put("transactional.id", "my-transactional-producer"); // 事务 ID
KafkaProducer<String, String> producer = new KafkaProducer<>(props);
producer.initTransactions();
  • 事务写入
try {
    producer.beginTransaction();
    producer.send(new ProducerRecord<>("topic1", "key1", "value1"));
    producer.send(new ProducerRecord<>("topic2", "key2", "value2"));
    producer.commitTransaction(); // 原子提交
} catch (Exception e) {
    producer.abortTransaction(); // 事务回滚
}

✅ 作用:防止部分成功、部分失败的情况,保证 Kafka Exactly Once 语义。

2.下游去重

如果 Kafka 侧仍有少量重复数据,下一层(Spark Streaming、Redis、Hive)可进行去重。
1️⃣ Spark Streaming 去重

import org.apache.spark.sql.expressions.Window
import org.apache.spark.sql.functions._

val df = spark.readStream.format("kafka").option("subscribe", "my-topic").load()

// 按照 id 进行去重,取最早的数据
val dedupedDF = df.withColumn("rank", row_number()
  .over(Window.partitionBy("id").orderBy("timestamp")))
  .filter(col("rank") === 1)

// 输出去重后的数据
dedupedDF.writeStream.format("console").start()

✅ 按 id 分组,取最新或最早的一条数据,防止重复。

2️⃣ Redis 去重
Kafka 消费时,可以将数据 ID 存入 Redis,并判断是否已存在:

if (!redis.sismember("processed_ids", messageId)) {
    redis.sadd("processed_ids", messageId);
    processMessage(message);
}

✅ 作用:利用 Redis Set 结构,保证相同 ID 数据不会被重复处理。
该处使用的url网络请求的数据。

3️⃣ Hive 数据仓库去重
在 DWD(Data Warehouse Detail)层去重,确保进入 DWS 层数据无重复:

SELECT id, data
FROM (
    SELECT id, data, row_number() OVER (PARTITION BY id ORDER BY timestamp DESC) AS rank
    FROM dwd_table
) t
WHERE rank = 1;

✅ 作用:按 id 分组,每个 id 只取最新一条,去除重复数据。

3. Kafka 数据去重方案对比

方案使用阶段作用使用场景缺点
Kafka 幂等性Producer 去除重复发送的消息日志采集、数据流仅限于Producer端
Kafka 事务Producer + Broker跨分区Exactly Once订单、金融数据性能开销较大
Spark Streaming 去重Consumer基于窗口去重实时分析需要额外计算资源
Redis去重Consumer存储 ID过滤重复低延迟业务占用 Redis 内存
Hive DWD 层去重数据仓库最终去重离线分析适用于 T+1 数据

4. 总结

✅ Kafka Producer

开启幂等性 (enable.idempotence=true),避免 Producer 端重复。
设置 acks=all,确保消息可靠写入。
使用事务 (transactional.id),防止跨分区重复。

✅ Kafka Consumer

设置 isolation.level=read_committed,避免读取未提交事务数据。
手动提交 Offset,确保处理完数据后再提交,防止重复消费。

✅ 下游去重

Spark Streaming 开窗去重。
Redis 记录已消费 ID。
Hive 数据仓库去重。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值