Basic usage of PHP practical rabbitmq

Time:2021-9-2

brief introduction

Rabbitmq is a highly available information middleware. It is very necessary to learn and use rabbitmq.

  • Asynchronous messaging
  • Support various development languages such as Java, python, PHP, etc
  • Pluggable authentication, authorization
  • Rabbitmq manager can be used for management and monitoring.

install

Docker is directly used here, which is very convenient for installation

Pull image
docker pull rabbitmq:3.8.3-management-alpine

function
docker run --name run-rabbitmq -d -p 15672:15672 -p 5672:5672 rabbitmq

Port 15672 is the rabbitmq web management page, which can be accessed directly: http://localhost:15672/ , initial user password: Guest
Basic usage of PHP practical rabbitmq

use

When rabbitmq is used as a producer and consumer, there are basically two scenarios

  • One / more producers, multiple shared consumers
  • One / more producers, multiple independent consumers

Shared consumers can consume data in one queue at the same time to increase throughput
Independent consumers do not share queues. Each consumer has its own queue and can define rules to pull data from exchange to its own queue

The following will implement various scenarios through code

Basic concepts

queue

Data queue. Data can be pushed to or consumed from the queue

Exchange switch

Push the data to the switch. The queue can bind to the switch. Different types of switches support different binding rules

  • Fanout has no rules. All data in exchange
  • Direct matches exactly and binds only the data with the value specified by routingkey
  • Topic is a more flexible rule. The routing key must be a routing key.Separated words,*(asterisk) used to represent a word,#(pound sign) used to represent any number (zero or more) of words

Encapsulate some common operations of rabbitmq

<?php


namespace RabbitMQ;

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

class RabbitMQ
{

    private $host = '127.0.0.1';
    private $port = 5672;
    private $user = 'guest';
    private $password = 'guest';
    protected $connection;
    protected $channel;


    /**
     * RabbitMQ constructor.
     */
    public function __construct()
    {
        $this->connection = new AMQPStreamConnection($this->host, $this->port, $this->user, $this->password);
        $this->channel    = $this->connection->channel();
    }

    /**
     * @param $exchangeName
     * @param $type
     * @param $pasive
     * @param $durable
     * @param $autoDelete
     */
    public function createExchange($exchangeName, $type, $pasive = false, $durable = false, $autoDelete = false)
    {
        $this->channel->exchange_declare($exchangeName, $type, $pasive, $durable, $autoDelete);
    }

    /**
     * @param $queueName
     * @param $pasive
     * @param $durable
     * @param $exlusive
     * @param $autoDelete
     */
    public function createQueue($queueName, $pasive = false, $durable = false, $exlusive = false, $autoDelete = false, $nowait = false, $arguments = [])
    {
        $this->channel->queue_declare($queueName, $pasive, $durable, $exlusive, $autoDelete, $nowait, $arguments);
    }

    /**
     *Generate information
     * @param $message
     */
    public function sendMessage($message, $routeKey, $exchange = '', $properties = [])
    {
        $data = new AMQPMessage(
            $message, $properties
        );
        $this->channel->basic_publish($data, $exchange, $routeKey);
    }

    /**
     *Consumption news
     * @param $queueName
     * @param $callback
     * @throws \ErrorException
     */
    public function consumeMessage($queueName, $callback, $tag = '', $noLocal = false, $noAck = false, $exclusive = false, $noWait = false)
    {
        $this->channel->basic_consume($queueName, $tag, $noLocal, $noAck, $exclusive, $noWait, $callback);
        while ($this->channel->is_consuming()) {
            $this->channel->wait();
        }
    }

    /**
     * @throws \Exception
     */
    public function __destruct()
    {
        $this->channel->close();
        $this->connection->close();
    }
}

Multiple shared consumers

Multiple consumers can increase consumption speed and provide system throughput
Basic usage of PHP practical rabbitmq

Waiter, go straight to the code
Producer code

<?php

require_once '../../vendor/autoload.php';

use RabbitMQ\RabbitMQ;
use PhpAmqpLib\Message\AMQPMessage;

