更多内容,前往IT-BLOG

消息送达语义是消息系统中一个常见的问题,主要包含三种语义:
【1】At most once:消息发送或消费至多一次;
【2】At least once:消息发送或消费至少一次;
【3】Exactly once:消息恰好只发送一次或只消费一次;
下面分别从生产者消费者的角度来阐述这三种消息送达语义。

生产者 Producer

从 Producer的角度来看,At most once意味着 Producer发送完一条消息后,不会确认消息是否成功送达。这样从 Producer的角度来看,消息仅仅被发送一次,也就存在者丢失的可能性。

从 Producer的角度来看,At least once意味着 Producer发送完一条消息后,会确认消息是否发送成功。如果 Producer没有收到 Broker的 ack确认消息,那么会不断重试发送消息。这样就意味着消息可能被发送不止一次,也就存在这消息重复的可能性。

从 Producer的角度来看,Exactly once意味着 Producer消息的发送是幂等的。这意味着不论消息重发多少遍,最终 Broker上记录的只有一条不重复的数据。

Producer At least once配置

Kafka默认的 Producer消息送达语义就是 At least once,这意味着我们不用做任何配置就能够实现 At least once消息语义。原因是 Kafka中默认 acks=1并且 retries=2147483647。

acks 机制:broker 表示发来的数据已确认接收无误,表示数据已经保存到磁盘。
0:不等待 broker 返回确认消息
1:等待 topic 中某个 partition leader 保存成功的状态反馈
-1/all:等待 topic 中某个 partition 所有副本都保存成功的状态反馈

Producer At most once配置

我们可以通过配置 Producer的以下配置项来实现 At most once语义:acks=0 && retries=0

当配置了retires的值后,如果没有将 max.in.flight.requests.per.connection配置的值设置为1,有可能造成消息乱序的结果。max.in.flight.requests.per.connection配置代表着一个 Producer同时可以发送的未收到确认的消息数量。如果max.in.flight.requests.per.connection数量大于1,那么可能发送了message1后,在没有收到确认前就发送了message2,此时 message1发送失败后触发重试,而 message2直接发送成功,就造成了Broker上消息的乱序。max.in.flight.requests.per.connection的默认值为5。

Producer Exactly once配置

Exactly once是 Kafka从版本0.11之后提供的高级特性。我们可以通过配置 Producer的以下配置项来实现 Exactly once语义:
【1】enable.idempotence=true。enable.idempotence配置项表示是否使用幂等性。当 enable.idempotence配置为 true时,acks必须配置为all。并且建议 max.in.flight.requests.per.connection的值小于5。
【2】acks=all。enable.idempotence 配置项表示是否使用幂等性。当 enable.idempotence配置为 true时,acks必须配置为all。并且建议max.in.flight.requests.per.connection 的值小于 5。

Kafka如何实现消息发送幂等性

Kafka本身支持 At least once消息送达语义,因此实现消息发送的幂等关键是要实现 Broker端消息的去重。为了实现消息发送的幂等性,Kafka引入了两个新的概念:
【1】PID:每个新的 Producer在初始化的时候会被分配一个唯一的PID,这个 PID对用户是不可见的;
【2】Sequence Numbler:对于每个PID,该 Producer发送数据的每个<Topic, Partition>都对应一个从0开始单调递增的Sequence Number;

Broker端在内存中保存了这 Sequence Numbler,对于接收的每条消息,如果其序列号的值(SN_new)比 Broker端中维护的对应的序列号的值(SN_old)大1(即SN_new = SN_old + 1)时,Broker才会接收它,否则将其丢弃。这样就可以实现了消息重复提交了。但是,只能保证单个 Producer对于同一个 <Topic, Partition>的 Exactly Once语义。不能保证同一个Producer一个 Topic不同的 Partion幂等。

Kafka幂等性配置时要求 max.in.flight.requests.per.connection 小于等于 5 的主要原因是:Server 端的 ProducerStateManager 实例会缓存每个 PID 在每个 Topic-Partition 上发送的最近 5 个 batch 数据(这个 5 是写死的,至于为什么是 5,可能跟经验有关,当不设置幂等性时,当这个设置为 5 时,性能相对来说较高,社区是有一个相关测试文档),如果超过 5,ProducerStateManager 就会将最旧的 batch 数据清除。假设应用将 MAX_IN_FLIGHT_REQUESTS_PER_CONNECTION 设置为 6,假设发送的请求顺序是 1、2、3、4、5、6,这时候 server 端只能缓存 2、3、4、5、6 请求对应的 batch 数据,这时候假设请求 1 发送失败,需要重试,当重试的请求发送过来后,首先先检查是否为重复的 batch,这时候检查的结果是否,之后会开始 check 其 sequence number 值,这时候只会返回一个 OutOfOrderSequenceException 异常,client 在收到这个异常后,会再次进行重试,直到超过最大重试次数或者超时,这样不但会影响 Producer 性能,还可能给 Server 带来压力(相当于client 狂发错误请求)。

