kafka对已提交的消息做有限度的持久化保证。
什么是已提交的消息
kakfa若干个broker成功收到一条消息并写入日志文件后,会告诉生产者程序这条消息已经成功提交。
什么是有限度
消息保留在N个broker上,至少要有一个存活
这里的数据丢失不一定是kafka的锅
调用的是 producer.send(msg) 这个 API,那么它会立即返回,不管发送的结果成功与否。原因很多,可能是网络抖动,消息根本没有到broker;可能是消息格式不正确,比如消息太大了broker无法处理。
解决办法是使用producer.send(msg, callback)这个API,对错误做针对性处理。如果是网络抖动会自动重试;如果是消息格式的问题,调整消息格式再发送。
补充
1.为什么将min.insync.replicas设置为大于1保证消息可用性,replication.factor > min.insync.replicas
kafka权威指南里的解释,生产者指定ack=all, 是要求同步副本也就是ISR(min.insync.replicas指定的就是最小同步副本个数),而不是分区的所有副本(replication.factor指定的是副本数目),都接收到消息,才算成功。
replication.factor是副本replica总数, min.insync.replicas是要求确保至少有多少个replica副本写入后才算是提交成功,这个参数是个硬指标;acks=all是个动态指标,确保当前能正常工作的replica副本都写入后才算是提交成功。举个例子:比如,此时副本总数3,即replication.factor = 3,设置min.insync.replicas=2,acks=all,那如果所有副本都正常工作,消息要都写入三个副本,才算提交成功,此时这个min.insync.replicas=2下限值不起作用。如果其中一个副本因为某些原因挂了,此时acks=all的动态约束就是写入两个副本即可,触达了min.insync.replicas=2这个下限约束。如果三个副本挂了两个,此时ack=all的约束就变成了1个副本,但是因为有min.insync.replicas=2这个下限约束,写入就会不成功。
2.什么是ISR
分区有多个副本,分为leader副本和follower副本,只有leader副本是工作的,读写请求都是走的leader副本,follower副本只是起备份作用
kafka是由follower周期性或者尝试去pull(拉)过来(其实这个过程与consumer消费过程非常相似)
leader会维护一个与其基本保持同步的Replica列表,该列表称为ISR(in-sync Replica),每个Partition都会有一个ISR,而且是由leader动态维护
3.kafka producer异步发送消息是怎么做的
kafka发送消息有同步和异步的方式,需要在效率和实效性做取舍,调用send方法发送实际上是把消息放到一个请求队列,后台发送线程读取队列的消息进行发送
https://blog.csdn.net/m0_45406092/article/details/119564881
https://zhuanlan.zhihu.com/p/427897970
4.kafka是在消息flush到磁盘、同步到副本后才能被消费吗
可能在刷盘之前就被消费了,能否被消费看的是leader副本的高水位是否超过了该消息。
如果此时消息消费了,但是刷盘失败了,消息就丢失了?有容错机制吗?
这个问题问的不太对,刷盘失败消息丢失是生产消息过程中可能发生的。如果在flush前机器宕机了,这条消息在这台broker确实丢失了,生产者的消息是否丢失取决于生产者配置的ack
https://cwiki.apache.org/confluence/display/KAFKA/KIP-101±+Alter+Replication+Protocol+to+use+Leader+Epoch+rather+than+High+Watermark+for+Truncation#KIP101AlterReplicationProtocoltouseLeaderEpochratherthanHighWatermarkforTruncation-LeaderEpoch
5.新增分区后导致消息丢失
如果配置了配置了auto.offset.reset=latest,可能会导致消息丢失,具体如下
broker新增分区后生产者先感知到,并将消息发送到新的分区;一段时间后消费者感知到了新分区,但是消费消息是从最新的消息开始消费,也就是会导致消息丢失。
所有的broker都挂了。这种情况消息并没有commit,符合开头提出的论点。
先更新位移,再消费消息,这种情况可能导致消息丢失。原因是消费者自动提交位移或者收到消息后先ack再处理消息,没有确认消息是否真正消费就盲目更新了位移。
解决办法是关掉消费者自动提交位移,程序手动提交位移。
还有一种情况是单consumer多线程消费
避免无消费消息丢失很简单,但极易出现消息被消费了多次的情况。
参考https://www.cnblogs.com/huxi2b/p/7089854.html