Kafka如何保证无消息丢失
Kafka 只对“已提交”的消息(committed message)做有限度的持久化保证。
已提交
Broker 成功地接收到一条消息并写入到日志文件后,它们会告诉生产者程序这条消息已成功提交。此时,这条消息在 Kafka 看来就正式变为“已提交”消息了。
有限度的持久化保证
Kafka 不可能保证在任何情况下都做到不丢失消息。假如你的消息保存在 N 个 Kafka Broker 上,那么这个前提条件就是这 N 个 Broker 中至少有 1 个存活。只要这个条件成立,Kafka 就能保证你的这条消息永远不会丢失。
最佳实践
- 不要使用 producer.send(msg),而要使用 producer.send(msg, callback)。记住,一定要使用带有回调通知的 send 方法。
- 设置
acks = all
。acks 是 Producer 的一个参数,代表了你对“已提交”消息的定义。如果设置成 all,则表明所有副本 Broker 都要接收到消息,该消息才算是“已提交”。这是最高等级的“已提交”定义。默认值为1- acks=0:生产者不会等待来自服务器的任何确认。消息被视为发送成功,即使服务器没有收到它。
- acks=1:生产者在将消息发送到服务器后会等待服务器的确认。只需要领导者副本(leader replica)确认即可,而不需要等待其他副本的确认(默认值)。
- acks=all(或者 acks=-1):生产者将等待所有同步副本(包括领导者和所有 ISR 副本)确认。这种设置提供了最高级别的持久性保证。
- 设置 retries 为一个较大的值。这里的 retries 同样是 Producer 的参数,对应前面提到的 Producer 自动重试。当出现网络的瞬时抖动时,消息发送可能会失败,此时配置了 retries > 0 的 Producer 能够自动重试消息发送,避免消息丢失。
- 设置
unclean.leader.election.enable = false
。这是 Broker 端的参数,它控制的是哪些 Broker 有资格竞选分区的 Leader。如果一个 Broker 落后原先的 Leader 太多,那么它一旦成为新的 Leader,必然会造成消息的丢失。故一般都要将该参数设置成 false,即不允许这种情况的发生。 - 设置
replication.factor >= 3
。这也是 Broker 端的参数。其实这里想表述的是,最好将消息多保存几份,毕竟目前防止消息丢失的主要机制就是冗余。 - 设置
min.insync.replicas > 1
。这依然是 Broker 端参数,控制的是消息至少要被写入到多少个副本才算是“已提交”。设置成大于 1 可以提升消息持久性。在实际环境中千万不要使用默认值 1(min.insync.replicas只有在acks=-1)。 - 确保
replication.factor > min.insync.replicas
。如果两者相等,那么只要有一个副本挂机,整个分区就无法正常工作了。我们不仅要改善消息的持久性,防止数据丢失,还要在不降低可用性的基础上完成。推荐设置成replication.factor = min.insync.replicas + 1
。 - 确保消息消费完成再提交。Consumer 端有个参数 enable.auto.commit,最好把它设置成 false,并采用手动提交位移的方式。就像前面说的,这对于单 Consumer 多线程处理的场景而言是至关重要的。
acks与min.insync.replicas
当Producer将 acks 设置为“all”(或“-1”)时,min.insync.replicas
指定必须确认写入的最小副本数,写入才会被视为成功。如果无法满足此最小值,则创建者将引发异常(NotEnoughReplicas 或 NotEnoughReplicasAfterAppend)。
一起使用时,min.insync.replicas
和 acks
允许您强制执行更高的持久性保证。典型的方案是创建一个复制因子为 3 的主题,将 min.insync.replicas 设置为 2,并使用 “all” 的 acks 进行生成。这将确保在大多数副本未收到写入时,生产者会引发异常。
acks与min.insync.replicas、ISR联系
- 如果设置了
acks=all
,那么生产者会等待所有ISR中的副本确认消息被写入。 min.insync.replicas
参数确定了需要有多少个ISR中的副本必须成功写入消息。假如ISR中的副本数少于min.insync.replicas
,生产者会接收到一个异常,并且消息不会被认为已成功发送。- 通过调整
min.insync.replicas
和acks
,可以在性能和可靠性之间找到平衡。较高的min.insync.replicas
值和acks=all
设置可以保证更高的数据可靠性,但也会影响写入性能。
本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来源 二九的博客!