如何保证kafka消息可靠性

205 阅读2分钟

本文已参与 「新人创作礼」活动,一起开启掘金创作之路。

生产端:

  1. ack设置为-1, 等到消息完全从leader同步到follower副本,breaker在向prodecer发送ack。

  2. 同时为了保证 消息的发送和数据的入库 的一致性,我们需要将消息入库,先把消息id存到threadLocal里面,

消息入库和业务数据落盘后,也就是事务提交后,在进行消息的发送,实现数据源事务管理器接口(DataSourceTransactionManager)

执行消息发送,发送成功后删除,为了防止消息发送失败,可以使用定时任务或者人工检查。

ListenableFuture<SendResult<String, Object>> future = kafkaTemplate.send(topic, o); future.addCallback(result -> logger.info("生产者成功发送消息到topic:{} partition:{}的消息", result.getRecordMetadata().topic(), result.getRecordMetadata().partition()), ex -> logger.error("生产者发送消失败,原因:{}", ex.getMessage()));

broker端:

1.acks = -1或all

-1代表生产者向topic上的parttion发送的消息,当partion的leader和floweer都落盘后,才向生产者返回ack.

  1. replication.factor >= 3

为了保证 leader 副本能有 follower 副本能同步消息,我们一般会为 topic 设置 replication.factor >= 3。这样就可以保证每个 分区(partition) 至少有 3 个副本。虽然造成了数据冗余,但是带来了数据的安全性

  1. min.insync.replicas > 1

一般情况下我们还需要设置 min.insync.replicas> 1 ,这样配置代表消息至少要被写入到 2 个副本才算是被成功发送。min.insync.replicas 的默认值为 1 ,在实际生产中应尽量避免默认值 1。

消费端:

幂等性问题的产生? 服务端侧已经消费的数据没有成功提交 offset(根本原因)。

如何解决?

  • 消费消息服务做幂等校验,比如 Redis 的set、MySQL 的主键等天然的幂等功能。这种方法最有效。
  • 将enable.auto.commit 参数设置为 false,关闭自动提交,开发者在代码中手动提交 offset。那么这里会有个问题:
  • 什么时候提交offset合适?
    • 处理完消息再提交:依旧有消息重复消费的风险,和自动提交一样
    • 拉取到消息即提交:会有消息丢失的风险。允许消息延时的场景,一般会采用这种方式。然后,通过定时任务在业务不繁忙(比如凌晨)的时候做数据兜底。

消费者消费失败的问题,那么如果⼀直消费失败导致消息积压怎么处理?

消费者出错,肯定是程序或者其他问题导致的,如果容易修复,先把问题修复,让consumer恢复正常消费