$rabbit = new RabbitMQ();

$queueName = 'test-single-queue';
$rabbit->createQueue($queueName,false,true,false,false);
for ($i = 0; $i < 10000; $i++) {
    $rabbit->sendMessage($i . "this is a test message.", $queueName,'',[
        'delivery_ mode' => AMQPMessage::DELIVERY_ MODE_ Persistent // the message is persisted. Restart rabbitmq and the message will not be lost
    ]);
}

unset($rabbit);// Close connection

Run producerphp Producer, you can see the queue information on the manager web page
Basic usage of PHP practical rabbitmq

Consumer code

<?php

require_once '../../vendor/autoload.php';

use RabbitMQ\RabbitMQ;

$rabbit = new RabbitMQ();

$queueName = 'test-single-queue';
$callback = function ($message){
    var_dump("Received Message : " . $message->body);//print message
    sleep(2);// Processing time-consuming tasks
    $message->delivery_info['channel']->basic_ack($message->delivery_info['delivery_tag']);//ack
};
$rabbit->consumeMessage($queueName,$callback);

unset($rabbit);// Close connection

Run consumer secondaryphp Consumer.php
Basic usage of PHP practical rabbitmq
Basic usage of PHP practical rabbitmq
You can see that two consumers will not consume message repeatedly
You can also see that the message of this queue is being consumed through the manager web
Basic usage of PHP practical rabbitmq

Multiple independent consumers

Rabbitmq producers push messages to exchange, and bind multiple queues to exchange to realize multiple independent consumers

Define a topic type switch. The consumption rule is: test.ex. add a word

<?php

require_once '../../vendor/autoload.php';

use RabbitMQ\RabbitMQ;

$rabbit = new RabbitMQ();

$exchangeName = 'test-ex-topic';
$queueName    = 'test-consumer-ex-topic';
$routingKey   = 'test.ex.*';// Definition of consumption rules

//Create queue
$rabbit->createQueue($queueName, false, true);
//Bind to switch
$rabbit->bindQueue($queueName, $exchangeName, $routingKey);
//Consumption
$callback = function ($message) {
    var_dump("Received Message : " . $message->body);//print message
    sleep(2);// Processing time-consuming tasks
    $message->delivery_info['channel']->basic_ack($message->delivery_info['delivery_tag']);//ack
};
$rabbit->consumeMessage($queueName, $callback);

unset($rabbit);// Close connection

Start consumerphp Consumer.php

Defining a producer will push messages to two different routingkeys

<?php

require_once '../../vendor/autoload.php';

use PhpAmqpLib\Exchange\AMQPExchangeType;
use PhpAmqpLib\Message\AMQPMessage;
use RabbitMQ\RabbitMQ;


$rabbit = new RabbitMQ();

$routingKey1  = 'test.ex.queue1';
$routingKey2  = 'test.ex.queue2';
$exchangeName = 'test-ex-topic';
$rabbit->createExchange($exchangeName, AMQPExchangeType::TOPIC, false, true, false);

//Push 10000 pieces of data to the switch and routingkey = test-ex-queue1
for ($i = 0; $i < 10000; $i++) {
    $rabbit->sendMessage($i . "this is a queue1 message.", $routingKey1, $exchangeName, [
        'delivery_ mode' => AMQPMessage::DELIVERY_ MODE_ Persistent // the message is persisted. Restart rabbitmq and the message will not be lost
    ]);
}
//Push 10000 pieces of data to the switch and routingkey = test-ex-queue2
for ($i = 0; $i < 10000; $i++) {
    $rabbit->sendMessage($i . "this is a queue2 message.", $routingKey2, $exchangeName, [
        'delivery_ mode' => AMQPMessage::DELIVERY_ MODE_ Persistent // the message is persisted. Restart rabbitmq and the message will not be lost
    ]);
}

unset($rabbit);// Close connection

Run producerphp Producer.php, you can see that the consumer has 20000 messages to consume, including the data in the two routingkeys
Basic usage of PHP practical rabbitmq

code

For codes, see: https://github.com/jiaoyang3/…