Topic mode of RabbitMQ (PHP version)

Keywords: PHP RabbitMQ JSON

Topic mode

  1. A message is obtained by multiple consumers. The target queue of the message can be specified by the BindingKey wildcard (ා: zero or more words, *: one word).
  2. There are four types of switches in RabbitMQ: direct fanout topic headers. In routing mode, the switch type is topic.

Class library

RabbitMQ uses the AMQP protocol. To use her you need a library that uses the same protocol. PHP amqplib is used here, and Composer dependency management is used.

# Add a composer.json file to the project
{
    "require": {
        "php-amqplib/php-amqplib": "^2.11"
    }
}
# Use Composer to install (if you want to install Composer)
composer install

Producer (message sender)

The producer connects to RabbitMQ Broker, establishes a Connection and opens a Channel. The producer sends the message to the Exchange, which receives the producer message and pushes the message to the queue. Here, the type of Exchange is topic, which routes messages to the queues that BindingKey and RoutingKey want to match. Here are some notes:

  1. RoutingKey is a string separated by dot "." (each independent string separated by dot "." is called a word), such as "abc.def.hij".
  2. BindKey and RoutingKey are also a string separated by dot ".".
  3. There can be two special strings "*" and "ා" in BindKey for fuzzy matching, where "*" is used to match one word and "#" is used to match zero or more words.

Now look at the sender code (publish.php).

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

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

$exchange = 'topic'; // Name of exchanger

try {
    $connection = new AMQPStreamConnection(HOST, PORT, USER, PASS, VHOST); // Establish connection to RabbitMQ server
    $channel = $connection->channel(); // Establishing channels
    $channel->exchange_declare($exchange, AMQPExchangeType::TOPIC, false, true, false); // Tentatively declare a switch
    $routingKey = isset($argv[1]) && !empty($argv[1]) ? $argv[1] : 'none.info'; // Get routing_key, no default is' none.info '
    $messageBody = json_encode(array_slice($argv, 2), JSON_UNESCAPED_UNICODE); // Get send data
    if (empty($messageBody)) throw new Exception('Please enter a message'); // No incoming message prompt error
    $message = new AMQPMessage($messageBody, ['content_type' => 'text/plain', 'delivery_mode' => AMQPMessage::DELIVERY_MODE_PERSISTENT]); // Define message
    $channel->basic_publish($message, $exchange, $routingKey); // Production news
    $channel->close();// Close channel
    $connection->close();// Close connection
} catch (Exception $e) {
    die($e->getMessage());
}

Consumer (recipient of message)

The producer connects to RabbitMQ Broker, establishes a Connection and opens a Channel. Declare a queue, specify routing rules, bind the queue and Exchange through routing rules, Exchange sends messages to the queue, and consumers consume messages from the queue. Check the consumer code (receive.php).

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

use PhpAmqpLib\Connection\AMQPStreamConnection;
use PhpAmqpLib\Exchange\AMQPExchangeType;

$exchange = 'topic'; // Name of exchanger

try {
    $connection = new AMQPStreamConnection(HOST, PORT, USER, PASS, VHOST); // Establish connection to RabbitMQ server
    $channel = $connection->channel(); // Establishing channels
    $channel->exchange_declare($exchange, AMQPExchangeType::TOPIC, false, true, false); // Tentatively declare a switch
    // Created a non persistent queue with a build name. When we connect to RabbitMQ, we need a new, empty queue. We can create a random queue name manually, or let the server choose a random queue name for us (recommended)
    list($queueName, ,) = $channel->queue_declare('', false, true, true, false); // Tentatively declare a queue
    $routingKeys = array_slice($argv, 1); // Get routing_key
    if (empty($routingKeys)) throw new Exception('Please enter at least one routing_key'); // Enter routing_key
    foreach ($routingKeys as $routingKey) {
        $channel->queue_bind($queueName, $exchange, $routingKey); // The queue is bound to the switch through routing_key
    }
    echo " [*] Waiting for logs. To exit press CTRL+C\n";
    $callback = function ($msg) { // Callback function
        sleep(3);
        // Manually confirm whether the message is consumed normally to ensure the idempotent of message consumption.
        $msg->delivery_info['channel']->basic_ack($msg->delivery_info['delivery_tag']);
        echo ' [x] Received ', $msg->delivery_info['routing_key'], ':', $msg->body, "\n";
    };
    $channel->basic_consume($queueName, '', false, false, false, false, $callback); // Consumer News
    while ($channel->is_consuming()) { // Circular consumption message, no blocking waiting
        $channel->wait();
    }
    $channel->close(); // Channel closure
    $connection->close(); // Connection closure
} catch (Exception $e) {
    die($e->getMessage());
}

test

  1. Open two consumers, specify different routing rules, open a producer, and the producer specifies routing rules and messages.
  2. Test results.

Other

  1. If you don't understand a concept, check Basic concepts of RabbitMQ
  2. If you don't understand some of the methods, check Details of RabbitMQ methods (PHP version)
  3. Code download

 

68 original articles published, 53 praised, 40000 visitors+
Private letter follow

Posted by MrQcue on Sun, 12 Jan 2020 23:49:21 -0800