RabbitMQ Part3 (Publish/Subscribe)

Publish / Subscribe

Teaching in the previous sections, we have created a work queue. After the work queue is assumed that each task are delivered to a particular worker process. In this section, we do something completely different things. We will distribute a message to multiple customers. This mode is called "publish / subscribe".

To illustrate this pattern, we will create a simple logging system. It includes two parts of the program: the first part will issue a log message, receive and print a second portion thereof.

In our logging system, the receiver runs a program every copy will receive the message. In this way, we can run one receiver, and logs are directed to disk; at the same time, we will be able to run another receiver, and see the log on the screen.

In essence, the log message to be broadcast to the release of all recipients.

switch

In the previous part of the tutorial, we send messages and receive messages from the queue to the queue. Now is the time to introduce the complete message passing model of the Rabbit.

Let's quickly review what previous tutorial:

  • Producer is a message sent to the user program.
  • Message queue is stored in the buffer.
  • Consumers are user program receives the message.

The core idea RabbitMQ messaging model is the producer never send the message directly to the queue. In fact, in most cases the producers do not even need to know where to send a message to a queue.

In contrast, the producer can send a message to switch to. A switch is very simple. In one, it receives a message from the producer, the other end of the push message queue. The switch must know exactly how to handle incoming messages. It should be attached to a specific queue it? It should be attached to multiple queues it? Or is it should be discarded. Its rules by the exchange typedefinition.  
Figure:
There are several types of directswitches: topic, , headersand fanout(broadcast mode). We will focus on the last (broadcast mode). Let us create such a type, called logs:

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

Broadcast switch is very simple. As you might guess from the name, it just all received broadcast messages to all queues know it. This is what we needed to log.

Switch list

To list on the exchange server, you can run the command rabbitmqctl:

  • sudo rabbitmqctl list_exchanges

In this list, there will be some amq.*switches and the default (unnamed) switch. These are created by default, but now less likely to need it.

Default Switch

In the previous sections of this tutorial, we know nothing about the switch, but still able to send messages to the queue. This is because we used the default switch that ( "") identified by an empty string.
We recall how before the release of information:

  • $channel->basic_publish($msg, '', 'hello');
    Here we used the default or anonymous switch: the message is routed to routing_keythe designated queue. The keyword basic_publishspecified in the third argument.

Now, we can post messages to just naming the switch:

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

Temporary queue

You may recall that before we use the queue is assigned a name (such as: helloand task_queue?). For us, the queue name is critical - we need to work a process point to the queue. When you want to share between producers and consumers in the queue, the queue name is also very important.

But for our logging system, it is not the case. We would like to receive all log messages, not just part of it. We are also interested in information only for the current flow, but not before. To solve this problem, we need to complete two parts.

A first portion connected to the RabbitMQ whenever required a new, empty queue. To this end, we can create a queue with a random name, or, better yet, let the server choose a random queue name for us.

The second part, once we disconnected consumers, the queue should be automatically deleted.

In the php-amqplibclient, when we queue name in the form of an empty string, we generated automatically generates the name of a queue of non-persistent:

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

When the method returns, $queue_namethe variable contains the name of the queue RabbitMQ randomly generated. For example, it may look like amq.gen-JzTY20BRgKO-HjmUJj0wLg.

When declaring its connection is closed, the queue will be deleted, because it is declared as exclusive. You can queue Guide Learn About exclusiveMore information signs and other attributes of the queue.

Bindings (bindings)

Here Insert Picture Description
We have created a radio switches and queue. Now we need to tell the switch to send a message to our queue. The relationship between the queue and the switches referred to bind .

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

From now on, logsthe switch will be a message attached to our queue.

Binding list

You can list the existing binding:
rabbitmqctl list_bindings

to sum up

Here Insert Picture Description
Log messages issued by the program producers look not much different from the previous tutorial. The most important change is that we now want to publish a message to the log switch, and an anonymous switch. Here is the emit_log.phpscript code:

<?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('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();

After the connection is established, we declare the switch. This step is necessary because there is no release to the switch is disabled.

If the queue is not bound to the exchange, the message will be lost, but for us it does not matter; if the consumer does not listen, we can safely discard this message.

receive_logs.php Code:

<?php

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

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

$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 (count($channel->callbacks)) {
    $channel->wait();
}

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

If you want to save the log to a file, open a console input:

php receive_logs.php > logs_from_rabbit.log

If you want to see the log on the screen, generate a new terminal and run:

 php receive_logs.php

Issue log:

php emit_log.php

Use rabbitmqctl list_bindings, you can verify the code is indeed in accordance with our requirements create and bind the queue. Two run receive_logs.phpthe program, you should see the following:

sudo rabbitmqctl list_bindings
# => Listing bindings ...
# => logs    exchange        amq.gen-JzTY20BRgKO-HjmUJj0wLg  queue           []
# => logs    exchange        amq.gen-vso0PVvyiRIL2WoV3i48Yg  queue           []
# => ...done.

Interpretation of the results is very simple: from a logsdata switch queue will be sent to two, the two queues are assigned by the server name. This is the effect we want.

To learn how to listen subset of the messages, let us continue to learn Tutorial 4 .

Translated from: https://www.rabbitmq.com/tutorials/tutorial-three-php.html

Guess you like

Origin blog.csdn.net/qq_35958788/article/details/92416980