关于Rabbitmq在逻辑主体层面的配置

我们这个文章,主体对象是对rabbitmq的逻辑实体去进行全面的认识和介绍。

什么是rabbitmq,这个其实本质上就是,本体就是一个可以存储大量json数据的队列。也就是queue。本质上,我认为他的主体就是这个。

但是,由于使用erlang语言编写的,他可以短时间承受大量的json请求接收。

这个我认为就是这个最重要的point。

但是为了适应更领灵活的场景,于是,有多个交换机,多个队列。也提供了几个基本的机制,来处理问题。

一、本体:队列,就是队列

别绕弯子。

RabbitMQ 的本体,就是一个能存消息的队列(Queue)。

生产者往里塞

消费者从里取

先进先出,天然解耦

消息体是什么?可以是 JSON,可以是二进制,但在绝大多数业务场景里,它就是 JSON。订单、日志、事件通知......全是 JSON 往队列里扔。

所以你说"存储大量 JSON 数据的队列",从业务视角看,没毛病。这就是开发者每天打交道的真实模样。

二、硬核底座:Erlang,扛住瞬时洪峰

为什么这个队列能扛住高并发?

因为它是用 Erlang 写的。

轻量级进程模型:每条连接、每个队列都是独立进程,互不干扰

调度器直接跑在 BEAM 虚拟机上,上下文切换成本极低

天生为"高并发、低延迟、软实时"场景而生

结果是什么?

瞬间涌入 10 万条 JSON 消息,RabbitMQ 能稳稳接住,不崩、不丢、不卡死。

这才是它立住的根本。没有这个底座,后面所有"灵活机制"都是空谈。

好,直接上干货。按你的风格:不绕弯,抓本质,讲场景


一、交换机:消息的"分拣员"

交换机就干一件事:接收消息,决定往哪个队列扔

就这么简单。但因为业务场景不同,所以有了 4 种分拣策略。


1. Direct Exchange ------ 精准投递

设计逻辑:一对一,精确匹配 Routing Key。

怎么玩

java 复制代码
// 生产者
channel.basicPublish("order_exchange", "order.create", null, message.getBytes());

// 绑定
channel.queueBind("order_create_queue", "order_exchange", "order.create");
channel.queueBind("order_cancel_queue", "order_exchange", "order.cancel");

场景

  • 订单创建 → 进 order.create 队列
  • 订单取消 → 进 order.cancel 队列
  • 支付成功 → 进 payment.success 队列

一句话点对点,谁的消息进谁的队列


2. Fanout Exchange ------ 广播分发

设计逻辑 :不管你叫啥,绑了就发。无视 Routing Key

怎么玩

java 复制代码
// 生产者
channel.basicPublish("log_exchange", "", null, logMessage.getBytes());
// Routing Key 写空都行,反正不看

// 绑定(多个队列)
channel.queueBind("log_queue_1", "log_exchange", "");
channel.queueBind("log_queue_2", "log_exchange", "");
channel.queueBind("log_queue_3", "log_exchange", "");

场景

  • 系统日志 → 同时发给日志服务、监控服务、审计服务
  • 用户注册事件 → 同时通知邮件服务、短信服务、积分服务
  • 配置变更 → 广播给所有微服务实例

一句话一发多收,谁绑了谁拿


3. Topic Exchange ------ 模糊匹配

设计逻辑 :Routing Key 支持通配符,* 匹配一个单词,# 匹配多个单词。

怎么玩

java 复制代码
// Routing Key 格式:order.create.us / order.cancel.cn / payment.success

// 绑定
channel.queueBind("us_order_queue", "topic_exchange", "order.*.us");
channel.queueBind("all_order_queue", "topic_exchange", "order.#");
channel.queueBind("payment_queue", "topic_exchange", "payment.*");

场景

  • order.create.us → 美国订单队列
  • order.create.cn → 中国订单队列
  • order.# → 所有订单(不管哪个国家、哪个操作)
  • payment.success / payment.fail → 支付相关队列

一句话多维度分类,灵活路由


4. Headers Exchange ------ 属性匹配

设计逻辑:不看 Routing Key,看消息头(headers)里的属性。

怎么玩

java 复制代码
// 消息头
Map<String, Object> headers = new HashMap<>();
headers.put("type", "order");
headers.put("region", "us");

AMQP.BasicProperties props = new AMQP.BasicProperties.Builder()
    .headers(headers)
    .build();

channel.basicPublish("headers_exchange", "", props, message.getBytes());

