Kafka进阶系列--消息异常

其他网址

平台搭建---Kafka使用---Kafka重复消费和丢失数据_diggerTT的博客-CSDN博客_kafka重复消费

消息丢失

生产者丢失消息

什么时候会丢失消息?

情景1:消息大小超过Broker的message.max.bytes的值。此时Broker会直接返回错误;

情景2:生产者发出消息后,网络突然中断了,导致消息没发到Broker

情景3:消息的格式错误;(此场景在开发自测时就应该排除)

解决方案

指定消息的大小(对应:情景3)

Producer的max.requests.size表示生产者发送的单个消息的最大值,也可以指单个请求中所有消息的总和大小。此值必须小于Broker的message.max.bytes。

异步发送、提供回调方法(对应:情景2)

结论:使用带回调的API,在发送失败时进行处理(比如存储到其他介质中在后边进行补偿)

详述:

生产中,我们会用Kafka生产者的异步发送,有如下两个API:

producer.send(msg) 不带回调方法
producer.send(msg,callback) 带回调方法

消息重试(对应:情景2)

  • 设置重试次数:retries          //经验值:3。
  • 设置重试间隔:retry.backoff.ms      //经验值:20000
    默认是1000,即1秒。
    设置此项,可以使其过段时间后再重试,这时网络可能已经好了。否则,重试若间隔太近,短时间网络还没好,会浪费了重试次数
    设置此项后,会导致消息顺序改变。保证顺序不变的方法:配置max.in.flight.requests.per.connection=1  (作用:限制客户端在单个连接上能够发送的未响应请求的个数。设为1表示kafka broker在响应请求之前client不能再向同一个broker发送请求。)
  • 设置重连间隔:reconnect.backoff.ms     //经验值:20000

响应个数(对应:情景2) 

结论

设置 acks = all

详述

acks这个参数有三个值:0,1,-1(all)。

acks 是 Producer 的一个参数,代表了你对“已提交”消息的定义。

  • 0:生产者只要把消息发送出去以后就认为消息发送成功了。
    可能会导致数据丢失:网络挂了、broker保存消息失败
  • 1:生产者把消息发送到服务端,服务端的leader replica 副本写成功以后,就返回生产者消息发送成功了。
    可能会导致丢数据:有可能刚好数据写入到leader replica,然后返回处理成功的响应给生产者,假如这个时候leader replica在的服务器出问题了,follower replica还没来得及同步数据,这时会丢数据。
  • all:所有replica 都写入成功以后,才会返回成功响应给生产者。
    假设有该分区的三个replica(一个leader replica,两个follower replica),那么acks=-1就意味着消息要写入到leader replica,并且两个follower replica从leader replica上同步数据成功,服务端才会给生产者发送消息发送成功的响应。 想要保证数据不丢,那么acks的值设置为-1,并且还需要保证有1个以上的副本

发送延迟(对应:场景2) 

结论

设置linger.ms。  //经验值:50。默认值:0

详述

此设置可以延迟生产者发送消息,从而一定程度上减少碰到网络问题的可能。

详见:https://kafka.apachecn.org/documentation.html

broker丢失消息

什么时候会丢失消息?

情景1:假如 leader 副本所在的 broker 突然挂掉,那么就要从 follower 副本重新选出一个 leader ,但是 leader 的数据还有一些没有被 follower 副本的同步的话,就会造成消息丢失。

说明:Kafka 为分区(Partition)引入了多副本(Replica)机制。分区(Partition)中的多个副本之间会有一个叫做 leader 的家伙,其他副本称为 follower。我们发送的消息会被发送到 leader 副本,然后 follower 副本才能从 leader 副本中拉取消息进行同步。生产者和消费者只与 leader 副本交互。你可以理解为其他副本只是 leader 副本的拷贝,它们的存在只是为了保证消息存储的安全性。

解决方案

leader竞选资格

结论

设置unclean.leader.election.enable为false

详解

这个参数控制leader replica出问题了以后follower replica竞选leader replica资格。

设置为false,意思就是如果follower replica如果落后leader replica太多就不能参与竞选。

副本的个数

结论

设置replication.factor为大于1的数  //经验值:3

详解

这个参数设置的是partition副本的个数,如果我们要想保证数据不丢,这个副本数需要设置成大于1。

最小的副本数 

结论

设置min.insync.replicas为大于1的数,且要小于replication.factor

