当前位置:首页 > 资讯列表 >RabbitMQ Fanout Exchange:实现消息的全量广播

RabbitMQ Fanout Exchange:实现消息的全量广播

发布时间:2026-07-09 12:03:37 分类:营销学堂

背景:为什么需要Fanout模式?

前面我们了解了RabbitMQ的基本安装和简单消息队列的使用后,我们自然会遇到一个新的问题:如何将同一条消息,同时发送给多个消费者?

在实际开发中,这种需求非常普遍。例如:

如果采用前面学习的基本队列模式,每条消息只能被一个消费者获取,无法实现“一对多”的分发。这时,就需要用到RabbitMQ中的Fanout(广播)模式

Fanout模式是RabbitMQ中一种简单而强大的交换机(Exchange) 类型。它的核心逻辑是:将接收到的消息,无条件地广播给所有绑定的队列。就像一个广播电台,发射的信号可以被任何打开收音机并调对频道的听众接收,每个听众都会收到完整的信号。

核心原理:Fanout模式的工作流程

在Fanout模式下,消息的流转遵循“生产者 → 交换机 → 多个队列 → 多个消费者”的路径。

  1. 生产者:只负责将消息发送到指定的交换机(Exchange),并不关心消息最终被谁消费。

  2. 交换机(Fanout类型):收到消息后,会将其复制并转发到所有与其绑定(Bind) 的队列中。

  3. 队列:每个队列都会收到一份完整的消息副本。

  4. 消费者:每个消费者只监听属于自己的队列。当多个消费者监听同一个队列时,它们之间依然是竞争关系(一条消息只被其中一个消费者获取)。但在Fanout模式下,我们通常让每个消费者独占一个队列,从而实现“消息被每个消费者都收到一次”的效果。

因此,Fanout模式非常适合用于广播通知日志分发事件驱动的场景。

代码实践:用PHP实现Fanout模式

在开始之前,请确保你的PHP项目已经通过Composer安装了RabbitMQ扩展(php-amqplib/php-amqplib)。

1. 生产者:publish.php

生产者负责创建Fanout交换机并发送消息。

php
<?php
require_once __DIR__ . '/vendor/autoload.php';

use PhpAmqpLib\Connection\AMQPStreamConnection;
use PhpAmqpLib\Message\AMQPMessage;

// 连接配置(请替换为你的实际信息)
$dbName = 'sanqing';
$dbPwd = '111111';
$tableName = 'order';

$connection = new AMQPStreamConnection('localhost', 5672, $dbName, $dbPwd, $tableName);
$channel = $connection->channel();

// 声明一个Fanout类型的交换机,名为 'exch'
$exc_name = 'exch';
$channel->exchange_declare($exc_name, 'fanout', false, false, false);

// 发送消息到交换机
$data = 'this is fanout message';
$msg = new AMQPMessage($data, ['delivery_mode' => AMQPMessage::DELIVERY_MODE_PERSISTENT]);
$channel->basic_publish($msg, $exc_name);

// 注意:这里没有指定队列,因为消息是发给交换机的

echo " [x] 消息已发送:", $data, "\n";

$channel->close();
$connection->close();

2. 消费者:sub.php

消费者负责创建队列,并将队列绑定到交换机,然后接收消息。为了演示广播效果,你可以复制此文件为sub2.php并同时运行。

php
<?php
require_once __DIR__ . '/vendor/autoload.php';

use PhpAmqpLib\Connection\AMQPStreamConnection;

// 连接配置(请与生产者保持一致)
$dbName = 'sanqing';
$dbPwd = '111111';
$tableName = 'order';

$connection = new AMQPStreamConnection('localhost', 5672, $dbName, $dbPwd, $tableName);
$channel = $connection->channel();

// 声明要绑定的Fanout交换机
$exc_name = 'exch';
$channel->exchange_declare($exc_name, 'fanout', false, false, false);

// 创建一个临时队列(名称为空,RabbitMQ会自动生成一个随机名称)
// 此队列会在消费者断开连接时自动删除
list($queue_name, ,) = $channel->queue_declare('', false, false, true, false);

// 将队列绑定到交换机
$channel->queue_bind($queue_name, $exc_name);

echo " [*] 等待消息。要退出请按 CTRL+C\n";

// 定义消息处理回调
$callback = function ($msg) {
    echo ' [x] 收到消息:', $msg->body, "\n";
    $msg->ack(); // 确认消息已处理
};

// 设置同时只处理一条消息
$channel->basic_qos(null, 1, null);
$channel->basic_consume($queue_name, '', false, false, false, false, $callback);

// 循环等待消息
while ($channel->is_open()) {
    $channel->wait();
}

$channel->close();
$connection->close();

3. 运行测试

  1. 打开两个终端窗口,分别运行:

    bash
    php sub.php

    bash
    php sub2.php
  2. 再打开一个终端窗口,运行生产者:

    bash
    php publish.php

你会看到两个消费者窗口同时打印出 [x] 收到消息:this is fanout message,这表明同一条消息被成功广播给了所有绑定的消费者。

总结

通过本次实践,我们掌握了RabbitMQ中Fanout(广播)模式的核心概念与用法。



关键点说明
核心思想一对多广播,消息到达交换机后,会被复制并转发给所有绑定的队列。
适用场景适用于需要将事件或通知同时通知给多个独立服务的场景。
关键代码生产者:exchange_declare 设置交换机类型为 fanout。消费者:queue_declare 创建临时队列,并通过 queue_bind 将其绑定到交换机。

Fanout模式极大地增强了消息队列的灵活性,是构建可扩展、松耦合系统的重要工具。理解并灵活运用它,可以帮助我们更优雅地处理分布式系统中的通信问题。

希望这个例子能帮助你快速上手RabbitMQ的Fanout模式。