// 绑定(匹配 headers)
Map<String, Object> bindingArgs = new HashMap<>();
bindingArgs.put("x-match", "all"); // all=全匹配,any=任一匹配
bindingArgs.put("type", "order");
bindingArgs.put("region", "us");

channel.queueBind("us_order_queue", "headers_exchange", "", bindingArgs);

场景

  • 消息需要多个维度筛选(如:类型=订单 AND 地区=美国)
  • Routing Key 太复杂,不如用 headers 灵活定义

一句话用消息头做路由条件,适合复杂匹配


交换机对比表

交换机类型 匹配方式 灵活性 典型场景
Direct 精确匹配 Routing Key 点对点任务分发
Fanout 无视 Routing Key,全广播 最低 日志、事件通知
Topic 通配符匹配 Routing Key 多维度消息分类
Headers 匹配消息头属性 最高 复杂路由条件

二、队列:消息的"仓库"

队列的本质就一个:存消息,等消费

但为了应对不同场景,队列有了不同的"特性配置"。


1. 普通队列 ------ 默认形态

特性

  • 非持久化(服务重启就清空)
  • 无 TTL(消息永不过期)
  • 无优先级

场景

  • 临时任务
  • 测试环境
  • 不重要的通知

一句话最简单,用完就扔


2. 持久化队列 ------ 保命配置

特性

