Kafka【八】如何保证消息发送的可靠性、重复性、有序性

news2024/12/22 20:16:10

【1】消息发送的可靠性保证

对于生产者发送的数据,我们有的时候是不关心数据是否已经发送成功的,我们只要发送就可以了。在这种场景中,消息可能会因为某些故障或问题导致丢失,我们将这种情况称之为消息不可靠。虽然消息数据可能会丢失,但是在某些需要高吞吐,低可靠的系统场景中,这种方式也是可以接受的,甚至是必须的。

但是在更多的场景中,我们是需要确定数据是否已经发送成功了且Kafka正确接收到数据的,也就是要保证数据不丢失,这就是所谓的消息可靠性保证。

而这个确定的过程一般是通过Kafka给我们返回的响应确认结果(Acknowledgement)来决定的,这里的响应确认结果我们也可以简称为ACK应答。根据场景,Kafka提供了3种应答处理,可以通过配置对象进行配置。

在 Apache Kafka 中,ACK(Acknowledgment)指的是生产者在发送消息后,从 Kafka Broker 接收到的确认信号。这种确认机制是用来保证消息发送的可靠性的。Kafka 支持不同的 ACK 策略,这些策略允许生产者根据自己的需求来配置不同的确认级别。以下是 Kafka 中关于 ACK 的几个选项:

  1. No Acknowledgment (acks = 0)

    • 在这种模式下,生产者在发送消息后不会等待任何确认就认为消息已经被成功发送。这意味着如果 Broker 在写入消息之前崩溃,消息可能会丢失。这种方式提供了最高的吞吐量,但是没有可靠性保障。
  2. Leader Acknowledgment (acks = 1)

    • 在这种模式下,生产者在发送消息后会等待 Leader 副本确认消息已被写入。如果在确认之后 Leader 崩溃,那么消息仍然可能会丢失,因为还没有同步到 Follower 副本。这种方式提供了较好的吞吐量,但仍然存在一定的数据丢失风险。
  3. All In-Sync Replicas Acknowledgment (acks = all 或 acks = -1)

    • 这是最严格的确认策略,生产者在发送消息后会等待所有 ISR(In-Sync Replicas)的确认。这意味着消息不仅写入了 Leader,还同步到了所有的 Follower 副本。这种方式虽然降低了吞吐量,但是提供了最强的数据持久性和可靠性保障。

选择哪种 ACK 策略取决于应用的具体需求。如果对数据丢失有严格的要求,那么通常会选择 acks=all,以确保消息的持久性和可靠性;如果对性能要求较高,并且可以接受一定程度的数据丢失风险,那么可以选择较低级别的确认策略。

需要注意的是,使用 acks=all 时,如果 ISR 中的任何一个副本无法同步消息,那么生产者将无法发送新的消息,直到问题解决。因此,在配置 ACK 时,也需要考虑集群的健康状况和副本的数量。

假设我们的分区有5个follower副本,编号为1,2,3,4,5:

在这里插入图片描述

但是此时只有3个副本处于和Leader副本之间处于数据同步状态,那么此时分区就存在一个同步副本列表,我们称之为In Syn Replica,简称为ISR。此时,Kafka只要保证ISR中所有的4个副本接收到了数据,就可以对数据请求进行响应了。无需5个副本全部收到数据。

【2】消息发送的重复性

kafka为了提高数据可靠性提供了重试机制用来解决消息丢失问题。如果禁用重试机制,那么一旦数据发送失败,数据就丢失了。而数据重复,恰恰是因为开启重试机制后,如果因为网络阻塞或不稳定,导致数据重新发送。那么数据就有可能是重复的。

kafka提供了幂等性操作解决数据重复,并且幂等性操作要求必须开启重试功能和ACK取值为-1。

在 Apache Kafka 中,解决消息重复发送的问题通常涉及以下几个方面:

1. 幂等性生产者

