RabbitMQ 工作模式介绍

这篇具有很好参考价值的文章主要介绍了RabbitMQ 工作模式介绍。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

RabbitMQ 工作模式介绍

1.Hello World

RabbitMQ 是一个消息代理:它接受并转发消息。您可以将其视为邮局:当您将要邮寄的邮件放入邮箱时,您可以确定信使最终会将邮件交付给您的收件人。在这个类比中,RabbitMQ是一个邮政信箱,一个邮局和一个信件载体。

RabbitMQ 和邮局之间的主要区别在于它不处理纸张,而是接受、存储和转发二进制数据 - 消息

以下是RabbitMq的专业术语

  • 消费与接受的含义相似。使用者是一个主要等待接收消息的程序

    RabbitMQ 工作模式介绍

  • 生产只意味着发送。发送消息的程序是生产者

    RabbitMQ 工作模式介绍

  • 队列是 RabbitMQ 中邮箱的名称。尽管消息流经 RabbitMQ 和您的应用程序,但它们只能存储在队列中。队列仅受主机内存和磁盘限制的约束,它本质上是一个大型消息缓冲区。许多生产者可以发送到一个队列的消息,许多使用者可以尝试从一个队列接收数据。这就是我们表示队列的方式

    RabbitMQ 工作模式介绍

请注意,生产者、使用者和代理不必驻留在同一个主机上;事实上,在大多数应用程序中,它们不会。应用程序也可以是生产者和使用者

“hello world”
(使用 php-amqplib 客户端)
在本教程的这一部分中,我们将用 PHP 编写两个使用 RabbitMQ 进行通信的程序。本教程使用需要 PHP 7.x 或 8.x 的客户端库。

第一个程序将是发送单个消息的生产者,第二个程序将是接收消息并将其打印出来的消费者。我们将掩盖php-amqplib API中的一些细节,专注于这个非常简单的事情,只是为了开始。这是一个消息传递的“Hello World”。

在下图中,“P”是我们的生产者,“C”是我们的消费者。中间的框是一个队列 - RabbitMQ 代表消费者保留的消息缓冲区。

Sending

RabbitMQ 工作模式介绍

<?php
include "../../vendor/autoload.php";
use PhpAmqpLib\Connection\AMQPStreamConnection;
use PhpAmqpLib\Message\AMQPMessage;

// 创建服务器连接
$connection = new AMQPStreamConnection(
    '127.0.0.1',
    5672,
    'guest',
    'guest',
    '/');
// 创建一个通道,这是大多数用于完成工作的 API 所在的位置
$channel = $connection->channel();
// 要发送,我们必须声明一个队列供我们发送到;然后我们可以向队列发布一条消息:
$channel->queue_declare('hello', false, false, false, false);
// 创建消息
$msg = new AMQPMessage('Hello World!');
// 发送消息
$channel->basic_publish($msg, '', 'hello');
echo " [x] Sent 'Hello World!'\n";
$channel->close();
$connection->close();

Recive

我们的接收器侦听来自 RabbitMQ 的消息,因此与发布单个消息的发布者不同,我们将保持接收器运行以侦听消息并打印出来

RabbitMQ 工作模式介绍

<?php
include "../../vendor/autoload.php";
use PhpAmqpLib\Connection\AMQPStreamConnection;
// 设置与发布者相同;我们打开一个连接和一个通道,并声明我们要从中使用的队列。
// 请注意,这与将发布发送到的队列匹配
$connection = new AMQPStreamConnection('localhost', 5672, 'guest', 'guest');
$channel = $connection->channel();

$channel->queue_declare('hello', false, false, false, false);

echo " [*] Waiting for messages. To exit press CTRL+C\n";

// 我们的代码将阻塞,而我们的$channel有回调。
// 每当我们收到消息时,我们的$callback函数都会传递收到的消息。
$callback = function ($msg) {
    echo ' [x] Received ', $msg->body, "\n";
};