java 复制代码
// 声明队列时设置 durable=true
channel.queueDeclare("order_queue", true, false, false, null);
  • 队列元数据持久化(服务重启,队列还在)
  • 消息也可以持久化(发布时设置 MessageProperties.PERSISTENT_TEXT_PLAIN

场景

  • 订单数据
  • 支付信息
  • 任何不能丢的消息

一句话服务挂了,消息还在


3. 优先级队列 ------ 插队机制

特性

java 复制代码
// 声明队列时设置最大优先级
Map<String, Object> args = new HashMap<>();
args.put("x-max-priority", 10); // 优先级范围 0-10
channel.queueDeclare("priority_queue", true, false, false, args);

// 发布消息时设置优先级
AMQP.BasicProperties props = new AMQP.BasicProperties.Builder()
    .priority(9) // 优先级越高,越先被消费
    .build();

场景

  • VIP 用户订单优先处理
  • 紧急任务插队
  • 系统告警优先推送

一句话重要的消息,先处理


4. 死信队列(DLQ) ------ 垃圾回收站

特性

  • 正常队列处理失败的消息,自动转入死信队列
  • 触发条件:
    • 消息被拒绝(basic.reject / basic.nack
    • 消息 TTL 过期
    • 队列达到最大长度
java 复制代码
// 声明正常队列,绑定死信队列
Map<String, Object> args = new HashMap<>();
args.put("x-dead-letter-exchange", "dlx_exchange");
args.put("x-dead-letter-routing-key", "dead_letter");

channel.queueDeclare("normal_queue", true, false, false, args);

场景

  • 消息处理失败,需要人工介入
  • 超时未处理的消息归档
  • 异常消息追踪与重试

一句话处理不了的,先扔一边,别堵着


5. 延迟队列 ------ 定时炸弹

特性

  • 需要安装插件:rabbitmq_delayed_message_exchange
  • 消息发布时设置延迟时间,到期后才投递到队列
java 复制代码
// 声明延迟交换机
Map<String, Object> args = new HashMap<>();
args.put("x-delayed-type", "direct");
channel.exchangeDeclare("delay_exchange", "x-delayed-message", true, false, args);

// 发布延迟消息
AMQP.BasicProperties props = new AMQP.BasicProperties.Builder()
    .headers(Collections.singletonMap("x-delay", 60000)) // 延迟 60 秒
    .build();

channel.basicPublish("delay_exchange", "delay_queue", props, message.getBytes());

场景

  • 订单 30 分钟未支付自动取消
  • 预约提醒(提前 1 小时通知)
  • 定时任务调度

一句话到点再处理,不用自己写定时器


6. 镜像队列 ------ 高可用保障

特性

  • 队列数据在集群多个节点间同步
  • 主节点挂了,从节点自动接管
bash 复制代码
# 通过策略设置镜像
rabbitmqctl set_policy ha-all "^" '{"ha-mode":"all"}'

场景

  • 金融交易系统
  • 核心业务队列
  • 不能容忍单点故障的场景

一句话一个挂了,还有备份


队列特性对比表

队列类型 核心特性 适用场景
普通队列 非持久化,简单 临时任务、测试
持久化队列 服务重启不丢数据 订单、支付等核心业务
优先级队列 消息可插队 VIP 任务、紧急告警
死信队列 处理失败消息归档 异常追踪、重试机制
延迟队列 消息延迟投递 订单超时、定时提醒
镜像队列 多节点数据同步 高可用、金融级系统

三、为什么这么设计?

一句话总结

交换机解决"往哪发",队列解决"怎么存"

交换机的设计逻辑:

问题 解决方案
消息太多,不能都进一个队列 Direct 精准分流
一个消息要通知多个服务 Fanout 广播
消息维度多,需要灵活分类 Topic 通配符匹配
路由条件复杂,Routing Key 不够用 Headers 属性匹配

队列的设计逻辑:

问题 解决方案
服务挂了,消息不能丢 持久化队列
重要消息要优先处理 优先级队列
处理失败的消息不能堵着 死信队列
需要延迟处理 延迟队列
不能容忍单点故障 镜像队列

四、完整示例:电商系统消息架构

java 复制代码
// ====== 交换机声明 ======
// Topic 交换机:处理订单相关消息
channel.exchangeDeclare("order_topic_exchange", "topic");

// Fanout 交换机:广播日志
channel.exchangeDeclare("log_fanout_exchange", "fanout");

// ====== 队列声明 ======
// 持久化队列:订单创建
channel.queueDeclare("order_create_queue", true, false, false, null);
channel.queueBind("order_create_queue", "order_topic_exchange", "order.create.*");

// 持久化队列:订单取消
channel.queueDeclare("order_cancel_queue", true, false, false, null);
channel.queueBind("order_cancel_queue", "order_topic_exchange", "order.cancel.*");

// 死信队列配置
Map<String, Object> dlqArgs = new HashMap<>();
dlqArgs.put("x-dead-letter-exchange", "dlx_exchange");
dlqArgs.put("x-message-ttl", 60000); // 1分钟超时
channel.queueDeclare("order_process_queue", true, false, false, dlqArgs);

// 延迟队列:30分钟未支付自动取消
Map<String, Object> delayArgs = new HashMap<>();
delayArgs.put("x-delayed-type", "direct");
channel.exchangeDeclare("delay_exchange", "x-delayed-message", true, false, delayArgs);
channel.queueDeclare("order_timeout_queue", true, false, false, null);
channel.queueBind("order_timeout_queue", "delay_exchange", "order.timeout");

// ====== 发布消息 ======
// 订单创建
channel.basicPublish("order_topic_exchange", "order.create.us", 
    MessageProperties.PERSISTENT_TEXT_PLAIN, 
    orderJson.getBytes());

// 延迟消息:30分钟后检查是否支付
AMQP.BasicProperties delayProps = new AMQP.BasicProperties.Builder()
    .headers(Collections.singletonMap("x-delay", 1800000)) // 30分钟
    .build();
channel.basicPublish("delay_exchange", "order.timeout", delayProps, orderId.getBytes());

五、一句话收尾

交换机是路由规则,队列是存储策略

4 种交换机应对 4 种分发需求,6 种队列特性应对 6 种存储场景。

组合起来,就能覆盖 99% 的业务需求。


需要我把这部分扩展成完整章节,或者加更多实际代码示例吗?

相关推荐
你才是臭弟弟4 小时前
SpringBoot 集成MinIo(根据上传文件.后缀自动归类)
java·spring boot·后端
what丶k5 小时前
SpringBoot3 配置文件使用全解析:从基础到实战,解锁灵活配置新姿势
java·数据库·spring boot·spring·spring cloud
RwTo5 小时前
【源码】- SpringBoot启动
java·spring boot·spring
Elieal6 小时前
JWT 登录校验机制:5 大核心类打造 Spring Boot 接口安全屏障
spring boot·后端·安全
czlczl200209256 小时前
Spring Boot Filter :doFilter 与 doFilterInternal 的差异
java·spring boot·后端
码界奇点6 小时前
基于Spring Boot和Activiti6的工作流OA系统设计与实现
java·spring boot·后端·车载系统·毕业设计·源代码管理
yangminlei6 小时前
Spring Boot拦截器(Interceptor)与过滤器(Filter)深度解析:区别、实现与实战指南
java·spring boot·后端
czlczl200209256 小时前
Spring Boot :彻底解决 HttpServletRequest 输入流只能读取一次的问题
java·spring boot·后端
小信丶6 小时前
@MappedJdbcTypes 注解详解:应用场景与实战示例
java·数据库·spring boot·后端·mybatis
奋进的芋圆7 小时前
Spring Boot 3 高并发事务与分布式事务企业级完整解决方案
spring boot·分布式