Kafka 0.10.1 版本引入了幂等性生产者(Idempotent Producers)。启用幂等性后,生产者可以保证消息不会被重复发送。幂等性生产者依赖于事务日志来跟踪已发送的消息,并确保即使生产者崩溃,消息也只会被发送一次。

  • 实现原理
    • 生产者为每条消息附加一个序列号。
    • Broker 使用序列号来检查消息是否已经被发送过。
    • 如果 Broker 发现序列号冲突,则拒绝该消息。
Map<String, Object> configMap = new HashMap<>();
configMap.put(ProducerConfig.BOOTSTRAP_SERVERS_CONFIG, "localhost:9092");
// TODO 对生产的数据K, V进行序列化的操作
configMap.put(ProducerConfig.KEY_SERIALIZER_CLASS_CONFIG, StringSerializer.class.getName());
configMap.put(ProducerConfig.VALUE_SERIALIZER_CLASS_CONFIG, StringSerializer.class.getName());
configMap.put(ProducerConfig.ACKS_CONFIG, "-1");//ACK应答
configMap.put(ProducerConfig.ENABLE_IDEMPOTENCE_CONFIG, true);//开启幂等性
configMap.put(ProducerConfig.RETRIES_CONFIG, 5);
configMap.put(ProducerConfig.BATCH_SIZE_CONFIG, 5);
configMap.put(ProducerConfig.REQUEST_TIMEOUT_MS_CONFIG, 3000);

KafkaProducer<String, String> producer = new KafkaProducer<String, String>(configMap);

kafka提供的幂等性操作只能保证同一个生产者会话中同一个分区中的数据不会重复,一旦数据发送过程中,生产者对象重启,那么幂等性操作就会失效。那么此时就需要使用Kafka的事务功能来解决跨会话的幂等性操作。但是跨分区的幂等性操作是无法实现的。

2. 事务支持

Kafka 从 0.11 版本开始支持事务,这使得生产者可以在事务上下文中发送消息。事务可以确保消息要么全部发送成功,要么全部不发送,从而避免部分消息丢失或重复发送的问题。

  • 实现原理

    • 生产者开启事务,并在一个事务中发送一系列消息。
    • 生产者在消息发送完成后提交事务。
    • 如果生产者崩溃或出现其他异常,则可以回滚事务,取消未完成的消息发送。

    事务支持可以用于确保消息的一致性和完整性。

【3】幂等性与事务支持

幂等性生产者(Idempotent Producers)和事务支持(Transactional Support)是两种不同的机制,它们各自解决了不同的问题,但在实际应用中可以结合起来使用。

幂等性生产者(Idempotent Producers)

幂等性生产者的设计目的是为了确保即使生产者崩溃或重试消息发送,消息也只被写入一次,从而避免重复消息。幂等性生产者不需要开启事务,而是通过以下机制来实现这一目标:

  • 消息序列化:生产者为每个分区的消息生成一个唯一的序列号。
  • 校验重复:Broker 会在接收到消息时检查序列号,如果发现序列号已经存在,则会拒绝这条消息。

幂等性生产者适用于那些希望避免重复消息,但又不需要事务一致性的情况。也就是说,它保证了即使生产者崩溃或重试发送,消息依然只被写入一次,但它并不保证消息的全局顺序或跨分区的一致性。

事务支持(Transactional Support)

事务支持则是为了实现更高级别的消息一致性和原子性,确保消息要么全部发送成功,要么全部不发送。事务支持可以用来处理跨多个分区甚至跨不同系统的复杂操作,确保这些操作作为一个整体成功或失败。

  • 事务上下文:生产者在事务上下文中发送消息,确保消息的发送是原子性的。
  • 提交或回滚:生产者可以在消息处理成功后提交事务,或者在处理失败时回滚事务。

事务支持适用于需要确保消息处理的原子性和一致性的场景,特别是在涉及到跨多个分区或多系统协调的情况下。

幂等性与事务的结合

在一些场景中,你可能会结合使用幂等性生产和事务支持,以达到更高的可靠性和一致性。例如:

  • 幂等性生产者 可以用来防止消息的重复发送。
  • 事务支持 可以用来确保跨多个分区或系统的操作的一致性。

