Kafka 如何保证消息不丢失?【消息手动 ACK】

前言:

Kafka 作为一个 MQ 它肯定会有消息丢失的场景,那我们如何做到让 Kafka 的消息不丢失呢?本篇我们来剖析一下 Kafka 如何做到消息不丢失。

Kafka 系列文章传送门

Kafka 简介及核心概念讲解

Spring Boot 整合 Kafka 详解

Kafka @KafkaListener 注解的详解及使用

Kafka 客户端工具使用分享【offsetexplorer】

Kafka 之消息同步/异步发送

Kafka 之批量消息发送消费

Kafka 之消息广播消费

Kafka 之消息并发消费

Kafka 之顺序消息

Kafka 之事务消息

Kafka 如何保证消息不丢失?

Kafka 有生产者、Broker、Consumer,这三个环节都可能有消息丢失的情况发生,下面我们就从这三个方面来分析 Kafka 是如何保证消息不丢失的。

生产者:

生产者发送消息到 Kafka 集群的时候,可能会因为网络等其他原因导致发送失败,因此我们可以需要一个机制告诉我们消息是否发送成功,如果没有发送成功就一直发送,直到消息发送成功为止,我们常用的 send(msg) 方法其实是异步发送,发送完消息后会立即返回,我们并不知道消息是否发送成功,为了保证消息一定能够发送成功,建议使用同步发送 send(msg).get() 方法或者带有回调的 send(msg,callback) 方法。

同时我们可以对生产者增加一些配置来保证消息不丢失,配置如下:

#0:表示消息发送后立即返回 无需等待 Leader 的任何确认 1:表示消息写入了 Leader 副本 -1: 表示需要等到消息写入到所有 ISR 同步副本中
spring.kafka.producer.acks = 1
#生产消息发送的重试次数
spring.kafka.producer.retries = 3

spring.kafka.producer.acks 各个值的含义如下:

  • acks =0:表示生产者不需要等待任何 Broker 确认收到消息的回复,就可以继续发送下一条消息,性能最高,但是最容易丢消息,可以用在对性能要求很高,但对数据丢失不敏感的情况可以用这种。
  • acks =1:需要保证 Leader 已经成功将消息写入本地 文件,但是不需要等待所有 ISR副本(同步副本)是否成功写入,就可以继续发送下一条消息,这种情况下,如果 ISR副本(同步副本)没有成功备份数据,而此时 Leader又挂掉,则消息会丢失。
  • acks =-1:需要 Leader 及其所有的 ISR副本(同步副本)都成功写入日志,才可以继续发送下一条消息,这种策略会保证只要有一个副本存活就不会丢失数据,最大程度的保证了消息不会丢失。

Broker:

Broker 合理的使用持久化机制,ISR 副本同步机制可以最大程度的保证消息不丢失。

  • 持久化存储:Kafka 使用持久化来存储消息,让消息在写入 Kafka 的时候被写入磁盘,这种方式可以防止消息因为节点宕机而丢失。
  • ISR 副本复制机制:Kafka 使用 ISR 副本同步机制来保证消息不丢失,ISR 副本同步机制可以让一个分区有多个副本,且副本可以分布在不同的节点上,当某个节点宕机后,其他节点可以继续提供服务,保证消息不丢失。

消费者:

做为消费者只需要保证能够正确的消费消息,并正确的提交消息 offset 即可,Kafka 会记录每个消费者的偏移量,消费者每次消费消息的时候,都会将偏移量向后移动,当消费者挂掉或者 Kafka 宕机的时候,Kafka 会将该消费者的所消费的分区偏移量保存下来,当故障恢复后,消费者可以继续从上一次的偏移量开始消费,为了保证消息不丢失,我们使用手动提交偏移量即可,避免拉取了消息后,业务逻辑没有处理完的时候消费者挂掉了,但是提交了偏移量,导致消息丢失。

Consumer 需要关闭自动提交并开启手动提交,具体配置如下:

#消息 ACK 模式 有7种
spring.kafka.listener.ack-mode = manual
#是否开启手动提交 默认自动提交
spring.kafka.consumer.enable-auto-commit = false