消费者 Consumer

从 Consumer的角度来看,At most once 意味着 Consumer对一条消息最多消费一次,因此有可能存在消息消费失败依旧提交offset的情况。考虑下面的情况:Consumer首先读取消息,然后提交 offset,最后处理这条消息。在处理消息时,Consumer宕机了,此时 offset已经提交,下一次读取消息时读到的是下一条消息了,这就是 At most once消费。

从Consumer的角度来看,At least once意味着 Consumer对一条消息可能消费多次。考虑下面的情况:Consumer首先读取消息,然后处理这条消息,最后提交offset。在处理消息时成功后,Consumer宕机了,此时 offset还未提交,下一次读取消息时依旧是这条消息,那么处理消息的逻辑又将被执行一遍,这就是 At least once消费。

从Consumer的角度来看,Exactly once意味着消息的消费处理逻辑和offset的提交是原子性的,即消息消费成功后 offset改变,消息消费失败 offset也能回滚

Consumer At least once配置

【1】enable.auto.commit=false:禁止后台自动提交offset;
【2】手动调用 consumer.commitSync()来提交offset。手动调用保证了 offset即时更新;
通过手动提交offset,就可以实现 Consumer At least once语义。

Consumer At most once配置

【1】enable.auto.commit=true:后台定时提交offset;
【2】auto.commit.interval.ms:配置为一个很小的数值。auto.commit.interval.ms表示后台提交 offset的时间间隔。
通过自动提交offset,并且将定时提交时间间隔设置的很小,就可以实现 Consumer At most once语义。

Consumer Exactly once配置

isolation.level=read_committed:isolation.level表示何种类型的 message对 Consumer可见:一个常见的 Exactly once的的使用场景是:当我们订阅了一个Topic,然后往另一个 Topic里写入数据时,我们希望这两个操作是原子性的,即如果写入消息失败,那么我们希望读取消息的 offset可以回滚。

此时可以通过 Kafka的 Transaction特性来实现。Kafka是在版本0.11之后开始提供事务特性的。我们可以将 Consumer读取数据和Producer写入数据放进一个同一个事务中,在事务没有成功结束前,所有的这个事务中包含的消息都被标记为 uncommitted。只有事务执行成功后,所有的消息才会被标记为 committed。

我们知道,offset信息是以消息的方式存储在 Broker的 __consumer_offsets topic中的。因此在事务开始后,Consumer读取消息后,所有的 offset消息都是uncommitted状态。所有的 Producer写入的消息也都是 uncommitted状态。

而 Consumer可以通过配置 isolation.level来决定 uncommitted状态的 message是否对 Consumer可见。isolation.level拥有两个可选值:read_committedread_uncommitted。默认值为 read_uncommitted。当我们将 isolation.level配置为 read_committed后,那么所有事务未提交的数据就都对 Consumer不可见了,也就实现了 Kafka的事务语义。