在这种情况下,幂等性生产者确保单个消息不会重复写入,而事务支持则确保整个操作的原子性。

总结

  • 幂等性生产者:防止消息重复发送,适用于单个消息级别的去重。
  • 事务支持:确保操作的原子性和一致性,适用于需要跨分区或系统的一致性操作。

因此,幂等性生产者并不是必须与事务隔离使用才能保证消息的唯一性。相反,幂等性生产者本身就是为了解决消息重复发送问题而设计的。事务支持则是为了实现更高级别的数据一致性和操作的原子性。两者可以独立使用,也可以结合使用以满足不同的需求。

【4】消息发送的有序性保证

在 Apache Kafka 中,保证消息发送的有序性主要依赖于以下几种机制和策略:

1. 单一分区内的消息有序

Kafka 默认保证在一个主题(Topic)的单个分区(Partition)内部的消息是有序的。这是因为消息是按顺序追加到分区的日志文件中的。因此,如果你需要确保消息在主题内的顺序,可以将所有相关消息都发送到同一个分区。

如何实现单一分区内消息有序:

  • 固定分区器:你可以通过设置固定的分区器(Partitioner),使所有具有相同键的消息都被发送到同一个分区。例如,使用相同的键(Key)可以使消息被发送到同一分区,从而在该分区内保持顺序。

2. 使用幂等性生产者

尽管幂等性生产者的主要目的是防止消息重复发送,但如果你使用相同的键发送消息,并且启用了幂等性生产者,那么所有具有相同键的消息将被发送到同一个分区,并且在这个分区内保持顺序。

3. 使用事务性生产者

事务性生产者可以用来确保消息的发送是原子的,并且可以用来实现跨多个分区的操作的一致性。虽然事务性生产者本身并不能直接保证消息的顺序,但如果结合分区策略,可以间接实现有序性。

示例配置

假设你需要确保所有消息在一个主题内是有序的,你可以这样配置生产者:

Properties props = new Properties();
props.put(ProducerConfig.BOOTSTRAP_SERVERS_CONFIG, "localhost:9092");
props.put(ProducerConfig.KEY_SERIALIZER_CLASS_CONFIG, "org.apache.kafka.common.serialization.StringSerializer");
props.put(ProducerConfig.VALUE_SERIALIZER_CLASS_CONFIG, "org.apache.kafka.common.serialization.StringSerializer");
props.put(ProducerConfig.ACKS_CONFIG, "all");
props.put(ProducerConfig.RETRIES_CONFIG, Integer.MAX_VALUE); // 无限重试
props.put(ProducerConfig.MAX_IN_FLIGHT_REQUESTS_PER_CONNECTION, 1); // 保证消息发送顺序
props.put(ProducerConfig.ENABLE_IDEMPOTENCE_CONFIG, true); // 启用幂等性

// 创建生产者
KafkaProducer<String, String> producer = new KafkaProducer<>(props);

这里的关键配置点是 max.in.flight.requests.per.connection 设置为 1,这可以确保在单个连接上一次只发送一条消息,从而在单一分区内保持消息的顺序。

注意事项

  • 单一分区限制:虽然单一分区内部可以保证消息有序,但这意味着所有相关消息都需要发送到同一个分区,这可能会导致性能瓶颈。
  • 并发处理:如果你需要高并发处理,而不仅仅关注消息的顺序,那么可能需要在多个分区之间平衡负载,并且在客户端实现适当的逻辑来处理顺序问题。

通过上述方法,Kafka 可以在不同程度上保证消息的有序性,但通常需要在性能和有序性之间做出权衡。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2106533.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

zoom缩放导致下拉框定位偏移问题

因为浏览器升级修改了zoom导致 https://developer.chrome.google.cn/release-notes/128?hlzh_tw 可根据zoom值计算相差偏移量 const isChromeHighVersion () > {const ua navigator.userAgent.toLowerCase();const chromeIndex ua.indexOf(chrome);if (chromeIndex >…

