一个啤酒肚,穿着格子衬衫,发际线严重后退的中年男人,手里拿着保温瓶,下着MacBook,正向你走来手臂。师级别。采访开始,开门见山。面试官:我在你的简历上看到,项目中使用了消息队列,也使用了Kafka。你遇到过消息队列丢失消息的情况吗?我:【提问】消息队列还能丢消息吗?那谁还在用消息队列呢!你错了吗?没有遇到过消息丢失的情况,也没有想过。面试官:嗯,小伙子,看来有些面试套路你还是不太明白。今天就来这里面试吧!把简历给我,我送你下楼。我去!面试还有什么可做的?能不能少点套路,多点真诚!八股作文一定要背熟才能参加面试吗?好吧,让我看看一登总结的八股面试作文。我:消息队列发送和消费消息的过程分为三个部分,生产过程、服务器持久化过程、消费过程,如下图所示。所有三个进程都有可能丢失消息。面试官:嗯,具体是什么原因导致消息丢失?如何防止丢失消息?我:具体说一下这种情况:1、制作过程中消息丢失的原因:一般可能是网络故障,导致消息发送不出去。解决方法:重新发送即可。由于kafka为了提高性能采用了异步发送消息。只有拿到发送结果,才能保证消息发送成功。获取发送结果有两种方案。一是kafka将发送结果封装在一个Future对象中,我可以使用Future的get方法阻塞同步获取结果。未来future=producer.send(newProducerRecord<>(topic,message));try{RecordMetadatarecordMetadata=future.get();if(recordMetadata!=null){System.out.println("发送成功");}}catch(Exceptione){e.printStackTrace();}另一种是利用kafka的回调函数获取返回结果。producer.send(newProducerRecord<>(topic,message),newCallback(){@OverridepublicvoidonCompletion(RecordMetadatametadata,Exceptionexception){if(exception==null){System.out.println("发送成功");}else{System.out.println("发送失败");}}});如果发送失败,有两种重试方案:在catch逻辑中手动重试或者else逻辑,再次调用send方法。如果不成功怎么办?在数据库中建一个异常消息表,表中存放失败消息,然后设置异步任务重试,方便控制重试次数和间隔时间。自动重试Kafka支持自动重试。设置参数如下。当集群的leader选举或者Follower数量不足返回失败时,可以自动重试。#设置重试次数为3retries=3#设置重试间隔为100ms2.服务器持久化过程中消息丢失。Kafka为了保证性能,采用了异步flushing。当我们发送消息成功后,Broker节点在flush之前宕机了,会导致消息丢失。当然我们也可以设置磁盘刷新频率:#设置每1000条消息刷新一次flush.messages=1000#设置每秒刷新一次flush.ms=1000首先科普一下Kafka集群的架构模型:Kafka集群由多个broker组成,经纪人是一个节点(机器)。一个topic有多个partition,每个partition分布在不同的broker上,可以充分利用分布式机器的性能,扩容时只需要增加机器和分区即可。一个分区有多个副本(副本),一个领导者副本(主副本)和多个跟随者副本(从副本),旨在确保数据安全。发送和消费消息都在leader上,follower负责定时从leader处拉取消息。只有follower从leader那里拉回消息,producer才能成功发送消息。为了加快持久化消息的性能,Kafka将性能较好的follower组成一个ISR列表(in-syncreplica),将性能较差的follower组成一个OSR列表(out-of-syncreplica),ISR+OSR=AR(分配的副本)。如果一个follower在一段时间内没有从leader那里拉取消息,并且落后leader太多,就会被从ISR中移除,放到OSR中。如果跟随者追上领导者,它将被放回ISR。如果leader挂了,会从ISR中选出一个follower作为leader。为了提高持久化消息的性能,我们可以做一些设置:#如果follower超过一秒没有从leader拉取消息,将其从ISR列表中移除rerplica.lag.time.max.ms=1000#如果follower落后leader一千条消息,将其移出ISR列表rerplica.lag.max.messages=1000#确保ISR中至少有3个followermin.insync.replicas=3#异步消息不需要leader确认,立即成功返回sender给producer。丢失消息的可能性很高。asks=0#leader将消息写入本地log,不会等待所有follower确认,然后返回给producer消息发送成功。丢失消息的可能性很小。返回给生产者发送成功,消息不会丢失。asks=-1orasks=all3.消费进程丢失消息。Kafka中有一个offset的概念。消费者从分区中拉取消息,本地处理完成后消费者需要提交偏移量,表示消费完成,下次不再取这条消息。所以我们需要关闭automaticcommitoffset的配置,防止消费者拉取消息后服务宕机,导致消息丢失。enable.auto.commit=false面试官:还是得是你。就你的总结而言,我认为它不是那么完整。明天来上班,工资翻倍。本文知识点总结:文章持续更新中,大家可以在微信搜索“一光架构”第一时间阅读更多技术干货。