Message deduplication 这里的去重与你想的可能不一样|Apache Pulsar 技术系列
导语
Apache Pulsar 是一个多租户、高性能的服务间消息传输解决方案,支持多租户、低延时、读写分离、跨地域复制、快速扩容、灵活容错等特性。腾讯云内部 Pulsar工作组对 Pulsar 做了深入调研以及大量的性能和稳定性方面优化,目前已经在腾讯内部业务TDBank落地上线。本文是Pulsar技术系列中的一篇,主要介绍Pulsar 的 Message Deduplication 特性,供大家参考,避免在使用过程中踩坑。
Message Deduplication背景介绍
消息中间件产品设计中,对消息的投递设计,一般参照Kafka中提出的三种投递语意,分别为:
至多一次 (at-most-once)
至少一次 (at-least-once)
精确一次(或恰好一次) (exactly-once )
理解上需要注意的是,这里都是对投递行为的限定描述。
至多一次:客户端在生产消息的时候,仅会对生产的消息投递一次,这里并不保证消息一定生产成功。
至少一次:客户端在生产消息的时候,在收到一次成功的响应之前,可能会投递多次。这种场景下,服务器端可能存在多条重复的消息。
精确一次(或恰好一次):客户端在生产消息的时候,针对这次生产,服务器端保证有且仅保存一份消息。这里的 “这次生产”,一般都是指的是客户端对一次“SendMessage”的调用。这种语意下,服务器一般不会处理多次对相同消息体调用生产,产生重复消息的场景。简单而言,就是“精确一次”并不等于消息去重复。
许多系统声称提供“exactly-once”的交付语义,但仔细阅读其声明会发现,一些系统的声明可能存在一定的误导性,我们需要考虑它们在生产超时,部分副本写入成功,部分失败等场景下对语意的保证。
目前业界,绝大多数的消息中间件产品,如Kafka、RocketMQ、Pulsar、InLong-Tube、RabbitMQ、ActiveMQ等,都支持at-least-once(至少一次)的投递语意,即生产成功的消息,服务器端至少能保证存储一份,消费者至少能消费到一份消息。但是,对exactly-once(精确一次)语意支持的产品还是比较少。
下面,我们着重介绍一下Pulsar的Message Deduplication(相当于对exactly-once的一种实现)功能,可能与你想的并不一样。
Pulsar 的消息去重(Message deduplication)
功能配置
Pulsar提供的Message Deduplication 功能,默认是关闭的。开启时,需要修改Broker 端的配置,另外客户端也需要添加少许的配置。(详情可参考pulsar的官网 )
开启Message Deduplictiaon能力,首先,Broker 端需要变更如下配置:
#是否开启message deduplication功能
brokerDeduplicationEnabled#deduplication功能下,生产者的数量限制
brokerDeduplicationMaxNumberOfProducers
#broker端生成deduplication 快照信息的间隔
brokerDeduplicationEntriesInterval
#生产者断链后,broker端deduplication信息保存的时长
brokerDeduplicationProducerInactivityTimeoutMinutes
其次,生产者客户端需要做如下变更:
1、为生产者指定一个名称。
2、配置消息生产超时为0(默认为30s)。
代码示例如下:
PulsarClient pulsarClient = PulsarClient.builder()
.serviceUrl("pulsar://localhost:6650")
.build();
Producer producer = pulsarClient.newProducer()
.producerName("producer-1")
.topic("persistent://public/default/topic-1")
.sendTimeout(0, TimeUnit.SECONDS)
.create();
功能原理
客户端对每一个发送的消息请求,都会采用递增方式生成一个唯一的Sequence ID编号,这个信息会被放置在Message 的元数据中,传输到Broker端。同时,客户端Producer 也会维护一个发送的PendingMessages队列,当收到Broker端返回的发送Ack 信息后,将PendingMessages中相同Sequence ID的信息移除,客户端认为发送的这个消息生产成功。
当Broker开启Message Deduplication 功能后,Broker对对每个收到的消息请求进行是否重复的判断。
判断的逻辑如下:
1、Broker端针对每个生产者,以生产者名字为key,分当前接收到的和已经处理完成的两个维度保存生产消息的最大Sequence ID信息:
/*当前已经接受不了到的*/
ConcurrentOpenHashMap<String, Long> highestSequencedPushed
/*当前已经存储处理过的*/
ConcurrentOpenHashMap<String, Long> highestSequencedPersisted
2、Broker端每收到一个生产Message的请求,会进行是否重复的判断,即收到的最新的Sequence ID是否大于Broker 端保存的两维度下相同ProducerName下的Sequence ID,如果大于则不重复,如果小于或等于则消息重复。消息重复时,Broker端会直接返回,不会继续走后续的存储处理流程。
由上面Pulsar 的Message Depulication feature 相关的配置和实现原理的介绍。可知,Pulsar Broker端的Message Depulication 功能,并不是对消息体的去重,而是客户端在不配置超时时间的前提下,Broker 端在一定的时间范围内,对同一个生产者名称下的客户端投递的具有相同Sequence id的消息的唯一行保证。
总结
Kafka 在0.11.0.0版本之后,针对Topic之内和多个Topic之间两种场景下的exactly-once语意,分别提供了支持传递幂等性处理的选项和类事物消息的处理方式进行保证。有兴趣的同学可以参展kafka的源码和官网介绍 。
Pulsar的Message Deduplication feature与Kafka的单Topic下对exaxtly-once语意的保证在实现方式上类似,也可以认为是对exaxtly-once语意的一种实现。
这里需要着重注意的是,exaxtly-once不等于消息去重。在实际的开发中,生产和消费部分都有可能产生重复的消息。
消息的生产者,在收到明确的消息生产成功的确认之前,消息在服务器端的存储状态是不确定的。
例如,在一定时间内,生产者没有收到生产的响应,选择了重发,这时,服务器端就可能有两份甚至多份消息的副本。
此外,消费部分在如下几个场景也有可能获取到重复推送的消息:
1、消费者重启时,已经消费,但是Broker端未收到Ack或消费者没有触发Ack;
2、Broker重启,因为消费者的Ack信息并不是实时保存的,Broker重启后可能会有少量的已经消费的消息会被重复推送;
3、消费出现异常,客户端使用reconsumerLater或negativeAck方式进行确认,这时Broker会重新推送消息。
因此,大家在选用消息中间件的特性时,需要注意相关的场景和限制。避免因为重复消息对业务产生不必要的影响。
one more thing
腾讯云基于 Apache Pulsar 自研的消息中间件--TDMQ Pulsar 版,具备极好的云原生和 Serverless 特性,兼容 Pulsar 的各个组件与概念,具备计算存储分离,灵活扩缩容的底层优势。目前TDMQ Pulsar 版已开始商业化,对Pulsar感兴趣的用户可以进入官网了解详情。
Message deduplication 这里的去重与你想的可能不一样|Apache Pulsar 技术系列的更多相关文章
- ☕【难点攻克技术系列】「海量数据计算系列」如何使用BitMap在海量数据中对相应的进行去重、查找和排序
BitMap(位图)的介绍 BitMap从字面的意思,很多人认为是位图,其实准确的来说,翻译成基于位的映射,其中数据库中有一种索引就叫做位图索引. 在具有性能优化的数据结构中,大家使用最多的就是has ...
- WPF MVVM UI分离之《交互与数据分离》 基础才是重中之重~delegate里的Invoke和BeginInvoke 将不确定变为确定系列~目录(“机器最能证明一切”) 爱上MVC3系列~全局异常处理与异常日志 基础才是重中之重~lock和monitor的区别 将不确定变成确定~我想监视我的对象,如果是某个值,就叫另一些方法自动运行 将不确定变成确定~LINQ DBML模型可以对
WPF MVVM UI分离之<交互与数据分离> 在我们使用WPF过程中,不可避免并且超级喜欢使用MVVM框架. 那么,使用MVVM的出发点是视觉与业务逻辑分离,即UI与数据分离 诸如下 ...
- Scrapy框架——介绍、安装、命令行创建,启动、项目目录结构介绍、Spiders文件夹详解(包括去重规则)、Selectors解析页面、Items、pipelines(自定义pipeline)、下载中间件(Downloader Middleware)、爬虫中间件、信号
一 介绍 Scrapy一个开源和协作的框架,其最初是为了页面抓取 (更确切来说, 网络抓取 )所设计的,使用它可以以快速.简单.可扩展的方式从网站中提取所需的数据.但目前Scrapy的用途十分广泛,可 ...
- JavaScript数组去重的四种方法
今天,洗澡的想一个有趣的问题,使用js给数组去重,我想了四种方法,虽然今天的任务没有完成,5555: 不多说,po代码: //方法一:简单循环去重 Array.prototype.unique1 ...
- Lambda如何实现条件去重distinct List,如何实现条件分组groupBy List
条件去重 我们知道, Java8 lambda自带的去重为 distinct 方法, 但是只能过滤整体对象, 不能实现对象里的某个值进行判定去重, 比如: List<Integer> nu ...
- Apache Spark 2.2.0 中文文档 - Structured Streaming 编程指南 | ApacheCN
Structured Streaming 编程指南 概述 快速示例 Programming Model (编程模型) 基本概念 处理 Event-time 和延迟数据 容错语义 API 使用 Data ...
- [Pulsar系列] 10分钟学会Pulsar消息系统概念
Apache Pulsar Pulsar是一个支持多租户的.高性能的服务与服务之间消息通讯的解决方案,最初由雅虎开发,现在由Apache软件基金会管理. Pulsar的主要特性如下: Pulsar实例 ...
- 97、爬虫框架scrapy
本篇导航: 介绍与安装 命令行工具 项目结构以及爬虫应用简介 Spiders 其它介绍 爬取亚马逊商品信息 一.介绍与安装 Scrapy一个开源和协作的框架,其最初是为了页面抓取 (更确切来说, ...
- python爬取youtube视频 多线程 非中文自动翻译
声明:我写的所有文章都是发在博客园的,我看到其他复制粘贴过去的 连个出处也不写,直接打上自己的水印...真是没的说了. 前言:前段时间搞了一些爬视频的项目,代码都写好了,这里写文章那就在来重新分析一遍 ...
随机推荐
- Spring Boot整合Thymeleaf及Thymeleaf页面基本语法
引入依赖 <dependency> <groupId>org.springframework.boot</groupId> <artifactId>sp ...
- ARTS Week 18
Algorithm 本周的 LeetCode 题目为 55. 跳跃游戏 给定一个非负整数数组 nums, 你最初位于数组的 第一个下标 .数组中的每个元素代表你在该位置可以跳跃的最大长度.判断你是否能 ...
- NDK编译可执行文件在Android 中运行显示error: only position independent executables (PIE) are supported.失败问题解决办法。
由于使用了NDK编译的可执行文件在应用中调用,在Android 7.0上的运行情况发现,当运行该可执行文件时,报如下错误: error: only position independent execu ...
- 【LeetCode】753. Cracking the Safe 解题报告(Python)
作者: 负雪明烛 id: fuxuemingzhu 个人博客: http://fuxuemingzhu.cn/ 题目地址: https://leetcode.com/problems/cracking ...
- idea使用教程-常用快捷键
[1]创建内容:alt+insert [2]main方法:psvm [3]输出语句:sout [4]复制行:ctrl+d [5]删除行:ctrl+y [6]代码向上/下移动:Ctrl + Shift ...
- SOFA 通信
私有通信协议设计: 我们的分布式架构,所需要的内部通信模块,采用了私有协议来设计和研发. 可以有效地利用协议里的各个字段 灵活满足各种通信功能需求:比如 CRC 校验,Server Fail-Fast ...
- Bristol大学密码学博士生的五十二个知识点
Bristol大学密码学博士生的五十二个知识点 这个系列,是Bristol大学的密码安全工作组为密码学和信息安全相关的博士准备了52个基本知识点. 原地址:http://bristolcrypto.b ...
- [OpenCV]基于特征匹配的实时平面目标检测算法
一直想基于传统图像匹配方式做一个融合Demo,也算是对上个阶段学习的一个总结. 由此,便采购了一个摄像头,在此基础上做了实时检测平面目标的特征匹配算法. 代码如下: # coding: utf-8 ' ...
- MyBatis练习——使用MyBatis查询所有职员信息
实现要求: 使用MyBatis查询所有职员信息 create table employee( id int not null auto_increment, name varchar(255) not ...
- 编写Java程序,以继承和多态思想模拟饲养员喂养不同动物的不同行为
返回本章节 返回作业目录 需求说明: 以继承和多态思想模拟饲养员喂养不同动物的不同行为 动物园有饲养员和动物,其中动物有老虎.马.猴子.羊.狼等. 饲养员对不同的动物有不同的喂养行为. 实现思路: 以 ...