跑步戴的耳机哪个品牌的好?精选五款热门品牌骨传导耳机分享

近年来&#xff0c;骨传导耳机逐渐成为了人们喜爱的耳机之一。相比于传统的耳机&#xff0c;骨传导耳机不需要使用耳塞&#xff0c;就可以让用户在运动时更加自由自在&#xff0c;不受耳机带来的束缚感。然而&#xff0c;市面上的骨传导耳机品牌和型号众多&#xff0c;质量参差…

如何把大的txt文件拆分为小的文件?

命令&#xff1a;split 1. 功能&#xff1a;这个是一个Linux 命令&#xff0c;功能是一个大文件分割成多个较小的文件。 可以使用该命令的系统&#xff1a;在Linux 终端&#xff0c;或者是windows git bash 端口。 官方说明&#xff1a;在Linux 终端&#xff0c;或者是…

【生成模型系列(中级)】词向量维度选择的奥秘——从理论到实验的揭秘【通俗理解,代码模拟】

【通俗理解】词向量维度选择的奥秘——从理论到实验的揭秘 关键词提炼 #词向量 #维度选择 #最小熵原理 #Johnson-Lindenstrauss引理 #注意力机制 #图网络 第一节&#xff1a;词向量维度选择的类比与核心概念【尽可能通俗】 1.1 词向量维度选择的类比 词向量维度选择就像为一…

Git 使用指南 --- 版本管理

序言 Git 是一个开源的 分布式版本控制系统&#xff0c;可以有效、高速地处理从很小到非常大的项目版本管理。对一个程序员来说&#xff0c;掌握 Git 的使用是必要的。  在这个系列中&#xff0c;将详细的介绍 Git 的使用和原理&#xff0c;话不多说&#xff0c;让我们开始吧。…

C# 加解密之DES

说完了对称加密中的AES&#xff0c;这一篇再来介绍下DES。加解密原理什么的就不介绍了&#xff0c;大家可以自行百度&#xff08;主要我也不太明白&#xff0c;也不需要太明白&#xff09;&#xff0c;大致说一下两者的区别吧&#xff01; 首先肯定是加密算法的不同&#xff0…

模型大师们!答应我把这8本书翻烂好嘛?

模型大师们&#xff0c;准备好踏上一段深度学习与模型构建的路了吗&#xff1f; 这里有八本经典之作&#xff0c;它们将是你攀登知识高峰的阶梯! 从《PyTorch深度学习实战》到《大模型时代》 从掌握基础框架到洞悉大模型时代的变革 模型大师&#xff0c;准备好了吗&#xff…

RabbitMQ核心架构

RabbitMQ架构设计 Producer&#xff1a;负责产生消息。 Connection&#xff1a;RabbitMQ客户端和代理服务器之间的TCP连接。 Channel&#xff1a;建立在连接之上的虚拟连接&#xff0c;RabbitMQ操作都是在信道中进行。 Broker&#xff1a;一个Broker可以看做一个RabbitMQ服…

TP5发送邮件功能如何实现?怎么配置服务?

TP5发送邮件性能优化如何优化&#xff1f;怎么使用TP5发送邮件&#xff1f; 在现代Web开发中&#xff0c;TP5框架因其高效和灵活性而广受欢迎。无论是用于用户注册验证、密码重置还是定期通知&#xff0c;TP5发送邮件功能都能提供强大的支持。AokSend将详细介绍如何在TP5框架中…

开放式耳机和骨传导耳机哪个好?2024年开放式耳机排行榜10强

随着耳机市场的不断发展&#xff0c;开放式耳机和骨传导耳机逐渐成为两大热门选择。无论是追求高音质还是重视佩戴舒适度&#xff0c;消费者在选购耳机时都面临着一个重要问题&#xff1a;开放式耳机和骨传导耳机到底哪个更好&#xff1f;今天我们就来深入对比这两种耳机的优缺…

顶会最高分的文章怎么写?基于CNN的时间序列新SOTA就是最好的答案!