Kafka 消息送达语义的更多相关文章

  1. Kafka消息时间戳(kafka message timestamp)

    最近碰到了消息时间戳的问题,于是花了一些功夫研究了一下,特此记录一下.   Kafka消息的时间戳 在消息中增加了一个时间戳字段和时间戳类型.目前支持的时间戳类型有两种: CreateTime 和 L ...

  2. Kakfa消息投递语义

    Message Delivery Semantics At most once -- Messages may be lost but are never redelivered(消息可能丢失但不会重 ...

  3. Kafka消息系统基础知识索引

    一些观念的修正 从 0.9 版本开始,Kafka 的标语已经从“一个高吞吐量,分布式的消息系统”改为"一个分布式流平台". Kafka不仅仅是一个队列,而且是一个存储,有超强的堆积 ...

  4. Kafka消息delivery可靠性保证(Message Delivery Semantics)

    原文见:http://kafka.apache.org/documentation.html#semantics kafka在生产者和消费者之间的传输是如何保证的,我们可以知道有这么几种可能提供的de ...

  5. spark streaming 接收kafka消息之二 -- 运行在driver端的receiver

    先从源码来深入理解一下 DirectKafkaInputDStream 的将 kafka 作为输入流时,如何确保 exactly-once 语义. val stream: InputDStream[( ...

  6. spark streaming 接收kafka消息之五 -- spark streaming 和 kafka 的对接总结

    Spark streaming 和kafka 处理确保消息不丢失的总结 接入kafka 我们前面的1到4 都在说 spark streaming 接入 kafka 消息的事情.讲了两种接入方式,以及s ...

  7. 实际业务处理 Kafka 消息丢失、重复消费和顺序消费的问题

    关于 Kafka 消息丢失.重复消费和顺序消费的问题 消息丢失,消息重复消费,消息顺序消费等问题是我们使用 MQ 时不得不考虑的一个问题,下面我结合实际的业务来和你分享一下解决方案. 消息丢失问题 比 ...

  8. IM消息送达保证机制实现(二):保证离线消息的可靠投递

    1.前言 本文的上篇<IM消息送达保证机制实现(一):保证在线实时消息的可靠投递>中,我们讨论了在线实时消息的投递可以通过应用层的确认.发送方的超时重传.接收方的去重等手段来保证业务层面消 ...

  9. Kafka 消息监控 - Kafka Eagle

    1.概述 在开发工作当中,消费 Kafka 集群中的消息时,数据的变动是我们所关心的,当业务并不复杂的前提下,我们可以使用 Kafka 提供的命令工具,配合 Zookeeper 客户端工具,可以很方便 ...

  10. kafka消息会不会丢失

    转载:https://baijiahao.baidu.com/s?id=1583469327946027281&wfr=spider&for=pc 消息发送方式 想清楚Kafka发送的 ...

随机推荐

  1. <雪山飞狐><飞狐外传 >合辑剧情+随笔

    严格而言雪山飞狐与飞狐外传的剧情并不相关,前者写作与前,然后飞狐外传算是对雪山飞狐中形象并不饱满的胡斐作进一步补充描述,同时对二十余年前苗人凤与胡一刀之间故事的补充,以及众人叙述中的一些补充.因此虽然 ...

  2. HDOJ--1010题C++

    有两点需要注意,第一点就是,题意是指在第T秒时门才打开,并不是越早到门口就能越早出去,而是只要存在指定长的路径即可以出去. 第二点,每次深搜发现答案不符都必须将点重新初始化.#include<i ...

  3. BUG级别及测试准入、暂停及准出原则

    一.BUG级别说明: BUG分5个严重级别:紧急.严重.重要.次要和微小.具体描述如下: 紧急: 1) 错误导致了死机.服务器500.系统悬挂无法操作 2) 数据库连接异常 3) 临近上线时间点需求变 ...

  4. 【已解决】xlwings库合并单元格,不报错,不执行

    源代码如下: import xlwings as xw app = xw.App(visible=True, add_book=False) app.display_alerts = False ap ...

  5. Optional类与使用==判断null有什么区别?使用Optional类有什么优势?

    1.使用object==null的例子 2.null带来的问题 3.其他语言中null的处理(替代) 4.Java8的Optional类 4.1 这样做有什么好处呢? 4.2 引入Optional类的 ...

  6. zynq_ps端点亮led灯代码

    #include "stdio.h"#include "xparameters.h"#include "xgpiops.h"#include ...

  7. zxb2022习题班16

    (1) 原则:合同中包含多项履约义务的,企业应当按照各单项履约义务所承诺的商品的单独售价的比例,将交易价格分摊至各单项履约义务. 方法:按照A和B商品单独售价的相对比例, 2x22年4月16日 借:合 ...

  8. 解决office提示您的许可证不是正版的问题

    https://blog.csdn.net/d_pcb66/article/details/125339872?spm=1001.2101.3001.6650.4&utm_medium=dis ...

  9. 黑马 java.lang.IllegalArgumentException: Property ‘dataSource‘ is required

    现象: 按照教程步骤做的,但连单元测试都无法通过,会出现java.lang.IllegalArgumentException: Property 'dataSource' is required这个错 ...

  10. MTS和MTO的差别

    一.概念篇 MTS(Make-to-Stock): 按库存生产 可以独立创建计划.生产订单,可以如非限制使用的库存,并且发货等不受限制. 生产的成品或者半成品在系统中建有BOM,开工单生产后记入库存, ...