消息队列技术选型:这 7 种消息场景一定要考虑!

news2024/12/26 0:19:18

大家好,我是君哥。

我们在做消息队列的技术选型时,往往会结合业务场景进行考虑。今天来聊一聊消息队列可能会用到的 7 种消息场景。

1 普通消息

消息队列最基础的功能就是生产者发送消息、Broker 保存消息,消费者来消费消息,以此实现系统解耦、削峰填谷的作用。

普通消息是消息队列必备的消息类型,也是系统使用场景最多的一种消息。

2 顺序消息

顺序消息是指生产者发送消息的顺序和消费者消费消息的顺序是一致的。比如在一个电商场景,同一个用户提交订单、订单支付、订单出库,这三个消息消费者需要按照顺序来进行消费。如下图:

顺序消息的实现并不容易,原因如下:

  • 生产者集群中,有多个生产者发送消息,网络延迟不一样,很难保证发送到 Broker 的消息落盘顺序是一致的;
  • 如果 Broker 有多个分区或队列,生产者发送的消息会进入多个分区,也无法保证顺序消费;
  • 如果有多个消费者来异步消费同一个分区,很难保证消费顺序跟生产者发送顺序一致。

要保证消息有序,需要满足两个条件:

  • 同一个生产者必须同步发送消息到同一个分区;
  • 一个分区只能给同一个消费者消费。

如下图:

上面第二个条件是比较容易实现的,一个分区绑定一个消费者就可以,主要是第一个条件。

在主流消息队列的实现中,Kafka 和 Pulsar 的实现方式类似,生产者给消息赋值一个 key,对 key 做 Hash 运算来指定消息发送到哪一个分区。比如上面电商的例子,对同一个用户的一笔订单,提交订单、订单支付、订单出库这三个消息赋值同一个 key,就可以把这三条消息发送到同一个分区。

对于 RocketMQ,生产者在发送消息的时候,可以通过 MessageQueueSelector 指定把消息投递到那个 MessageQueue,如下图:

示例代码如下:

public static void main(String[] args) throws UnsupportedEncodingException {
 try {
  DefaultMQProducer producer = new DefaultMQProducer("please_rename_unique_group_name");
  producer.start();

  String[] tags = new String[] {"TagA", "TagB", "TagC", "TagD", "TagE"};
  for (int i = 0; i < 100; i++) {
   int orderId = i % 10;
   Message msg =
    new Message("TopicTestjjj", tags[i % tags.length], "KEY" + i,
     ("Hello RocketMQ " + i).getBytes(RemotingHelper.DEFAULT_CHARSET));
   SendResult sendResult = producer.send(msg, new MessageQueueSelector() {
    @Override
    public MessageQueue select(List<MessageQueue> mqs, Message msg, Object arg) {
     Integer id = (Integer) arg;
     int index = id % mqs.size();
     return mqs.get(index);
    }
   }, orderId);

   System.out.printf("%s%n", sendResult);
  }

  producer.shutdown();
 } catch (MQClientException | RemotingException | MQBrokerException | InterruptedException e) {
  e.printStackTrace();
 }
}

RabbitMQ 的实现是 Exchange 根据设置好的 Route Key 将数据路由到不同的 Queue 中。示例代码如下:

@Resource
private AmqpTemplate rabbitTemplate;

public void send1(String message) {
 rabbitTemplate.convertAndSend("testExchange", "testRoutingKey", message);
}

3 延时消息

或者也叫定时消息,是指消息发送后不会立即被消费,而是指定一个时间,到时间后再消费。经典的场景比如电商购物时,30 分钟未支付订单,让订单自动失效。

3.1 RocketMQ 实现

RocketMQ 定义了 18 个延时级别,每个延时级别对应一个延时时间。下面如果延迟级别是 3,则消息会延迟 10s 才会拉取。

//MessageStoreConfig类
private String messageDelayLevel = "1s 5s 10s 30s 1m 2m 3m 4m 5m 6m 7m 8m 9m 10m 20m 30m 1h 2h";

RocketMQ 的延时消息如下图:

生产者把消费发送到 Broker 后,Broker 首先把消息保存到 SCHEDULE_TOPIC_XXXX 这个 Topic,然后调度任务会判断是否到期,如果到期,会把消息从 SCHEDULE_TOPIC_XXXX 取出投递到原始的 queue,这样消费者就可以消费到了。

