当前位置: 首页 > news >正文

深入浅出 RabbitMQ - 主题模式(Topic)

大家好,我是工藤学编程 🦉一个正在努力学习的小博主,期待你的关注
实战代码系列最新文章😉C++实现图书管理系统(Qt C++ GUI界面版)
SpringBoot实战系列🐷【SpringBoot实战系列】SpringBoot3.X 整合 MinIO 存储原生方案
分库分表分库分表之实战-sharding-JDBC分库分表执行流程原理剖析
消息队列深入浅出 RabbitMQ-路由模式详解

前情摘要:

1、深入浅出 RabbitMQ-核心概念介绍与容器化部署
2、深入浅出 RabbitMQ-简单队列实战
3、深入浅出 RabbitMQ-工作队列实战(轮训策略VS公平策略)
4、深入浅出 RabbitMQ-交换机详解与发布订阅模型实战
4、深入浅出 RabbitMQ-路由模式详解


【亲测宝藏】发现一个让 AI 学习秒变轻松的神站!不用啃高数、不用怕编程,高中生都能看懂的人工智能教程来啦!

👉点击跳转,和 thousands of 小伙伴一起用快乐学习法征服 AI,说不定下一个开发出爆款 AI 程序的就是你!


本文章目录

      • 深入浅出 RabbitMQ-主题模式(Topic):通配符带来的灵活消息分发
        • 一、为什么需要主题模式?
        • 二、什么是主题模式?
        • 三、通配符匹配规则实战解析
        • 四、经典应用场景:精细化日志系统
        • 五、代码实战:实现多维度日志分发
          • 1. 生产者:发送带结构化路由键的日志
          • 2. 消费者1:接收订单系统所有日志(order.log.#)
          • 3. 消费者2:接收所有系统的 error 日志(*.log.error)
        • 六、运行效果与核心优势
        • 七、RabbitMQ 五种工作模式总结
        • 八、总结

深入浅出 RabbitMQ-主题模式(Topic):通配符带来的灵活消息分发

在 RabbitMQ 的消息分发机制中,如果你觉得路由模式(Direct)的精确匹配不够灵活,又嫌发布订阅模式(Fanout)的广播太过“粗放”,那么主题模式(Topic) 一定是你的理想选择。它像一把“瑞士军刀”,通过通配符匹配实现了更精细、更灵活的消息路由,几乎能满足大多数复杂业务场景的需求。

一、为什么需要主题模式?

先来看一个实际问题:如果你的系统中有上百种消息类型,每种类型对应一个路由键(Routing Key),用路由模式(Direct)需要为每个路由键手动绑定队列,维护成本会非常高。比如日志系统中,可能有 order.log.erroruser.log.infoproduct.log.debug 等成百上千种路由键,总不能逐个绑定吧?

主题模式应运而生:它通过「通配符匹配」替代精确匹配,让队列只需绑定一个或几个带通配符的路由键,就能匹配一类消息,极大减少了绑定工作量,同时保留了消息定向分发的灵活性。

二、什么是主题模式?

主题模式是 RabbitMQ 中最灵活的消息分发模式,核心是基于通配符的路由键(Routing Key)匹配。其关键特性如下:

  • 交换机类型:必须使用 Topic 类型(主题交换机)。
  • 路由键格式:路由键由多个“词”组成,词之间用 . 分隔(如 order.log.error,其中 orderlogerror 是三个词)。
  • 通配符规则:队列与交换机绑定时,Binding Key 可使用通配符:
    • *:匹配恰好1个词(如 *.log.error 可匹配 order.log.error,但不能匹配 user.system.log.error)。
    • #:匹配1个或多个词(如 order.log.# 可匹配 order.log.errororder.log.info.debug 等)。
  • 转发逻辑:Topic 交换机会将消息的 Routing Key 与队列的 Binding Key 进行通配符匹配,匹配成功则转发消息。
三、通配符匹配规则实战解析

光说规则太抽象,我们用几个例子直观感受下(假设消息的 Routing Key 如下,队列的 Binding Key 为 Q1: *.log.*Q2: order.log.#):

消息 Routing Key是否匹配 Q1(.log.是否匹配 Q2(order.log.#)结果总结
order.log.error是(order 匹配 *)是(# 匹配 error)同时进入 Q1 和 Q2
user.log.info是(user 匹配 *)否(前缀不是 order)仅进入 Q1
order.log.debug.warn否(超过3个词)是(# 匹配 debug.warn)仅进入 Q2
product.error否(没有 log 词)否(前缀不是 order)不匹配任何队列,默认被丢弃

注意:如果消息的 Routing Key 没有匹配到任何队列,Topic 交换机会默认丢弃消息(可通过设置「返回回调」监听未被路由的消息,进行二次处理)。

四、经典应用场景:精细化日志系统

主题模式最典型的场景是日志分级分类处理,比如:

  • 需求1:收集所有系统的 error 级别日志(用于告警),Binding Key 可设为 *.log.error
  • 需求2:收集订单系统的所有级别日志(用于订单问题排查),Binding Key 可设为 order.log.#
  • 需求3:收集所有系统的所有日志(用于全局存储),Binding Key 可设为 #.log.#

只需一个 Topic 交换机,就能通过不同通配符绑定,实现多维度的日志分发,远比路由模式更简洁。

五、代码实战:实现多维度日志分发

下面用 Java 代码演示主题模式的完整流程(基于 RabbitMQ Java Client 5.x)。

1. 生产者:发送带结构化路由键的日志
public class LogProducer {private static final String EXCHANGE_NAME = "log_topic_exchange";public static void main(String[] args) throws Exception {// 1. 配置连接工厂ConnectionFactory factory = new ConnectionFactory();factory.setHost("192.168.229.128");factory.setUsername("admin");factory.setPassword("password");factory.setVirtualHost("/dev");factory.setPort(5672);// 2. 建立连接和信道try (Connection connection = factory.newConnection();Channel channel = connection.createChannel()) {// 3. 声明 Topic 交换机channel.exchangeDeclare(EXCHANGE_NAME, BuiltinExchangeType.TOPIC);// 4. 发送不同类型的日志(路由键格式:[系统名].[日志类型].[级别])String orderErrorLog = "订单系统:支付超时";String orderInfoLog = "订单系统:新订单创建";String productDebugLog = "商品系统:库存查询SQL执行";// 5. 指定具体的 Routing Key(无通配符)channel.basicPublish(EXCHANGE_NAME, "order.log.error", null, orderErrorLog.getBytes());channel.basicPublish(EXCHANGE_NAME, "order.log.info", null, orderInfoLog.getBytes());channel.basicPublish(EXCHANGE_NAME, "product.log.debug", null, productDebugLog.getBytes());System.out.println("日志消息发送完成");}}
}
2. 消费者1:接收订单系统所有日志(order.log.#)
public class OrderLogConsumer {private static final String EXCHANGE_NAME = "log_topic_exchange";public static void main(String[] args) throws Exception {// 连接配置同生产者ConnectionFactory factory = new ConnectionFactory();factory.setHost("192.168.229.128");// ...省略其他配置Connection connection = factory.newConnection();Channel channel = connection.createChannel();// 声明交换机(与生产者一致)channel.exchangeDeclare(EXCHANGE_NAME, BuiltinExchangeType.TOPIC);// 创建临时队列,绑定通配符 Binding Key:order.log.#String queueName = channel.queueDeclare().getQueue();channel.queueBind(queueName, EXCHANGE_NAME, "order.log.#");// 消费消息(订单系统日志处理逻辑)DeliverCallback callback = (consumerTag, delivery) -> {String message = new String(delivery.getBody(), "UTF-8");System.out.println("[订单日志服务] 收到:" + message + "(路由键:" + delivery.getEnvelope().getRoutingKey() + ")");};channel.basicConsume(queueName, true, callback, consumerTag -> {});}
}
3. 消费者2:接收所有系统的 error 日志(*.log.error)
public class ErrorAlertConsumer {private static final String EXCHANGE_NAME = "log_topic_exchange";public static void main(String[] args) throws Exception {// 连接配置同生产者ConnectionFactory factory = new ConnectionFactory();// ...省略其他配置Connection connection = factory.newConnection();Channel channel = connection.createChannel();channel.exchangeDeclare(EXCHANGE_NAME, BuiltinExchangeType.TOPIC);String queueName = channel.queueDeclare().getQueue();// 绑定通配符 Binding Key:*.log.errorchannel.queueBind(queueName, EXCHANGE_NAME, "*.log.error");// 消费消息(错误告警逻辑)DeliverCallback callback = (consumerTag, delivery) -> {String message = new String(delivery.getBody(), "UTF-8");System.out.println("[告警服务] 紧急!" + message + "(路由键:" + delivery.getEnvelope().getRoutingKey() + ")");};channel.basicConsume(queueName, true, callback, consumerTag -> {});}
}
六、运行效果与核心优势
  • 生产者发送3条消息后:

    • 「订单日志服务」会收到 order.log.errororder.log.info(匹配 order.log.#)。
    • 「告警服务」只会收到 order.log.error(匹配 *.log.error)。
    • product.log.debug 因无匹配队列,默认被丢弃(可通过回调处理)。
  • 核心优势:

    1. 灵活性:通配符匹配覆盖多种场景,减少绑定工作量。
    2. 兼容性:可模拟 Fanout(用 # 匹配所有)和 Direct(用具体路由键)的功能。
    3. 可扩展性:新增消息类型时,无需修改现有绑定,只需按规则定义路由键即可。
七、RabbitMQ 五种工作模式总结

学到这里,我们已经掌握了 RabbitMQ 的核心工作模式,这里用一张表总结它们的区别:

模式交换机类型路由键(Routing Key)使用方式核心场景特点总结
简单模式默认交换机无需指定(队列名即路由键)一对一消息传递最简单,无交换机配置
工作队列默认交换机无需指定(队列名即路由键)多消费者分摊任务支持轮训/公平分发策略
发布订阅Fanout无需指定(忽略路由键,广播所有队列)消息通知、日志广播所有绑定队列都能收到消息
路由模式Direct精确匹配(消息路由键 = 队列绑定键)按类型分发(如 error/info)精准匹配,适合少量固定类型
主题模式Topic通配符匹配(* 匹配1个词,# 匹配多个词)复杂分类场景(如多系统日志)最灵活,支持规则化匹配
八、总结

主题模式(Topic)凭借通配符匹配的特性,成为 RabbitMQ 中应用最广泛的模式之一。它既解决了路由模式(Direct)绑定繁琐的问题,又弥补了发布订阅模式(Fanout)无法精确筛选的缺陷,几乎能应对所有需要“规则化消息分发”的场景。

掌握主题模式的关键,在于理解 *# 的区别,以及路由键的结构化设计(建议按业务维度用 . 分隔,如 系统.模块.操作)。下次开发时,不妨优先考虑主题模式——它可能就是你寻找的“万能方案”。

觉得有用请点赞收藏!
如果有相关问题,欢迎评论区留言讨论~

http://www.dtcms.com/a/317163.html

相关文章:

  • JavaWeb(04)
  • 丝滑qt页面跳转
  • android10~16变更一览和开发者兼容应对
  • 学习 Android(十五)NDK进阶及性能优化
  • antd组件select下拉数据分页加载
  • 学习 Android (十六) 学习 OpenCV (一)
  • Cglib的Enhancer实现动态代理?
  • 新能源汽车热管理系统核心零部件及工作原理详解
  • AI巨模型对决2025:五强争霸,谁能称王?
  • ORACLE 19C建库时卡在46%、36%
  • 【网络运维】Linux:简单DHCP服务器的部署
  • PyTorch入门引导
  • 识别 Base64 编码的 JSON、凭证和私钥
  • 接口自动化测试用例详解
  • 使用python与streamlit构建的空间微生物分析
  • RabbitMQ 全面指南:从基础概念到高级特性实现
  • 控制服务和守护进程-systemctl
  • python学智能算法(三十四)|SVM-KKT条件回顾
  • 系统的缓存(buff/cache)是如何影响系统性能的?
  • 【学习笔记之redis】删除缓存
  • 【Redis】hash哈希,List列表
  • app-3
  • Python day36
  • Java Stream API 详解(Java 8+)
  • IP与MAC地址的区别解析
  • 数据仓库命名规范
  • AS32S601 芯片 ADC 模块交流耦合测试:技术要点与实践
  • 使用 gptqmodel 量化 Qwen3-Coder-30B-A3B-Instruct
  • 大型音频语言模型论文总结
  • 【前端开发】三. JS运算符