php 发布订阅模式,rabbitmq exchange 的四种模式与点对点消息队列、发布订阅消息队列的实现...

最基本的模式就是点对点模式,一个生产者向队列中投入消息,一个消费者循环从队列中取数据

fdb22b99c168b451b4161621c1576ce5.png

php-amqplibproducer

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

use PhpAmqpLib\Connection\AMQPStreamConnection;

use PhpAmqpLib\Message\AMQPMessage;

$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] Sent 'Hello World!'\n";

$channel->close();

$connection->close();

?>

consumer

require_once __DIR__ . '/../composer/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";

$callback = function($msg) {

echo " [x] Received ", $msg->body, "\n";

};

$channel->basic_consume('hello', '', false, true, false, false, $callback);

while(count($channel->callbacks)) {

$channel->wait();

}

?>

这段代码中,producer 向名为 "hello" 的队列中放入消息 "Hello World",consumer 从其中取出消息,这是消息队列最简单的用法

basic_consume 方法的第一个参数标识队列名称,第四个参数标识是否自动 ack,第七个参数则是收到消息后执行的回调方法

Acknowledge

消息队列使用时,如果 consumer 意外退出,那么他没来得及处理的消息会如何处理呢?

AMQP 要求消费者需要向队列发送 ACK 消息表示消息已经处理,否则这条消息还会分发给其他 consumer 去处理,以防止消息的丢失

如果设置了 auto_ack,则 consumer 在收到消息后会立即自动发送 ACK 消息,这样在代码中无需手动发送 ack 消息,但是方便的同时带来了消息丢失的风险

下面是手动 ack 的 consumer 改进版本:

require_once __DIR__ . '/../composer/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";

$callback = function($msg) {

echo " [x] Received ", $msg->body, "\n";

sleep(3);

echo " [x] Done".PHP_EOL;

$msg->delivery_info['channel']->basic_ack($msg->delivery_info['delivery_tag']);

};

$channel->basic_qos(null, 1, null);

$channel->basic_consume('hello', '', false, false, false, false, $callback);

while(count($channel->callbacks)) {

$channel->wait();

}

?>

basic_qos 设置了队列的 prefetch_count 属性,它限制了消费者同时能够接收的消息数,设置为 1 也就意味着,在 consumer 手动发送 ack 前,队列不会再将新的消息发送给他

这样,我们可以不再仅仅用一个 consumer 来进行消费了,我们可以同时启动多个 consumer 来实现队列消息的消费了

PHP AMQP 扩展

下面使用 PHP 官方提供的 AMQP 扩展实现上述功能producer

$conn_args = array('host' => 'localhost', 'port' => 5672,

'login' => 'guest', 'password' => 'guest');

$connection = new AMQPConnection($conn_args);

if ($connection->connect()) {

echo "Established a connection to the broker \n";

} else {

echo "Cannot connect to the broker \n ";

}

$channel = new AMQPChannel($connection);

$queue = new AMQPQueue($channel);

$queue->setName('hello');

$ex = new AMQPExchange($channel);

$ex->setName('helloexchange');

$ex->setType(AMQP_EX_TYPE_DIRECT);

$ex->setFlags(AMQP_DURABLE);

$ex->declareExchange();

$ex->publish('Hello World!', 'hello');

?>

consumer

$conn_args = array('host' => 'localhost', 'port' => 5672,

'login' => 'guest', 'password' => 'guest');

$connection = new AMQPConnection($conn_args);

if ($connection->connect()) {

echo "Established a connection to the broker \n";

} else {

echo "Cannot connect to the broker \n ";

}

$channel = new AMQPChannel($connection);

$queue = new AMQPQueue($channel);

$queue->setName('hello');

$queue->bind('helloexchange', 'hello');

$queue->qos(0, 1);

while (1) {

if ($message = $queue->get()) {

echo " [x] Received ", $message->getBody(), "\n";

sleep(3);

echo $message->getBody().PHP_EOL;

echo " [x] Done".PHP_EOL;

$queue->ack($message->getDeliveryTag());

}

}

?>

需要注意的是:AMQPQueue 对象的 get 方法如果以 AMQP_AUTOACK 为参数则会自动发送 ack,无参数版本则需要手动调用 ack 方法发送

AMQPQueue 对象的 qos 方法与上面所说的 basic_qos 方法一样,设置了能够接收的消息大小和消息数,由于 rabbitmq 并没有实现对消息大小的限制,所以这里第一个参数并没有意义,我们设为了 0

这里涉及到 exchange 的相关概念,我们马上来了解

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值