RocketMQ 的延时消息只支持最大两个小时的延时,不过 RocketMQ5.0 基于时间轮算法实现了定时消息,解决了这个问题。

3.2 Pulsar 实现

Pulsar 的实现如下图:

Pulsar 的延时消息首先会写入一个 Delayed Message Tracker 的数据结构中,Delayed Message Tracker 根据延时时间构建 delayed index 优先级队列。消费者拉取消息时,首先去 Delayed Message Tracker 检查是否有到期的消息。如果有则直接拉取进行消费。

3.3 RabbitMQ 实现

RabbitMQ 的实现方式有两种,一种是投递到普通队列都不消费,等消息过期后被投递到死信队列,消费者消费死信队列。如下图:

第二种方式是生产者发送消息时,先发送到本地 Mnesia 数据库,消息到期后定时器再将消息投递到 broker。

3.4 Kafka 实现

Kafka 本身并没有延时队列,不过可以通过生产者拦截器来实现消息延时发送,也可以定义延时 Topic,利用类似 RocketMQ 的方案来实现延时消息。

4 事务消息

事务消息是指生产消息和消费消息满足事务的特性。

RabbitMQ 和 Kafka 的事务消息都是只支持生产消息的事务特性,即一批消息要不全部发送成功,要不全部发送失败。

RabbitMQ 通过 Channel 来开启事务消息,代码如下:

ConnectionFactory factory=new ConnectionFactory();
connection=factory.newConnection();
Channel channel=connection.createChannel();
//开启事务
channel.txSelect();
channel.basicPublish("directTransactionExchange","transactionRoutingKey",null,message.getBytes("utf-8"));
//提交事务 或者 channel.txRollback()回滚事务
channel.txCommit();

Kafka 可以给多个生产者设置同一个事务 ID ,从而把多个 Topic 、多个 Partition 放在一个事务中,实现原子性写入。

Pulsar 的事务消息对于事务语义的定义是:允许事件流应用将消费、处理、生产消息整个过程定义为一个原子操作。可见,Pulsar 的事务消息可以覆盖消息流整个过程。

RocketMQ 的事务消息是通过 half 消息来实现的。以电商购物场景来看,账户服务扣减账户金额后,发送消息给 Broker,库存服务来消费这条消息进行扣减库存。如下图:

可见,RocketMQ 只能保证生产者发送消息和本地事务的原子性,并不能保证消费消息的原子性。

5 轨迹消息

轨迹消息主要用于跟踪消息的生命周期,当消息丢失时可以很方便地找出原因。

轨迹消息也跟普通消息一样,也需要存储和查询,也会占用消息队列的资源,所以选择轨迹消息要考虑下面几点:

  • 消息生命周期的关键节点一定要记录;
  • 不能影响正常消息的发送和消费性能;
  • 不能影响 Broker 的消息存储性能;
  • 要考虑消息查询维度和性能。

RabbitMQ Broker 实现了轨迹消息的功能,打开 Trace 开关,就可以把轨迹消息发送到 amq.rabbitmq.trace 这个 exchange,但是要考虑轨迹消息会不会给 Broker 造成 压力进而导致消息积压。RabbitMQ 的生产者和消费者都没有实现轨迹消息,需要开发者自己来实现。

RocketMQ 生产者、Broker 和消费者都实现了轨迹消息,不过默认是关闭的,需要手工开启。

使用轨迹消息,需要考虑记录哪些节点、存储介质、性能、查询方式等问题。

6 死信队列

在消息队列中,死信队列主要应对一些异常的情况,如下图:

RocketMQ 实现了消费端的死信队列,当消费者消费失败时,会进行重试,如果重试 16 次还是失败,则这条消息会被发送到死信队列。

RabbitMQ 实现了生产者和 Broker 的死信队列,下面三种情况,消息会被发送到死信队列:

  • 生产者发送消息被拒绝,并且 requeue 参数设置为 false;
  • Broker 消息过期了;
  • 队列达到最大长度。

RabbitMQ 消息变成死信消息后,会被发送到死信交换机(Dead-Letter-Exchange)。

7 优先级消息