$channel->basic_consume('hello', '', false, true, false, false, $callback);

while ($channel->is_open()) {
    $channel->wait();
}

2. Work Queue

在第一个教程中(hello world),我们编写了程序来发送和接收来自命名队列的消息。在此部分中,我们将创建一个工作队列,用于在多个工作线程之间分配耗时的任务

RabbitMQ 工作模式介绍

工作队列(又名:任务队列)背后的主要思想是避免立即执行资源密集型任务并必须等待其完成。相反,我们将任务安排在以后完成。我们将任务封装为消息并将其发送到队列。在后台运行的工作进程将弹出任务并最终执行作业。当您运行许多工作线程时,任务将在它们之间共享

此概念在 Web 应用程序中特别有用,在这些应用程序中,在短 HTTP 请求窗口期间无法处理复杂任务。

task.php (P)

<?php
// 工作队列 work queue 发送 send
use PhpAmqpLib\Connection\AMQPStreamConnection;
use PhpAmqpLib\Message\AMQPMessage;

include "../../vendor/autoload.php";

// 创建服务器连接
$connection = new AMQPStreamConnection(
    '127.0.0.1',
    5672,
    'guest',
    'guest',
    '/');
// 创建一个通道,这是大多数用于完成工作的 API 所在的位置
$channel = $connection->channel();
// 要发送,我们必须声明一个队列供我们发送到;然后我们可以向队列发布一条消息:
$channel->queue_declare('task_queue', false, false, false, false);
// 创建消息
$data = implode(' ', array_slice($argv, 1));
if (empty($data)) {
    $data = "hello world!";
}
// [
//    'delivery_mode' => AMQPMessage::DELIVERY_MODE_PERSISTENT
//]
$msg = new AMQPMessage($data);
// 发送消息
$channel->basic_publish($msg, '', 'task_queue');
echo " [x] Sent '".$data ."'\n";
$channel->close();
$connection->close();

worker.php (C)

<?php
include "../../vendor/autoload.php";
use PhpAmqpLib\Connection\AMQPStreamConnection;
// 设置与发布者相同;我们打开一个连接和一个通道,并声明我们要从中使用的队列。
// 请注意,这与将发布发送到的队列匹配
$connection = new AMQPStreamConnection('localhost', 5672, 'guest', 'guest');
$channel = $connection->channel();

$channel->queue_declare(
    'task_queue',
    false,
    false,
    false,
    false
);

echo " [*] Waiting for messages. To exit press CTRL+C\n";

$callback = function ($msg) {
    echo ' [x] Received ', $msg->body, "\n";
    sleep(substr_count($msg->body, '.'));
    echo " [x] Done\n";
    // 手动ack
    // $msg->ack();
};
// 公平调度
$channel->basic_qos(null, 1, null);
// 手动ack
// $channel->basic_consume('task_queue', '', false, false, false, false, $callback);
$channel->basic_consume('task_queue', '', false, true, false, false, $callback);

while ($channel->is_open()) {
    $channel->wait();
}

执行结果

# shell1
php task.php First message.
php task.php Second message..
php task.php Third message...
php task.php Fourth message....
php task.php Fifth message.....

# shell2
php worker.php

# => [*] Waiting for messages. To exit press CTRL+C
# => [x] Received 'First message.'
# => [x] Received 'Third message...'
# => [x] Received 'Fifth message.....'

# shell3
php worker.php

# => [*] Waiting for messages. To exit press CTRL+C
# => [x] Received 'Second message..'
# => [x] Received 'Fourth message....'

默认情况下,RabbitMQ 将按顺序将每条消息发送给下一个消费者。平均而言,每个消费者都会收到相同数量的消息。这种分发消息的方式称为轮询。对三个或更多工作人员进行尝试。

消息确认(Confirm)

消息确认以前由我们自己关闭。是时候通过将第四个参数设置为 basic_consume false 来打开它们了(true 表示没有确认),并在我们完成任务后从工作人员发送适当的确认

