当前位置: 首页 > 科技观察

如果服务器宕机,Kafka消息会丢失吗?

时间:2023-03-22 00:50:12 科技观察

消息队列是高并发下必备的中间件,而Kafka作为其中的佼佼者,经常被我们用在各种场景中。伴随着Kafka,存在三个问题:消息丢失、消息重复、消息顺序。今天树哥就带大家说说消息丢失的问题。文章思维导图可靠性等级回到标题提出的问题:我们真的能保证Kafka消息不丢失吗?答案是:我们不能保证Kafka消息不会丢失,只能在一定程度上保证消息不会丢失。这里提到的一些情况,按严重程度依次为:Kafka宕机、服务器宕机、机房地震、城市毁灭、地球毁灭。不要以为舒哥是危言耸听。如果你的服务器部署在乌克兰首都,会不会遇到毁城的风险?因此,我们根据业务的重要性设置合理的可靠性等级。毕竟,可靠性等级越高,成本就越高。如果你的应用是金融或者国家级的应用,那么你需要考虑机房地震级以上的可靠性等级,否则一般考虑服务器宕机这个维度就够了。对于机房震级以上的情况,大多需要多做异地活动,然后做好各地机房数据的实时同步。就算地球毁灭了,你在火星上部署一个机房,原理也是类似的。我想大部分同学的应用可靠性可能只需要考虑服务器宕机的级别,所以后续的考虑也仅限于这个级别。从大局上看,如果Kafka想要让Kafka消息不丢失,那么我们就必须知道Kafka可能在什么地方丢失数据,所以了解Kafka消息流的全过程是非常重要的。对于Kafka来说,其整体架构可以分为三个部分:producer、Kafkaserver、consumer。其整体架构如下图所示。Kafka消息架构图生产者对于生产者来说,在向Kafka服务器发送消息的过程中可能会出现网络波动,导致消息丢失。对于这种可能存在的风险,我们可以通过适当设置Kafka客户端的request.required.acks参数来避免消息丢失。该参数表示生产者需要收到服务器的ack确认。当确认或超市收不到时,会抛出异常,以便生产者进一步处理。该参数可以设置不同级别的可靠性以满足不同业务的需要。参数设置及含义如下:request.required.acks=0表示Producer不等待Leader的ACK确认,直接发送下一条消息。在这种情况下,如果Leadershard所在的服务器宕机,已经发送的数据就会丢失。request.required.acks=1表示Producer等待Leader的ACK确认,收到确认后才发送下一条消息。在这种情况下,消息必须写入Leader服务器,但不保证Follow节点已经同步。因此,如果消息已经写入Leadershard,但还没有同步到Follower节点,Leadershard所在的服务器宕机,消息就会丢失,无法消费。request.required.acks=-1表示Producer在发送下一条消息之前等待Leader和所有Follower的ACK确认。在这种情况下,除非Leader节点和所有Follower节点都宕机,否则不会发生消息丢失。如上图,如果业务对可靠性要求高,可以将request.required.acks参数设置为-1,这样producer阶段就不会出现消息丢失的问题。Kafka服务器当Kafka服务器收到一条消息时,并不会直接写入磁盘,而是先写入内存。之后Kafka服务器会根据不同的设置参数选择不同的刷盘流程。这里有两个参数来控制刷盘过程:#当数据条数达到时Flushmessagestodisk#log.flush.interval.messages=10000#需要多长时间将累积的消息刷盘,任意一个达到指定值就会触发写入#log.flush.interval.ms=1000如果我们设置log.flush.interval.messages=1,那么每有一条消息过来,就会刷盘一次。这样可以降低消息丢失的概率,我们称之为同步闪现。相反,我们称之为异步刷机。同时Kafka服务器也会复制replica,Partition的Follower会从Leader节点拉取数据进行存储。然后将数据存储在Partition的Follower节点中。对于Kafka服务器来说,它会根据生产者设置的request.required.acks参数来选择何时回复ack给生产者。对于acks为0的情况,表示不等待Kafka服务器Leader节点的确认。对于acks为1的情况,表示等待Kafka服务器Leader节点的确认。对于acks为1的情况,表示等待Kafka服务器Leader节点和Follow节点的确认。但需要注意的是,Kafka服务器返回确认后,只是表示消息已经写入到Kafka服务器的PageCache中,并不代表已经写入磁盘。这时候如果Kafka所在的服务器掉电或者死机,消息也会丢失。而如果只有Kafka服务崩溃,那么消息是不会丢失的。所以,对于Kafka服务器来说,即使你设置了一次刷新一条消息,也有可能出现消息丢失,但是消息丢失的概率大大降低了。对于消费者来说,如果拉取消息后自动返回ack,但是消费者服务在处理过程中崩溃退出,那么消息就相当于丢失了。这种情况下,我们一般会采用业务处理完后手动提交ack的方式,避免消息丢失。在我们处理完业务后再提交ack的情况下,可能会出现重复处理消息的情况,即业务逻辑处理完了,但是提交ack的时候出现了异常。这就要求消费者在处理业务时处处进行幂等处理,避免业务重复处理。能不丢吗?根据我们上面的分析,Kafka只能做到Kafka应用崩溃的程度,因为Kafka的acks只是表示已经写入了PageCache。如果服务器宕机了,即使我们设置每条传入的消息都写入磁盘,那么服务器也可能在写入PageCache之后和写入磁盘之前的临界点宕机。这时候PageCache中的消息数据没有了,消息自然也就丢失了。但是如果只是Kafka应用崩溃退出,因为已经写入了PageCache,那么系统自然会把它写入磁盘,所以消息不会丢失。综上所述,消息可靠性的高低一定与业务的重要性有关。不能抛开业务本身的重要性谈可靠性,只能取一个平衡的值。根据我的经验,除非是金融或国家级别的应用,否则你只需要考虑服务器宕机的级别。而如果是金融级或者国家级的应用,那么就需要考虑城市破坏的可靠性水平。但是地球毁灭,我想没有人会去想。对于大多数应用,在考虑服务器宕机级别时,对于Kafka消息,只需要考虑以下几项:生产者。根据业务重要性,设置acks参数,做业务重试和告警记录。卡夫卡服务器。根据业务的重要性,设置闪烁参数即可。一般来说,没有必要设置为同步闪烁。消费者。使用手动提交acks的方式避免消息丢失,同时需要做幂等处理,避免重复处理。本文思维导图如下图。文章的思维导图准备好了,这就是今天的分享。