有一些业务场景下,我们需要优先处理一些消息,比如银行里面的金卡客户、银卡客户优先级高于普通客户,他们的业务需要优先处理。如下图:

主流消息队列中,RabbitMQ 是支持优先级队列的,代码如下:

ConnectionFactory factory=new ConnectionFactory();
connection=factory.newConnection();
Channel channel=connection.createChannel();
Map<String, Object> args = new HashMap<String, Object>();
//设置优先级为 5
args.put("x-max-priority", 5);
channel.queueDeclare("my-priority-queue", true, false, false, args);

8 总结

消息队列技术选型,要考虑的因素很多,本文主要从业务场景来分析需要考虑的因素,同时技术上也需要考虑运维复杂度、业务规模、社区活跃度、学习成本等因素。希望本文对你使用消息队列有所帮助。

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

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

相关文章

在vue2中,v-model和.sync的区别

最近在封装一个弹窗组件时&#xff0c;用了比较复杂的逻辑去做显示和隐藏的逻辑&#xff0c;在查看同事的代码之后&#xff0c;才知道还有更简单的方法&#xff0c;自己已经忘了一些API. popup组件里统一的template&#xff1a; <div v-ifisShowPopup> // 弹窗内容 <…

手机图片合成gif怎么操作?用这个网站试试

制作gif动图的工具越来越多&#xff0c;但是很多时候使用电脑并不方便&#xff0c;想要在手机上制作gif动图的时候应该怎么办呢&#xff1f;很简单&#xff0c;给大家分享一款无需下载手机浏览器就能操作的gif制作&#xff08;https://www.gif.cn/&#xff09;工具-GIF中文网&a…

分库分表理论总结

一、概述 分库分表是在面对高并发、海量数量时常见的数据库层面的解决方案。通过把数据分散到不同的数据库中&#xff0c;使得单一数据库的数据量变小来缓解单一数据库的性能问题&#xff0c;从而达到提升数据库性能的目的。比如&#xff1a;将电商数据库拆分为若干独立的数据…

计算机考研 | 2019年 | 计算机组成原理真题

文章目录 【计算机组成原理2019年真题45题-16分】【第一步&#xff1a;信息提取】【第二步&#xff1a;具体解答】 【计算机组成原理2019年真题46题-7分】【第一步&#xff1a;信息提取】【第二步&#xff1a;具体解答】 【计算机组成原理2019年真题45题-16分】 【第一步&#…

FreeTAKServer安装教程

项目地址 https://github.com/FreeTAKTeam/FreeTakServer 环境说明 FreeTakServer使用python开发&#xff0c;所以需要安装python,本教程安装的python版本为python3.11,系统为ubuntu 20.04 安装 安装FreeTakServer 安装FreeTAKServer pip install FreeTakServer启动Free…

Canvas--》使用Canvas完成基本绘图

&#x1f31f;Canvas介绍 <canvas>是一个可以使用脚本 (通常为javaScript) 来绘制图形的HTML元素。例如&#xff0c;它可以用于绘制图表、制作图片构图或者制作简单的动画。如上面效果示例就是使用 <canvas> 来实现示例&#xff0c;后续将一步步实现上面效果。 C…

HDLbits: ece241 2014 q4

module top_module (input clk,input x,output z ); reg [2:0] Q;always(posedge clk)beginQ[0] < Q[0] ^ x;Q[1] < (~Q[1]) & x;Q[2] < (~Q[2]) | x;z < ~(| Q[2:0]); //错误&#xff01;&#xff01;&#xff01;&#xff01;endendmodule 正确答案&#xf…

Python python-docx 使用教程

openpyxl是Python下的Word库&#xff0c;它能够很容易的对Word文档进行读取 安装方法&#xff1a;pip install python-docx国内镜像安装&#xff1a;pip install -i https://mirrors.aliyun.com/pypi/simple/ python-docx&#xff08;推荐&#xff0c;安装更快&#xff09;中文…

【算法】关于排序你应该知道的一切(下)

和光同尘_我的个人主页 单程孤舟&#xff0c;出云入霞&#xff0c;如歌如吟。 --门孔 八大排序 &#x1f56f;️前言1. 常见排序算法2. 常见排序算法实现2.1. 冒泡排序2.1.1. 基本思想2.1.2. 代码实现2.1.3. 特性 2.2. 快速排序2.2.1. hoare法基本思想代码实现 2.2.2. 快速排…

