xjjdog/interview-ng

【Kafka】使用Kafka,如何保证消息不丢?

Opened this issue · 3 comments

Kafka

思路

一般,MQ至少包含三个组成部分,Producer,Broker,Consumer。producer发送消息到broker,consumer消费存储在Broker的消息。producer到broker,broker到consumer,broker存储消息三个环节都有可能导致消息丢失。

Kafka

Producer

丢消息场景

1、Kafka消息发送都是异步进行,所以当我们调用API发送消息之后,消息并无法保证一定会被发送到Broker,如果此时进程退出,可能导致消息丢失。
2、Kafka发送消息过程中,也可能会由于Broker异常或网络原因导致消息发送失败,如果没有相应的重试策略,也会导致消息丢失。
3、Kafka发送消息到分片的主节点,如果主节点与从节点之间没有同步成功,主节点出故障也可能导致消息丢失。

解决方案:

1、控制Kafka向Broker提交消息的时间间隔和批次大小:

batch.size:kafka在发送消息之前会按分片聚合消息,批量提交,如果该值过大,则会导致大量消息得不到及时提交,增加了延迟也增加了消息丢失风险
linger.ms:默认为0,表示不开启此选项,默认情况下消息会立马被提交。但是如果该值大于0,当消息大小没有达到batch.size时,会等待linger.ms设置的时间,也增加了延迟和消息丢失风险。

2、设置重试策略,消息发送失败后重试。重试会有消息重复的可能。
1)自动重试:设置retries。当消息发送失败后,kafka将自动重试,直到超过retries设置的重试次数。
2)手动重试:实现API提供的回调,失败后重新发送。如果设置了retries自动重试,自动重试失败之后才会回调callback,所以两者不冲突。
3、设置ack策略。

ack=0,不需要等待ack,消息写入到socket缓冲区即认为成功
ack=1,只等待主节点的ack,主节点写入本地日志即认为成功
ack=all或-1, 等待当前topic的leader节点和所有in-sync follower节点都ack才算成功。

Broker本身

丢消息场景

1、topic没有设置副本
2、in-sync副本数过少
3、broker未能及时刷盘,由于文件写入并不会立即刷新到磁盘,具体刷盘时机依赖操作系统,所以Linux系统提供了fsync来实现强制刷盘,如果没有实时刷盘,也可能导致消息丢失。
4、某些没有在in-sync状态中的节点被选成了主节点,当主节点挂掉,重新选主的过程中,如果没有在ISR中的节点被选做主节点,可能会导致消息丢失。

解决方案

1、设置topic多副本:replication.factor
2、控制核心topic的in-sync副本数量:min.insync.replicas,保证当前集群中处于正常同步状态的副本 follower 数量,当实际值小于配置值时,集群停止服务。
3、控制核心topic的刷盘间隔:log.flush.interval.messageslog.flush.interval.ms
4、禁止不在ISR中的节点被选成主节点(全局生效,无法针对topic设置):unclean.leader.election.enable

Consumer

丢消息场景

1、自动提交offset,导致消息拉取到,没有消费成功就被标记为已消费。

解决方案

1、禁止自动提交

emmmmm,
持久化数据库作backup

对于Kafka,如果设置成ack=all,kafka性能将大幅下降,可以参考这里的一个压测数据.