Kafka 消息手动 ACK 案例演示

在演示 Kafka 手动 ACK 之前我们先了解一下 Kafka 的几种 ACK 的含义,也就是 AckMode 的枚举值的含义。

public static enum AckMode {
   
   
	RECORD,
	BATCH,
	TIME,
	COUNT,
	COUNT_TIME,
	MANUAL,
	MANUAL_IMMEDIATE;

	private AckMode() {
   
   
	}
}
  • RECORD:每一条记录被消费者消费之后提交。
  • BATCH:当每一批 poll() 的消息被消费者处理之后提交,频率取决于 poll 的调用频率,是 Kafka 的默认提交方式,BATCH 模式适用于需要提高处理效率的场景,例如批量处理大量消息
<think>嗯,用户问的是Redis的Pub/Sub模式如何保证消息不丢失。首先,我需要回忆一下Redis的Pub/Sub机制的基本工作原理。我记得Pub/Sub是发布订阅模式,生产者发送消息到频道,所有订阅该频道的消费者都会收到消息。但问题在于,如果消费者在消息发布时没有连接或者处理不过来,消息会不会丢失呢? 根据之前的知识,Redis的Pub/Sub是即时的,也就是说,消息一旦发布,Redis会立即发送给所有当前在线的订阅者。如果订阅者此时不在线,比如断开连接或者还没开始订阅,那么他们将无法接收到这条消息。这意味着默认情况下,Pub/Sub的消息是不持久化的,可能会丢失。 那用户的问题是如何保证消息不丢失呢?显然,标准的Pub/Sub可能无法满足这个需求。这时候可能需要引入其他机制。比如,使用Redis Streams,这是Redis 5.0引入的数据结构,专门用于处理消息队列,支持持久化存储、消费者组等功能。Streams可以确保消息在消费者离线时仍然保留,并在重新连接后继续处理。 或者,用户可能需要结合其他工具或方法,比如在应用层实现确认机制,或者使用持久化存储。但需要注意,这些方法可能不在Pub/Sub本身的特性范围内。另外,还可以提到使用RabbitMQKafka这样的专业消息队列系统,它们更适合需要高可靠性的场景。 用户可能是在设计一个需要高可靠性的消息系统,但目前使用的是Redis的Pub/Sub,所以想知道如何改进。或者他们可能遇到了消息丢失的问题,想了解解决方案。需要明确回答Pub/Sub本身的限制,并给出替代方案或补充措施。 总结回答的结构应该是:先说明Pub/Sub的局限性,再介绍替代方案如Redis Streams,最后可能比较其他消息队列系统。同时,按照用户示例,需要生成相关问题。</think>Redis的Pub/Sub模式本身**不保证消息持久化**,默认情况下消息仅在发布时实时传递给在线的订阅者。若消费者未连接或处理延迟,消息会丢失。若需可靠性,可通过以下方案实现: --- ### 1. **使用Redis Streams(推荐)** - Redis 5.0+ 引入的 **Streams** 是专为消息队列设计的持久化数据结构,支持: - **消息持久化**:消息存储在Redis中,即使消费者离线也不会丢失。 - **消费者组**:多个消费者可组成组内竞争消费,确保每条消息仅被消费一次。 - **ACK确认机制**:消费者处理完消息后需手动确认,未确认的消息会重新投递。 ```python # 生产者(添加消息到Stream) r.xadd('mystream', {'data': 'Hello Redis Streams'}) # 消费者(从Stream读取消息) messages = r.xread({'mystream': '0'}, count=1, block=0) for msg in messages[0][1]: print(f"处理消息: {msg[1]}") r.xack('mystream', 'mygroup', msg[0]) # 确认消息 ``` ### 2. **结合外部持久化存储** - 在应用层将消息写入数据库或日志系统(如MySQL、Kafka),再通过Redis Pub/Sub通知消费者拉取。 ### 3. **使用专业消息队列** - 若需高可靠性,可替换为 **RabbitMQ** 或 **Kafka**,它们天然支持消息持久化、重试机制等。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值