RabbitMQ 工作模式介绍

1.Hello World

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

<?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 的消息,因此与发布单个消息的发布者不同,我们将保持接收器运行以侦听消息并打印出来

<?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),我们编写了程序来发送和接收来自命名队列的消息。在此部分中,我们将创建一个工作队列,用于在多个工作线程之间分配耗时的任务

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

此概念在 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 只是在消息进入队列时调度消息。它不会查看使用者的未确认消息数。它只是盲目地将每 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)定义。

交换机类型有 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(绑定)

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

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

将一切都整合到一起

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

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 参数和返回的消息,因此您无需处理序列号(传递标记)即可了解此回调属于哪条消息

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 工作模式介绍的更多相关文章

  1. rsync的介绍及参数详解,配置步骤,工作模式介绍

    rsync的介绍及参数详解,配置步骤,工作模式介绍 rsync是类unix系统下的数据镜像备份工具.它是快速增量备份.全量备份工具. Sync可以远程同步,支持本地复制,或者与其他SSH.rsync主 ...

  2. 【RabbitMQ】工作模式介绍

    一.前言 之前,笔者写过< CentOS 7.2 安装 RabbitMQ> 这篇文章,今天整理一下 RabbitMQ 相关的笔记便于以后复习. 二.模式介绍 在 RabbitMQ 官网上提 ...

  3. LVS的工作模式介绍和NAT模式&DR模式实验步骤

    一:LVS介绍 二.LVS的NAT和DR模式的实验及配置步骤 一.LVS的简单介绍 linux virtual server 简单来讲lvs是一段内核代码 类似于netfilter本身是一框架但不提供 ...

  4. RabbitMQ工作模式

    ------------恢复内容开始------------ RabbitMQ基本概念: Producer:生产者(消息的提供者) Consumer:消费者(消息的使用者) Message:消息(程序 ...

  5. CLR的GC工作模式介绍(Workstation和Server)

    CLR的核心功能之一就是垃圾回收(garbage collection),关于GC的基本概念本文不在赘述.这里主要针对GC的两种工作模式展开讨论和研究. Workstaction模式介绍 该模式设计的 ...

  6. 阶段5 3.微服务项目【学成在线】_day05 消息中间件RabbitMQ_10.RabbitMQ研究-工作模式-路由工作模式介绍

    队列在绑定交换机的时候可以指定routingKey, 路由模式: 1.每个消费者监听自己的队列,并且设置routingkey. 2.生产者将消息发给交换机,由交换机根据routingkey来转发消息到 ...

  7. RabbitMQ入门及其几种工作模式

    1.简介 MQ全程Message Queue,用于应用程序和应用程序间进行通信.RabbitMQ采用Erlang编写,实现了AMQP(高级消息队列)协议,跨平台,支持各种主流的操作系统和多种客户端. ...

  8. 面试官:RabbitMQ有哪些工作模式?

    哈喽!大家好,我是小奇,一位不靠谱的程序员 小奇打算以轻松幽默的对话方式来分享一些技术,如果你觉得通过小奇的文章学到了东西,那就给小奇一个赞吧 文章持续更新 一.前言 今天又.又.又来面试了,还是老规 ...

  9. 深入解读RabbitMQ工作原理及简单使用

    RabbitMQ系列目录 RabbitMQ在Ubuntu上的环境搭建 深入解读RabbitMQ工作原理及简单使用 Rabbit的几种工作模式介绍与实践 Rabbit事务与消息确认 Rabbit集群搭建 ...

  10. LVS工作模式与调度算法

    LVS三种工作模式.十种调度算法介绍 工作模式介绍: 1.Virtual server via NAT(VS-NAT) 优点:集群中的物理服务器可以使用任何支持TCP/IP操作系统,物理服务器可以分配 ...

随机推荐

  1. Debiased Contrastive Learning of Unsupervised Sentence Representations 论文精读

    1. 介绍(Introduction) 问题: 由PLM编码得到的句子表示在方向上分布不均匀, 在向量空间中占据一个狭窄的锥形区域, 这在很大程度上限制了它们的表达能力. 已有的解决办法: 对比学习. ...

  2. Salesforce Javascript(三) 小结1

    本篇参考: https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Guide/Functions https://developer.mozi ...

  3. 用BingGPT写一首勉励自己的诗

    觉得写的还挺有意思,所以记录一下,祝自己在今后的生活中努力学习,学有所成 勤学不辍志,博览群书知. 海纳百川理,山高自有路. 勿以时日长,惟以功夫深.

  4. kubernetes 的TCP 数据包可视化

    kubernetes 的TCP 数据包可视化 介绍 k8spacket是用 Golang 编写的工具,它使用gopacket第三方库来嗅探工作负载(传入和传出)上的 TCP 数据包.它在运行的容器网络 ...

  5. 【Vue原理模拟】模拟Vue实现响应式数据

    1. 预期效果 当数据变动时,触发自定义的回调函数. 2. 思路 对对象 object 的 setter 进行设置,使 setter 在赋值之后执行回调函数 callback(). 3.细节 3.1 ...

  6. python入门教程之二十四Python MySQL - mysql-connector 驱动

    MySQL 是最流行的关系型数据库管理系统,如果你不熟悉 MySQL,可以阅读我们的 MySQL 教程. 本章节我们为大家介绍使用 mysql-connector 来连接使用 MySQL, mysql ...

  7. 打造自己的ChatGPT:逐字打印的流式处理

    接口的延迟 在调用OpenAI的接口时,不免会有很慢的感觉,抛去地理位置上的网络延迟,大量的延迟往往发生在响应生成的过程中. 因此,如果使用同步接口的话,需要等待响应完全生成之后才能最终显示输出结果, ...

  8. opencv基础

    Python 和 OpenCV 的结合是计算机视觉领域中应用最为广泛的一种方式,它们的结合使得开发者可以快速.高效地完成各种视觉任务.本文将介绍 Python 和 OpenCV 的基础使用,包括安装. ...

  9. Hugging News #0414: Attention 在多模态情景中的应用、Unity API 以及 Gradio 主题构建器

    每一周,我们的同事都会向社区的成员们发布一些关于 Hugging Face 相关的更新,包括我们的产品和平台更新.社区活动.学习资源和内容更新.开源库和模型更新等,我们将其称之为「Hugging Ne ...

  10. SpringBoot 集成 Quartz + MySQL

    Quartz 简单使用 Java SpringBoot 中,动态执行 bean 对象中的方法 源代码地址 => https://gitee.com/VipSoft/VipBoot/tree/de ...