【时间序列CNN】&#xff08;卷积神经网络&#xff09;在近年来的深度学习领域中备受关注&#xff0c;它通过将卷积神经网络应用于时间序列数据&#xff0c;显著提升了模型在特征提取和模式识别任务中的表现。时间序列CNN技术已经在金融预测、健康监测和工业设备故障检测等多个…

竟然有50万个使用Flutter开发的应用了,这也太牛了!

近期工作比较清闲&#xff0c;在Flutter和React Native两者中犹豫学习哪个&#xff0c;做了不少功课&#xff0c;最终决定入手Flutter。原因很简单&#xff0c;感觉Flutter更有前景&#xff0c;另外B站也找到了适合自己学习的Flutter免费教程&#xff0c;天时地利人和&#xff…

进程的那些事——了解进程(虚拟地址空间)

目录 前言 一、程序地址空间&#xff08;虚拟地址空间&#xff09; 二、虚拟地址寻找物理内存 1.页表 总结 前言 提示&#xff1a;这里可以添加本文要记录的大概内容&#xff1a; 程序和进程之间的区别&#xff1a; 进程&#xff1a;对用户而言&#xff0c;进程是运行中的…

写卡片可以成为专家吗?

前一段&#xff0c;一位同学问我&#xff1a; 写小卡片记录巅峰&#xff0c;积少成多就一定能成为行业专家了吗&#xff1f; 我的观点如下&#xff1a; 想成为行业专家&#xff0c;我认为要有两类卡片&#xff1a; 1. 对同行专家知识学习后&#xff0c;所写的卡片。比如&am…

【专项刷题】— 字符串

1、最长公共前缀 - 力扣&#xff08;LeetCode&#xff09; 思路&#xff1a; 解法一&#xff1a;两两比较字符串解法二&#xff1a;比较每一个字符串的同一位图解&#xff1a;代码&#xff1a; class Solution {public String longestCommonPrefix(String[] strs) {String ret …

北京精诚博爱医院简介

北京精诚博爱医院位于北京市朝阳区崔各庄乡南皋路188号&#xff0c;地处东北五环外&#xff0c;毗邻首都机场高速&#xff0c;与北京798艺术区和草场地艺术区隔窗相望&#xff0c;交通便捷。是一所以医疗、康复、预防保健为一体综合性医保定点医院。 医院为国家呼吸临床中心医联…

旺店通ERP集成用友NC(用友NC主供应链)

源系统成集云目标系统 用友NC介绍 用友NC是用友NC产品的全新系列&#xff0c;是面向集团企业的世界级高端管理软件。它以“全球化集团管控、行业化解决方案、全程化电子商务、平台化应用集成”的管理业务理念而设计&#xff0c;采用J2EE架构和先进开放的集团级开发平…

基于Java的在线文献检索系统

基于springbootvue实现的在线文献检索系统&#xff08;源码L文ppt远程调试&#xff09;4-027 第4章 系统设计 4.1 总体功能设计 一般个人用户和管理者都需要登录才能进入在线文献检索系统&#xff0c;使用者登录时会在后台判断使用的权限类型&#xff0c;包括一般使用者…

C# NX二次开发-获取体全部面

使用 UF_MODL_ask_body_faces 或获取一个体的全部面&#xff1a; 代码&#xff1a; theUf.Modl.AskBodyFaces(body.Tag, out var face_list);face_list.Foreach(x > x.NxListing()); 免责声明&#xff1a; 只用于参考&#xff0c;如果有什么问题不要找我呀。

【Google Play】携程旅行8.71.6最新国际版(如何鉴别是否官方?)

作为业内权威的在线旅游服务公司&#xff0c;携程旅行手机客户端提供中国境内超过11万家酒店和公寓的选择&#xff0c;海外则有超过70万家酒店可供预订。覆盖所有国内航线机票以及大部分主流国际航线&#xff0c;国内火车票全覆盖&#xff0c;长途汽车票则涵盖了500多个城市的2…