rabbitmq消息中間件的初步探索

在上次學xattr的時候用它簡單實現一箇中間件,我去了解了一下rabbitmq這個消息中間件,感覺理論上還是挺好用的,給一般併發量的系統用足夠了。

首先安裝這個服務。

sudo apt search rabbitmq

發現了這個

rabbitmq-server/focal-updates,focal-updates,focal-security,focal-security,now 3.8.2-0ubuntu1.3 all
    AMQP server written in Erlang

好,然後安裝它

sudo apt-get install rabbitmq-server

等他跑完就行了,要用PHP調用的話需要這個php組件

composer require php-amqplib/php-amqplib

跑完後創建兩個文件 receive.php 和 send.php

receive.php

<?php
require_once __DIR__ . '/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 message. ctrl+c to stop', "\n";
$callback = function($msg) {
  echo " [x] Received " . $msg->body . "\n";
};
$channel->basic_consume('hello', '', false, true, false, false, $callback);
while (count($channel->callbacks)) {
  $channel->wait();
}
$channel->close();
$connection->close();

send.php

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

$start_time = microtime(true);

$connection = new AMQPStreamConnection('localhost', 5672, 'guest', 'guest');
$channel = $connection->channel();
$channel->queue_declare('hello', false, false, false, false);
$msg = new AMQPMessage('Hello world!');
$channel->basic_publish($msg, '', 'hello');
// echo " [x] Send 'Hello world'\n";
$channel->close();
$connection->close();

$end_time = microtime(true);

echo "use time " . ($end_time - $start_time) * 1000 . " ms \n";

先運行 php receive.php 它就一直在監聽消息

[*] waiting for message. ctrl+c to stop

再運行 php send.php 進行投遞消息

就可以看到效果了。

 [*] waiting for message. ctrl+c to stop
 [x] Received Hello world!

關於這個例子 這篇文章介紹了很詳細 https://www.rabbitmq.com/tutorials/tutorial-one-php.html

git倉庫在這裏 https://github.com/php-amqplib/php-amqplib

除了這個composer之外 還可以安裝PHP的擴展

sudo apt-get install php7.4-amqp

安裝後用  php -m |grep amqp 來驗證一下擴展是不是真的安裝上了。

如果我不運行receive.php 直接運行send.php會怎麼樣呢?

我發現它會把消息堆積放在中間介質裏面(當然這個應該是rabbitmq server服務裏面的一部分)

只運行 send.php 不運行receive.php 發現有消息堆積 我們可以用  sudo rabbitmqctl list_queues 來查看列表

sudo rabbitmqctl list_queues
Timeout: 60.0 seconds ...
Listing queues for vhost / ...
name messages
hello 3

我執行了send.php3次留下來3條消息,在倉庫列表裏面等待處理。

此時再運行receive.php 然後進來就有消息輸出 再看看列表,發現沒有消息堆積了

sudo rabbitmqctl list_queues
Timeout: 60.0 seconds ...
Listing queues for vhost / ...
name messages
hello 0

這說明生產者是可以隨時生產投遞到中間存儲的,消費者啓動的時候會自己去消費堆積任務。
如果生產者消費者都在運行,那麼生產者投遞的消息馬上就被消費者處理了。

當你運行兩個receive.php的話

然後讓 send.php 執行10個消息投遞

for ($i=0; $i < 10; $i++) {
    $msg = new AMQPMessage('Hello world!'.$i);
    $channel->basic_publish($msg, '', 'hello');
}

1個消費者打印

[*] waiting for message. ctrl+c to stop
[x] Received Hello world!0
[x] Received Hello world!2
[x] Received Hello world!4
[x] Received Hello world!6
[x] Received Hello world!8

另1個消費者打印

[*] waiting for message. ctrl+c to stop
[x] Received Hello world!1
[x] Received Hello world!3
[x] Received Hello world!5
[x] Received Hello world!7
[x] Received Hello world!9

看來它倆分配了消息

然後對於這個效率的話,我做了一個測試

投遞   1 萬條消息耗費   228 ms 合約 43859 條/秒
投遞  10 萬條消息耗費  1512 ms 合約 66137 條/秒
投遞 100 萬條消息耗費 18785 ms 合約 54990 條/
for ($i=0; $i < 10000; $i++) {
    $msg = new AMQPMessage('Hello world!'.$i);
    $channel->basic_publish($msg, '', 'hello');
}
for ($i=0; $i < 100000; $i++) {
    $msg = new AMQPMessage('Hello world!'.$i);
    $channel->basic_publish($msg, '', 'hello');
}
for ($i=0; $i < 1000000; $i++) {
    $msg = new AMQPMessage('Hello world!'.$i);
    $channel->basic_publish($msg, '', 'hello');
}

可以看出這個投遞極限也就是單個進程每秒5-6萬條左右,總體而言效率還算不錯,已經能滿足很多系統了,畢竟業務上也沒有那麼多消息要傳遞,如果非要更快,那就需要考慮用更快的xattr或者共享內存之類的了。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章