详解

  • min.insync.replicas大于1
    这参数要跟生产者里的acks参数配合使用,当生产者acks=all时,服务端所有副本都写入成功,才会给生产者返回成功的响应。
    min.insync.replicas就是控制消息至少要被写入到多少个副本才算是“已提交”。假设min.insync.replicas=1,则表示可只有一个副本,这副本就是leader replica,这时即使acks设为all,但其实消息只发送到leader replica,以后就返回成功的响应了。
  • min.insync.replicas小于replication.factor
    为了保证整个 Kafka 服务的高可用,需确保 replication.factor > min.insync.replicas 。为什么呢?假如两者相等,只要有一个副本挂掉,整个分区就无法正常工作,这明显违反高可用!一般推荐设置成 replication.factor = min.insync.replicas + 1。

消费者丢失消息

什么时候会丢失消息?

情景1:先提交偏移量,后处理消息,当消息处理失败时,该消息丢失。

先处理消息,后提交偏移量,当提交偏移量失败时,该消息会重复。消息重复只需处理幂等即可,消息重复不是本文关注的内容。

解决方案

手动提交offset

结论

设置enable.auto.commit为false,处理消息之后,手动提交,提交方法有如下几种:

  1. 异步提交
    consumer.commitAsync()、consumer.commitAsync(new OffsetCommitCallBack())
  2. 同步提交
    consumer.commitSync()

详解

同步提交会一直重试直到成功,需要Broker的响应,而异步提交能够提高吞吐量。

消息零丢失的配置

如果上述所有情况都做到了,即可以做到消息零丢失。

总览很多博客,做到上边的配置后,在生产中已经可以消息零丢失了。

下边这些情况也会导致修饰消息,但可以忽略它

Kafka的数据首先是写到操作系统缓存的,假如我们用了上面的配置方案,数据写入成功了,还没落到磁盘,但是集群停电了,这个时候也是会丢数据的。如果配置其立马写入磁盘,则会降低吞吐量,一般不会这么配置。

消息重复

其他网址

kafka消息重复和丢失的场景及解决方案分析_zhangCheng的博客-CSDN博客
kafka笔记:生产者投递消息exactly once 精准一次性(幂等性解决消息重复投递)-云社区-华为云
Kafka的消息会丢失和重复吗?——如何实现Kafka精确传递一次语义
极简单系列-kafka 生产-重复问题_博学之,审问之,慎思之,明辨之,笃行之-CSDN博客

生产者消息重复

什么时候会重复?

情景1:生产发送的消息没有收到正确的broke响应,导致producer重试。

详解:producer发出一条消息,broker落盘以后,因为网络等原因,发送端得到一个发送失败的响应或者网络中断,然后producer收到 一个可恢复的Exception重试消息导致消息重复。

解决方案

启动kafka的幂等性

结论

enable.idempotence=true   //此时会默认开启acks=all
acks=all
retries>1

详解

kafka 0.11.0.0版本之后,正式推出了idempotent producer,支持生产者的幂等。

每个生产者producer都有一个唯一id,producer每发送一条数据都会带上一个sequence,当消息落盘,sequence就会递增1。只需判断当前消息的sequence是否大于当前最大sequence,大于就代表此条数据没有落盘过,可以正常消费;不大于就代表落盘过,这个时候重发的消息会被服务端拒掉从而避免消息重复。

局限性

        在初始化期间,kafka会给生产者生成一个唯一的ID称为Producer ID或PID。 PID和序列号与消息捆绑在一起,然后发送给Broker。由于序列号从零开始并且单调递增,因此,仅当消息的序列号比该PID / TopicPartition对中最后提交的消息正好大1时,Broker才会接受该消息。如果不是这种情况,则Broker认定是生产者重新发送该消息。 

消费者消息重复

什么时候会重复?

情景1:消费者使用自动动提交offset模式,消费者收到消息还没消费时,提交offset并开始消费消息,结果网络异常,offset提交失败、消费消息成功

情景2:消费者使用手动提交offset模式,消费者在消费了消息之后,消费者挂了,还未提交offset

解决方案1

业务代码中处理。

结论

设置为手动提交模式;手动判断幂等

详解

幂等实际上就两种方法:
(1)、将唯一键存入第三方介质,要操作数据的时候先判断第三方介质(数据库或者缓存)有没有这个唯一键。

(2)、将版本号(offset)存入到数据里面,然后再要操作数据的时候用这个版本号做乐观锁,当版本号大于原先的才能操作。

解决方案2

使用kafka的流处理引擎:Kafka Streams(此法用的很少)

结论

设置processing.guarantee=exactly_once,就可以轻松实现exactly once了。

猜你喜欢

转载自blog.csdn.net/feiying0canglang/article/details/113886464
今日推荐