$callback = function ($msg) {
    echo ' [x] Received ', $msg->body, "\n";
    $msg->ack();
};


$channel->basic_consume('task_queue', '', false, false, false, false, $callback);

使用此代码,可以确保即使在处理消息时使用 CTRL+C 终止工作线程,也不会丢失任何内容。工作线程终止后不久,将重新传递所有未确认的消息

消息持久性(Message Durability)

我们已经学会了如何确保即使消费者死亡,任务也不会丢失。但是如果 RabbitMQ 服务器停止,我们的任务仍然会丢失。

当 RabbitMQ 退出或崩溃时,它会忘记队列和消息,除非您告诉它不要这样做。要确保消息不会丢失,需要做两件事:我们需要将队列和消息都标记为持久

首先,我们需要确保队列在 RabbitMQ 节点重新启动后能够幸存下来

$channel->queue_declare('task_queue', false, true, false, false);

此标志设置为 true 需要同时应用于生产者代码和使用者代码

现在我们需要将我们的消息标记为持久 - 通过设置 delivery_mode = 2 消息属性,AMQPMessage 将其作为属性数组的一部分

$msg = new AMQPMessage( $data, array('delivery_mode' => AMQPMessage::DELIVERY_MODE_PERSISTENT));

公平调度(Fair dispatch)

您可能已经注意到,调度仍然不能完全按照我们想要的方式工作。例如,在有两个工作线程的情况下,当所有奇数消息都很重而偶数消息都很轻时,一个工作人员将一直很忙,而另一个工作人员几乎不会做任何工作。好吧,RabbitMQ 对此一无所知,仍然会均匀地调度消息

RabbitMQ 工作模式介绍

发生这种情况是因为 RabbitMQ 只是在消息进入队列时调度消息。它不会查看使用者的未确认消息数。它只是盲目地将每 n 条消息发送给第 n 个消费者

为了解决这个问题,我们可以将basic_qos方法与 prefetch_count = 1 设置一起使用。这告诉 RabbitMQ 不要一次向一个 worker 提供多条消息。或者,换句话说,在工作人员处理并确认前一条消息之前,不要向工作人员发送新消息。相反,它会将其调度给下一个尚未繁忙的工作人员

$channel->basic_qos(null, 1, null);

3. Publish/Subscribe

在上一教程中,我们创建了一个工作队列。工作队列背后的假设是每个任务只传递给一个工作人员。在这一部分中,我们将做一些完全不同的事情 - 我们将向多个消费者传递消息。此模式称为“发布/订阅”

为了说明这种模式,我们将构建一个简单的日志记录系统。它将由两个程序组成 - 第一个将发出日志消息,第二个将接收和打印它们

在我们的日志记录系统中,接收器程序的每个运行副本都将获得消息。这样,我们将能够运行一个接收器并将日志定向到磁盘;同时,我们将能够运行另一个接收器并在屏幕上查看日志

本质上,已发布的日志消息将广播到所有接收方

Exchanges

在本教程的前几部分中,我们向队列发送消息和从队列接收消息。现在是时候在 Rabbit 中引入完整的消息传递模型了

让我们快速回顾一下前面教程中介绍的内容:

  • 生产者(Producer)是发送消息的用户应用程序。
  • 队列是(Queue)存储消息的缓冲区。
  • 使用者(Consumer)是接收消息的用户应用程序

RabbitMQ 中消息传递模型的核心思想是,生产者从不将任何消息直接发送到队列。实际上,很多时候,生产者甚至根本不知道消息是否会传递到任何队列

相反,生产者只能向交易所(exchange)发送消息。交换是一件非常简单的事情。一方面,它接收来自生产者的消息,另一方面将它们推送到队列中。交换必须确切地知道如何处理它收到的消息。是否应将其附加到特定队列?是否应该将其附加到许多队列中?或者应该丢弃它。其规则由交换类型(exchange type)定义。

RabbitMQ 工作模式介绍