静图表情包怎么做成动态图?动图表情包制作教程

静态的图片不如动态的图片吸引人&#xff0c;动态的图片内容丰富、生动&#xff0c;体积小还易于传播保存。Gif格式动图其实就是由一帧一帧的图片合成的带有动态效果的图片。下面&#xff0c;给大家介绍一下动图gif制作&#xff08;https://www.gif.cn/&#xff09;的方法&…

asp.net班级管理系统VS开发sqlserver数据库web结构c#编程Microsoft Visual Studio

一、源码特点 asp.net班级管理系统 是一套完善的web设计管理系统&#xff0c;系统具有完整的源代码和数据库&#xff0c;系统主要采用B/S模式开发。开发环境为vs2010&#xff0c;数据库为sqlserver2008&#xff0c;使用c#语言开发 asp.net班级管理系统 二、功能介绍 1…

操作系统和进程相关的认识

目录 冯诺依曼体系结构 冯诺依曼体系结构五大组成部分 为什么数据只能通过存储器进行输入和输出 操作系统 概念一&#xff1a;访问操作系统的请求都是通过系统调用完成的 操作系统如何管理用户信息 概念二&#xff1a;先描述&#xff0c;再组织。 进程的概念 在认识进行相关的知…

Java基础--泛型详解

一、背景 java推出泛型之前&#xff0c;集合元素类型可以是object类型&#xff0c;能够存储任意的数据类型对象&#xff0c;但是在使用过程中&#xff0c;如果不知道集合里面的各个元素的类型&#xff0c;在进行类型转换的时候就很容易引发ClassCastException异常。 二、概念 …

POJ 2104 K-th Number 平方分割(分桶法)

一、题目大意 长度为n&#xff08;n<100000&#xff09;的数组&#xff0c;进行m次查询&#xff08;m<5000&#xff09;&#xff0c;每次查询时&#xff0c;输入为 i j k&#xff0c;返回为数组 [i,j] 的分片里第k大数字&#xff08;1<i<j<n,k<j-i1) 二、解…

基于Java的校园自助洗衣系统设计与实现(源码+lw+ppt+部署文档+视频讲解等)

文章目录 前言具体实现截图论文参考详细视频演示为什么选择我自己的网站自己的小程序&#xff08;小蔡coding&#xff09;有保障的售后福利 代码参考源码获取 前言 &#x1f497;博主介绍&#xff1a;✌全网粉丝10W,CSDN特邀作者、博客专家、CSDN新星计划导师、全栈领域优质创作…

python机器学习之梯度下降法

系列文章目录 第一章 Python 机器学习入门之线性回归 第一章 Python 机器学习入门之梯度下降法 梯度下降法 系列文章目录前言一、梯度下降法1.梯度下降法简介2.基本原理 梯度下降函数效果展示 前言 上一篇文章里面说到了用梯度下降法来对最小化代价函数和模型参数进行求解&am…

计算机网络八股

1、请你说说TCP和UDP的区别 TCP提供面向连接的可靠传输&#xff0c;UDP提供面向无连接的不可靠传输。UDP在很多实时性要求高的场景有很好的表现&#xff0c;而TCP在要求数据准确、对速度没有硬件要求的场景有很好的表现。TCP和UDP都是传输层协议&#xff0c;都是为应用层程序服…

八、【快速选择工具组】

文章目录 对象选择工具快速选择工具魔棒工具 对象选择工具 当我们选择对象选择工具时&#xff0c;需要先注意上边有一个循环的圆&#xff0c;它会进行内容识别&#xff0c;当识别完成会停止旋转。这个时候我们按住n键&#xff0c;或者将鼠标放上对应的图形时会出现选中的颜色。…

多实例学习MIL(easy / hard)

多示例学习&#xff08;Multiple Instance Learning&#xff09; - 知乎 (zhihu.com)https://zhuanlan.zhihu.com/p/377220948 多示例学习 和弱监督&#xff08;weakly supervised&#xff09;有一定的关系&#xff0c;弱监督weakly supervised有三个含义&#xff08;或者说三…

ethercat EOE arp

1 网口设置 电脑地址位169.254.254.3 2 从站地址 3 PING 正常 异常 4 抓包