RabbitMQ相关信息及使用指南

RabbitMQ 是基于高级消息队列协议(AMQP)的消息队列系统,擅长低延迟、高可用的消息传递。

如何使用

  1. 下载依赖

  2. 启动服务与网页管理

    • 开启 RabbitMQ 服务:在 cmd 管理员模式下执行 net start RabbitMQ
    • 开启 RabbitMQ 网页管理:在 cmd 管理员模式下执行 rabbitmq-plugins enable rabbitmq_management
    • 访问:重新打开浏览器,访问 http://localhost:15672,用户名:guest,密码:guest
  3. 使用说明

    • 正式使用时,生产者和消费者都需要创建队列、创建交换机,并绑定路由。
    • 若未指定交换机和绑定路由,直接创建队列,RabbitMQ 会走默认交换机。默认交换机会将消息路由到队列名称与路由键相同的队列,优点是快速开发,缺点是灵活性差,无法利用死信队列、延迟队列等高级特性。

如何保证 RabbitMQ 消息的可靠性?

  • 生产者端 :开启发布确认(confirmSelect()),通过回调确认消息到达交换机。

  • Broker 端

    • 持久化交换机(durable=true
    • 持久化队列(durable=true
    • 持久化消息(delivery_mode=2
  • 消费者端

    • 手动 Ack,关闭自动确认(auto_ack=false
    • 处理完成后调用 basic_ack,避免消费中途失败导致消息丢失
    • 利用死信队列

死信队列的用途及实现方式?

  • 用途

    • 处理消费失败的信息
    • 处理超时未消费的信息
    • 实现消息重试机制
  • 实现方式

    1. 声明死信交换机和队列:

      bash 复制代码
      $channel->exchange_declare('dlx_exchange', 'direct', false, true, false);
      $channel->queue_declare('dlx_queue', false, true, false, false);
      $channel->queue_bind('dlx_queue', 'dlx_exchange', 'dlx_key');
    2. 源队列绑定死信配置:

      dart 复制代码
      $channel->queue_declare('source_queue', false, true, false, false, false, [
          'x-dead-letter-exchange' => 'dlx_exchange', // 死信交换机
          'x-dead-letter-routing-key' => 'dlx_key', // 死信路由键
          'x-message-ttl' => 60000 // 消息存活时间(毫秒)
      ]);
    3. 消费者监听死信队列:

      php 复制代码
      $channel->basic_consume('dlx_queue', '', false, true, false, false, $callback); // 自动确认,直接记录日志或人工处理
  • 场景举例:订单支付超时未完成,将消息放入死信队列,触发自动取消订单或人工跟进。

如何实现延迟队列,有哪些方案?

  1. TTL + 死信队列组合 :通过 x-message-ttlx-expires 设置消息 / 队列过期时间,过期后自动转入死信队列触发消费。

  2. 使用 rabbitmq_delayed_message_exchange 插件

    php 复制代码
    $channel->exchange_declare('delayed_exchange', 'x-delayed-message', false, true, false, false, [
        'x-delayed-type' => 'direct' // 支持 direct/fanout/topic 类型
    ]);
    $msg = new AMQPMessage('delayed message', ['x-delay' => 5000]); // 5秒延迟
    $channel->basic_publish($msg, 'delayed_exchange', 'delay_key');

使用 Demo(PHP + ThinkPHP)

php 复制代码
namespace app\controller;

use PhpAmqpLib\Connection\AMQPStreamConnection;
use PhpAmqpLib\Message\AMQPMessage;
use think\facade\Log;

class RabbitMQDemo
{
    private $connection;
    private $channel;
    static $data = [];

    public function __construct()
    {
        try {
            // 创建连接 - 使用新版本的连接方式
            $this->connection = new AMQPStreamConnection(
                'localhost',     // host
                5672,           // port
                'guest',        // user
                'guest',        // password
                '/',            // vhost
                false,          // insist
                'AMQPLAIN',     // login_method
                null,           // login_response
                'en_US',        // locale
                3.0,            // connection_timeout
                3.0,            // read_write_timeout
                null,           // context
                false,          // keepalive
                0               // heartbeat
            );
            $this->channel = $this->connection->channel();
        } catch (\Exception $e) {
            Log::error('RabbitMQ连接失败:' . $e->getMessage());
            throw $e;
        }
    }

    /**
     * 发送消息
     */
    public function send()
    {
        try {
            $exchange = 'my_exchange';
            $queue = 'hello';
            $routing_key = 'my_routing_key';
            // 声明交换机
            $this->channel->exchange_declare($exchange, 'direct', false, true, false);

            // 声明队列
            $this->channel->queue_declare($queue, false, true, false, false);

            // 绑定队列跟交换机
            $this->channel->queue_bind($queue, $exchange, $routing_key);

            // 准备消息
            $message = [
                'id' => uniqid(),
                'time' => date('Y-m-d H:i:s'),
                'data' => 'Hello World!s'
            ];

            // 创建消息对象
            $msg = new AMQPMessage(
                json_encode($message),
                ['delivery_mode' => AMQPMessage::DELIVERY_MODE_PERSISTENT]
            );

            // 发送消息
            $this->channel->basic_publish($msg, $exchange, $routing_key);

            // 关闭连接
            $this->channel->close();
            $this->connection->close();

            return json(['code' => 200, 'msg' => '消息发送成功', 'data' => $message]);
        } catch (\Exception $e) {
            Log::error('发送消息失败:' . $e->getMessage());
            return json(['code' => 500, 'msg' => '发送消息失败:' . $e->getMessage()]);
        }
    }

    /**
     * 接收消息
     */
    public function receive()
    {
        try {
            $exchange = 'my_exchange';
            $queue = 'hello';
            $routing_key = 'my_routing_key';
            // 声明交换机
            $this->channel->exchange_declare($exchange, 'direct', false, true, false);

            // 声明队列
            $this->channel->queue_declare($queue, false, true, false, false);

            // 绑定队列跟交换机
            $this->channel->queue_bind($queue, $exchange, $routing_key);

            // 设置每次只处理一条消息
            $this->channel->basic_qos(null, 1, null);

            // 获取队列中的消息数量
            $queueInfo = $this->channel->queue_declare($queue, false, true, false, false);
            $messageCount = $queueInfo[1]; // 队列中的消息数量

            if ($messageCount == 0) {
                $this->channel->close();
                $this->connection->close();
                return json(['code' => 200, 'msg' => '队列中没有消息', 'count' => 0]);
            }

            $data = [];
            // 定义回调函数
            $callback = function($msg) {
                $data = json_decode($msg->body, true);
                self::$data = $data;
                Log::info('收到消息:' . json_encode($data, JSON_UNESCAPED_UNICODE));

                // 确认消息已处理
                $msg->ack();
            };

            // 开始消费
            $this->channel->basic_consume($queue, '', false, false, false, false, $callback);

            // 只等待一条消息,设置超时时间
            try {
                $this->channel->wait(null, true, 2); // 等待2秒
            } catch (\PhpAmqpLib\Exception\AMQPTimeoutException $e) {
                // 超时处理
                Log::info('等待消息超时');
            }

            // 关闭连接
            $this->channel->close();
            $this->connection->close();

            return json([
                'code' => 200,
                'msg' => '消息接收完成',
                'count' => $messageCount,
                'data' =>  self::$data,
                'received' => true
            ]);
        } catch (\Exception $e) {
            Log::error('接收消息失败:' . $e->getMessage());
            return json(['code' => 500, 'msg' => '接收消息失败:' . $e->getMessage()]);
        }
    }
        
} 
相关推荐
努力的小雨6 小时前
还在为调试提示词头疼?一个案例教你轻松上手!
后端
魔都吴所谓6 小时前
【go】语言的匿名变量如何定义与使用
开发语言·后端·golang
陈佬昔没带相机7 小时前
围观前后端对接的 TypeScript 最佳实践,我们缺什么?
前端·后端·api
Livingbody8 小时前
大模型微调数据集加载和分析
后端
Livingbody8 小时前
第一次免费使用A800显卡80GB显存微调Ernie大模型
后端
Goboy9 小时前
Java 使用 FileOutputStream 写 Excel 文件不落盘?
后端·面试·架构
Goboy9 小时前
讲了八百遍,你还是没有理解CAS
后端·面试·架构
麦兜*10 小时前
大模型时代,Transformer 架构中的核心注意力机制算法详解与优化实践
jvm·后端·深度学习·算法·spring·spring cloud·transformer
树獭叔叔10 小时前
Python 多进程与多线程:深入理解与实践指南
后端·python
阿华的代码王国10 小时前
【Android】PopupWindow实现长按菜单
android·xml·java·前端·后端