交换机类型有 direct, topic, headers and fanout, 下面我们创建一个direct类型的交换机

$channel->exchange_declare('logs', 'fanout', false, false, false);

现在,我们可以发布到我们命名的交易所(exchange)

$channel->exchange_declare('logs', 'fanout', false, false, false);
$channel->basic_publish($msg, 'logs');

Temporary queues(临时队列)

您可能还记得以前我们使用具有特定名称的队列(还记得 hello 和 task_queue 吗?能够命名队列对我们来说至关重要 - 我们需要将工人指向同一个队列。如果要在生产者和使用者之间共享队列,为队列命名非常重要

首先,每当我们连接到Rabbit时,我们都需要一个新的空队列。为此,我们可以创建一个具有随机名称的队列,或者更好的是 - 让服务器为我们选择一个随机队列名称

其次,一旦我们断开了消费者的连接,队列应该被自动删除。

在 php-amqplib 客户端中,当我们以空字符串形式提供队列名称时,我们创建一个具有生成名称的非持久队列:

list($queue_name, ,) = $channel->queue_declare("");

当该方法返回时,$queue_name 变量包含由 RabbitMQ 生成的随机队列名称。例如,它可能看起来像amq.gen-JzTY20BRgKO-HjmUJj0wLg。

Bindings(绑定)

RabbitMQ 工作模式介绍

交换机和队列之间的关系称为绑定

$channel->queue_bind($queue_name, 'logs');

将一切都整合到一起

RabbitMQ 工作模式介绍

发出日志消息的生产者程序看起来与上一教程没有太大区别。最重要的变化是我们现在希望将消息发布到我们的日志交换机

publish.php

<?php

require_once __DIR__ . '/vendor/autoload.php';
use PhpAmqpLib\Connection\AMQPStreamConnection;
use PhpAmqpLib\Message\AMQPMessage;

$connection = new AMQPStreamConnection('localhost', 5672, 'guest', 'guest');
$channel = $connection->channel();
// 创建log交换机 类型为:fanout
$channel->exchange_declare('logs', 'fanout', false, false, false);

$data = implode(' ', array_slice($argv, 1));
if (empty($data)) {
    $data = "info: Hello World!";
}
$msg = new AMQPMessage($data);

// 把消息发布到日志交换机
$channel->basic_publish($msg, 'logs');

echo ' [x] Sent ', $data, "\n";

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

subscribe.php

<?php

require_once __DIR__ . '/vendor/autoload.php';
use PhpAmqpLib\Connection\AMQPStreamConnection;

$connection = new AMQPStreamConnection('localhost', 5672, 'guest', 'guest');
$channel = $connection->channel();

// 日志交换机类型为:fanout
$channel->exchange_declare('logs', 'fanout', false, false, false);

// 生成临时队列
list($queue_name, ,) = $channel->queue_declare("", false, false, true, false);

// 队列绑定交换机
$channel->queue_bind($queue_name, 'logs');

echo " [*] Waiting for logs. To exit press CTRL+C\n";

$callback = function ($msg) {
    echo ' [x] ', $msg->body, "\n";
};

$channel->basic_consume($queue_name, '', false, true, false, false, $callback);

while ($channel->is_open()) {
    $channel->wait();
}

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

执行结果

# shell1
php publish.php 记录日志信息
# shell2
php subscribe.php 
	
 [*] Waiting for logs. To exit press CTRL+C
 [x] 记录日志信息

# shell3
php subscribe.php

 [*] Waiting for logs. To exit press CTRL+C
 [x] 记录日志信息

4. Routing

在前面的教程中,我们构建了一个简单的日志记录系统。我们能够将日志消息广播到许多接收器

在本教程中,我们将为其添加一个功能 - 我们将使仅订阅消息的子集成为可能。例如,我们将能够仅将关键错误消息定向到日志文件(以节省磁盘空间),同时仍然能够在控制台上打印所有日志消息

Bindings

绑定可以采用额外的routing_key参数。为了避免与 $channel::basic_publish 参数混淆,我们将其称为绑定键。这就是我们如何用键创建绑定

$channel->queue_bind($queue_name, 'logs');

$binding_key = 'black';
$channel->queue_bind($queue_name, $exchange_name, $binding_key);

Direct exchange

上一教程中的日志记录系统将所有消息广播给所有使用者。我们希望对其进行扩展,以允许根据消息的严重性筛选消息。例如,我们可能希望将日志消息写入磁盘的脚本仅接收严重错误,而不是在警告或信息日志消息上浪费磁盘空间

fanout 这并没有给我们带来太大的灵活性 - 它只能进行无意识的广播

direct 我们将改用直接交换。直接交换背后的路由算法很简单 - 消息进入绑定键与消息的路由键完全匹配的队列

![](C:\Users\yanwe\Pictures\Saved Pictures\python-four.png)

send.php

<?php

require_once __DIR__ . '/vendor/autoload.php';
use PhpAmqpLib\Connection\AMQPStreamConnection;
use PhpAmqpLib\Message\AMQPMessage;

// 创建连接
$connection = new AMQPStreamConnection('localhost', 5672, 'guest', 'guest');
$channel = $connection->channel();

// 声明交换机 类型为:direct
$channel->exchange_declare('direct_logs', 'direct', false, false, false);

// 接受控制台参数
$severity = isset($argv[1]) && !empty($argv[1]) ? $argv[1] : 'info';

$data = implode(' ', array_slice($argv, 2));
if (empty($data)) {
    $data = "Hello World!";
}

// 实例化消息
$msg = new AMQPMessage($data);

// 发送消息:exchange、routingkey
$channel->basic_publish($msg, 'direct_logs', $severity);

echo ' [x] Sent ', $severity, ':', $data, "\n";

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

revice.php

<?php

require_once __DIR__ . '/vendor/autoload.php';
use PhpAmqpLib\Connection\AMQPStreamConnection;

$connection = new AMQPStreamConnection('localhost', 5672, 'guest', 'guest');
$channel = $connection->channel();
// 声明交换机类型为:direct
$channel->exchange_declare('direct_logs', 'direct', false, false, false);

// 声明空队列
list($queue_name, ,) = $channel->queue_declare("", false, false, true, false);


$severities = array_slice($argv, 1);
if (empty($severities)) {
    file_put_contents('php://stderr', "Usage: $argv[0] [info] [warning] [error]\n");
    exit(1);
}

// 绑定多个routingkey
foreach ($severities as $severity) {
    $channel->queue_bind($queue_name, 'direct_logs', $severity);
}

echo " [*] Waiting for logs. To exit press CTRL+C\n";

$callback = function ($msg) {
    echo ' [x] ', $msg->delivery_info['routing_key'], ':', $msg->body, "\n";
};

$channel->basic_consume($queue_name, '', false, true, false, false, $callback);

while ($channel->is_open()) {
    $channel->wait();
}

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

执行结果

# shell1  发送error类型日志
php send.php error "Run. Run. Or it will explode."

# shell2 监听  warning error 类型
php receive.php warning error
# 有消息输出

# shell3 监听info类型日志内容
php receive.php info
# 正常情况 无法收到消息
	

5. Topics

在前面的教程中,我们改进了日志记录系统。我们没有使用只能进行虚拟广播的fanout交换,而是使用了direct直接交换,并获得了有选择地接收日志的可能性。

尽管使用direct直接交换改进了我们的系统,但它仍然存在局限性 - 它不能基于多个标准进行路由

Topic exchange

发送到主题交换的消息不能具有任意routing_key - 它必须是单词列表,由点分隔。单词可以是任何东西,但通常它们指定与消息相关的一些特征。一些有效的路由密钥示例:“stock.usd.nyse”、“nyse.vmw”、“quick.orange.rabbit”。路由密钥中可以有任意数量的单词,最多 255 字节的限制

绑定密钥也必须采用相同的形式。主题交换背后的逻辑类似于直接交换 - 使用特定路由密钥发送的消息将被传递到与匹配绑定密钥绑定的所有队列。但是,绑定键有两种重要的特殊情况

  • * (star) can substitute for exactly one word. (可以替代一个词)
  • # (hash) can substitute for zero or more words. (可以替代零个或者多个单词)

![](C:\Users\yanwe\Pictures\Saved Pictures\python-five.png)

在这个例子中,我们将发送所有描述动物的消息。消息将使用由三个单词(两个点)组成的路由密钥发送。路由键中的第一个词将描述速度,第二个词描述颜色,第三个词描述物种:<speed>.<colour>.<species>

send.php

<?php

require_once __DIR__ . '/vendor/autoload.php';
use PhpAmqpLib\Connection\AMQPStreamConnection;
use PhpAmqpLib\Message\AMQPMessage;

$connection = new AMQPStreamConnection('localhost', 5672, 'guest', 'guest');
$channel = $connection->channel();

$channel->exchange_declare('topic_logs', 'topic', false, false, false);

$routing_key = isset($argv[1]) && !empty($argv[1]) ? $argv[1] : 'anonymous.info';
$data = implode(' ', array_slice($argv, 2));
if (empty($data)) {
    $data = "Hello World!";
}

$msg = new AMQPMessage($data);

$channel->basic_publish($msg, 'topic_logs', $routing_key);

revice.php

<?php

require_once __DIR__ . '/vendor/autoload.php';
use PhpAmqpLib\Connection\AMQPStreamConnection;

$connection = new AMQPStreamConnection('localhost', 5672, 'guest', 'guest');
$channel = $connection->channel();

$channel->exchange_declare('topic_logs', 'topic', false, false, false);

list($queue_name, ,) = $channel->queue_declare("", false, false, true, false);

$binding_keys = array_slice($argv, 1);
if (empty($binding_keys)) {
    file_put_contents('php://stderr', "Usage: $argv[0] [binding_key]\n");
    exit(1);
}

foreach ($binding_keys as $binding_key) {
    $channel->queue_bind($queue_name, 'topic_logs', $binding_key);
}

echo " [*] Waiting for logs. To exit press CTRL+C\n";

$callback = function ($msg) {
    echo ' [x] ', $msg->delivery_info['routing_key'], ':', $msg->body, "\n";
};

$channel->basic_consume($queue_name, '', false, true, false, false, $callback);

while ($channel->is_open()) {
    $channel->wait();
}

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

执行结果

# shell1

# shell2
php revice.php "#"
# shell3
php revice.php "kern.*"
# shell4 
php revice.php "*.critical"
# shell5
php revice.php "kern.*" "*.critical"

6. Publisher Confirms

发布者确认是 RabbitMQ 扩展,以实现可靠的发布。当在通道上启用发布者确认时,代理会异步确认客户端发布的消息,这意味着它们已在服务器端处理

概述

在本教程中,我们将使用发布者确认来确保已发布的消息已安全到达代理。我们将介绍使用发布商确认的几种策略,并解释它们的优缺点

开启发布者确认

$channel = $connection->channel();
$channel->confirm_select();

Strategy #1: Publishing Messages Individually(策略#1:单独发布消息)

让我们从使用确认发布的最简单方法开始,即发布消息并同步等待其确认

while (thereAreMessagesToPublish()) {
    $data = "Hello World!";
    $msg = new AMQPMessage($data);
    $channel->basic_publish($msg, 'exchange');
    // uses a 5 second timeout
    $channel->wait_for_pending_acks(5.000);
}

在前面的示例中,我们像往常一样发布一条消息,并使用 $channel::wait_for_pending_acks(int|float) 方法等待其确认。确认消息后,该方法将立即返回。如果消息未在超时内确认,或者它是裸的(意味着代理由于某种原因无法处理它),该方法将引发异常。异常的处理通常包括记录错误消息和/或重试发送消息

不同的客户端库有不同的方法来同步处理发布者确认,因此请务必仔细阅读您正在使用的客户端的文档

这种技术非常简单,但也有一个主要缺点:它大大减慢了发布速度,因为消息的确认会阻止所有后续消息的发布。此方法不会提供每秒超过几百条已发布消息的吞吐量。尽管如此,这对于某些应用程序来说已经足够了

Strategy #2: Publishing Messages in Batches(策略#2:批量发布消息)

为了改进前面的示例,我们可以发布一批消息并等待整个批次得到确认。以下示例使用一批 100

$batch_size = 100;
$outstanding_message_count = 0;
while (thereAreMessagesToPublish()) {
    $data = ...;
    $msg = new AMQPMessage($data);
    $channel->basic_publish($msg, 'exchange');
    $outstanding_message_count++;
    if ($outstanding_message_count === $batch_size) {
        $channel->wait_for_pending_acks(5.000);
        $outstanding_message_count = 0;
    }
}
if ($outstanding_message_count > 0) {
    $channel->wait_for_pending_acks(5.000);
}

等待一批消息被确认比等待单个消息的确认大大提高了吞吐量(使用远程 RabbitMQ 节点最多 20-30 倍)。一个缺点是,在发生故障时,我们不知道到底出了什么问题,因此我们可能不得不在内存中保留整个批次以记录有意义的内容或重新发布消息。并且此解决方案仍然是同步的,因此它会阻止消息的发布

Strategy #3: Handling Publisher Confirms Asynchronously(策略 #3:处理发布服务器异步确认)

代理异步确认已发布的消息,只需在客户端注册回调即可收到这些确认的通知

$channel = $connection->channel();
$channel->confirm_select();

$channel->set_ack_handler(
    function (AMQPMessage $message){
        // code when message is confirmed
    }
);

$channel->set_nack_handler(
    function (AMQPMessage $message){
        // code when message is nack-ed
    }
);

有 2 个回调:一个用于已确认的消息,一个用于裸消息(代理可以认为丢失的消息)。每个回调都有 AMQPMessage $message 参数和返回的消息,因此您无需处理序列号(传递标记)即可了解此回调属于哪条消息文章来源地址https://www.toymoban.com/news/detail-464232.html

send.php

$channel->confirm_select();

$channel->set_ack_handler(function (AMQPMessage $message) {
    file_put_contents("./librabbitmq.log", var_export([
        'type' => 'ack', 'message' => $message->body
    ], true) . PHP_EOL , FILE_APPEND);
});

$channel->set_nack_handler(function (AMQPMessage $message) {
    file_put_contents("./librabbitmq.log", var_export([
        'type' => 'nack', 'message' => $message->body
    ], true) . PHP_EOL , FILE_APPEND);
});

$channel->wait_for_pending_acks();

到了这里,关于RabbitMQ 工作模式介绍的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • RabbitMQ五大常用工作模式

    消息生产者 消息消费者(会一直监听队列) 工作队列 消息生产能力大于消费能力,增加多个消费节点 和简单队列类似,增加多个消费节点,处于竞争关系 默认策略:round robin轮训 生产者 消费者1 消费者2 轮训策略验证 先启动两个消费者,再启动生产者 缺点:存在部分节点

    2024年02月19日
    浏览(45)
  • RabbitMQ的工作模式

    RabbitMQ 的工作模式 一 .simple 模式(即最简单的收发模式) 二 .work 工作模式 ( 资源的竞争 ) publish_subscribe 发布订阅 (../../../../../0 马士兵 / 新建文件夹 /BAT 面试突击资料 (1)/ 整理 /BAT 面试突击资料 /15- 消息中间件 MQ 面试题( 2020 最新 版) .assets/publish_subscribe 发布订阅 ( 共享资

    2024年02月06日
    浏览(71)
  • RabbitMQ:工作队列模式

    📃个人主页:不断前进的皮卡丘 🌞博客描述:梦想也许遥不可及,但重要的是追梦的过程,用博客记录自己的成长,记录自己一步一步向上攀登的印记 🔥个人专栏:消息中间件 工作队列(又名: 任务队列 )背后的主要思想是避免立即执行资源密集型任务并等待其完成。相反

    2024年01月23日
    浏览(39)
  • 消息队列之RabbitMQ工作模式

    提示:这里可以添加系列文章的所有文章的目录,目录需要自己手动添加 消息队列之RabbitMQ工作模式 提示:写完文章后,目录可以自动生成,如何生成可参考右边的帮助文档 提示:这里可以添加本文要记录的大概内容: 在这篇博客中,我将深入探讨 RabbitMQ 的工作模式,带你

    2024年01月18日
    浏览(53)
  • RabbitMQ的6种工作模式

    官方文档: http://www.rabbitmq.com/ https://www.rabbitmq.com/getstarted.html RabbitMQ 常见的 6 种工作模式: 1)、消息产生后将消息放入队列。 2)、消息的消费者监听消息队列,如果队列中有消息,就消费掉,消息被拿走后,自动从队列中删除。 3)、存在的问题:消息可能没有被消费者正确处

    2024年02月14日
    浏览(38)
  • RabbitMQ消息队列的工作模式

    官方文档地址:https://www.rabbitmq.com/getstarted.html 工作模式其实就是消息队列分发消息的路由方式。 RabbitMQ常用的几种工作模式: 简单模式 WorkQueues工作队列模式 PubSub生产者/PubSub消费者模式 Routing路由模式 Topics通配符模式 发布/订阅模式(Publish/Subscribe):该模式用于一对多的

    2024年02月15日
    浏览(44)
  • 消息队列——rabbitmq的不同工作模式

    目录 Work queues 工作队列模式  Pub/Sub 订阅模式 Routing路由模式 Topics通配符模式   工作模式总结 C1和C2属于竞争关系,一个消息只有一个消费者可以取到。  代码部分只需要用两个消费者进程监听同一个队里即可。 两个消费者呈现竞争关系。 用一个生产者推送10条消息 两个监

    2024年02月16日
    浏览(43)
  • RabbitMQ常用工作模式+整合springboot

    目录 1.MQ的相关概念 1.1 什么是MQ消息中间件 1.2 为什么使用MQ (1) 应用解耦 (2) 异步提速   (3)削峰填谷 1.3 使用MQ的劣势 1.4 常见的MQ组件​​​​​​​ 2. RabbitMQ的概述 2.1 RabbitMQ的概念 2.2 RabbitMQ的原理 2.3 安装RabbitMQ 3. RabbitMQ 的工作模式 3.1 simple (简单模式) 3.2 Work queues(工作模

    2024年02月15日
    浏览(40)
  • RabbitMQ的5种模式——再探RabbitMQ的模式,简单、工作,发布订阅(广播),路由、主题 & 页面分析

    RabbitMQ作为一款常用的消息中间件,在微服务项目中得到大量应用,其本身是微服务中的重点和难点,有不少概念我自己的也是一知半解,本系列博客尝试结合实际应用场景阐述RabbitMQ的应用,分析其为什么使用,并给出怎么用的案例。 本篇博客结合场景来阐述RabbitMQ的几种模

    2024年02月07日
    浏览(43)
  • 【RabbitMQ】Spring整合RabbitMQ、Spring实现RabbitMQ五大工作模式(万字长文)

    目录 一、准备 1、创建maven项目​编辑 2、引入依赖 3、创建配置文件 1.RabbitMQ配置文件 2.生产者项目配置文件 3.消费者项目配置文件 二、生产者xml中文件创建队列 三、生产者xml文件中创建交换机以及绑定队列 1、创建交换机 2、绑定队列  四、消费者xml文件中创建队列消息监

    2024年01月21日
    浏览(41)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包