rabbitmq是一款成熟的消息中间件产品,提供了各类应用场景下相关队列的实现。延迟队列也是其中之一,rabbitmq提供了两种实现延迟队列的途径,下边就针对这两种方式进行实战演戏(采用php实现)。
rabbitmq消息队列中的消息在以下几种情况下会变成“死信”:
消息被拒绝(basic.reject / basic.nack),并且requeue = false;
消息TTL过期;
队列达到最大长度;
变成死信后可绑定死信交换机(dead letter exchange),将信息publish到死信交换机中后可被绑定交换机的死信队列消费,利用这一特性可以实现延迟队列,下边是相关代码:
$config = [
'host' => 'localhost',
'vhost' => '/',
'port' => 5672,
'login' => 'admin',
'password' => 'admin'
];
//链接broker
$conn = new AMQPConnection($config);
if(!$conn->connect()) {
echo "cannot connect to broker.";
exit();
}
//创建一个通道
$ch = new AMQPChannel($conn);
//创建死信交换机以及队列
$dlxName = "dlx_exchange";
$dlxKey = "dlx_key";
$dlx = new AMQPExchange($ch);
$dlx->setName($dlxName);
$dlx->setType(AMQP_EX_TYPE_DIRECT);
$dlx->setFlags(AMQP_DURABLE);
$dlx->declareExchange();
$dlxQ = new AMQPQueue($ch);
$dlxQ->setName('dlx_queue');
$dlxQ->setFlags(AMQP_DURABLE);
$dlxQ->declareQueue();
$dlxQ->bind($dlx->getName(), $dlxKey);
//需要被delay的交换机
$ex = new AMQPExchange($ch);
$routeKey = "key_2";
$exchangeName = "exchange_delayed";
$ex->setName($exchangeName);
$ex->setType(AMQP_EX_TYPE_DIRECT);
$ex->setFlags(AMQP_DURABLE);
$ex->declareExchange();
//被delayed的队列
$q = new AMQPQueue($ch);
$q->setName('queue_delayed');
$q->setFlags(AMQP_DURABLE);
$arguments = [
'x-message-ttl' => 10000, //消息TTL
'x-dead-letter-exchange' => $dlxName, //死信发送的交换机
'x-dead-letter-routing-key' => $dlxKey, //死信routeKey
];
//设置属性
$q->setArguments($arguments);
$q->declareQueue();
$q->bind($ex->getName(), $routeKey);
//发送消息
$ex->publish("消息10秒后将被delay", $routeKey, AMQP_NOPARAM, array('delivery_mode' => 2));
需要注意这三个参数就可以了,x-message-ttl设置队列中消息的生存期,超过这个时间消息将变成死信,也可以在单条消息publish的时候设置ttl,rabbitmq会取两者中较小者;x-dead-letter-exchange即设置死信交换机的名字,死信将会发送到这个交换机上;x-dead-letter-routing-key路由key,rabbitmq发送和消费消息都需要有相应的routeKey,消费队列要和这里的routeKey相同。通过以上方法,队列中过期的消息将会自动发送到死信交换机上,绑定死信队列后即可做相关的相关的消费逻辑处理。
rabbitmq默认是没有安装rabbitmq_delayed_message_exchange插件的,可以自行下载rabbitmq_delayed_message_exchange插件,解压后将.ez文件放到rabbitmq安装目录下的plugins目录里,然后执行以下命令激活插件:
rabbitmq-plugins enable rabbitmq_delayed_message_exchange
之后执行:rabbitmq-plugins list即可看到插件已被激活。
激活后在创建交换机的时候就可选x-delayed-message类型了:
$config = [
'host' => 'localhost',
'vhost' => '/',
'port' => 5672,
'login' => 'admin',
'password' => 'admin'
];
//链接broker
$conn = new AMQPConnection($config);
if(!$conn->connect()) {
echo "cannot connect to broker.";
exit();
}
//创建一个通道
$ch = new AMQPChannel($conn);
//创建延迟交换机
$exName = "delay_exchange";
$exKey = "route_key2";
$arguments = [
'x-delayed-type' => 'direct',
];
$ex = new AMQPExchange($ch);
$ex->setName($exName);
$ex->setType('x-delayed-message');
$ex->setArguments($arguments);
$ex->setFlags(AMQP_DURABLE);
$ex->declareExchange();
$exQ = new AMQPQueue($ch);
$exQ->setName('delay_queue');
$exQ->setFlags(AMQP_DURABLE);
$exQ->declareQueue();
$exQ->bind($ex->getName(), $exKey);
//发送消息
$ex->publish("消息10秒后将被delay", $exKey, AMQP_NOPARAM, array('delivery_mode' => 2, 'headers' => ['x-delay' => 10000]));
需要注意的有两点,一是交换机的arguments设置项里需要加x-delayed-type,否则会出问题;二是消息在publish的时候需要在headers中加x-delay项,表示延迟多长时间从交换机中发送到队列中。
以上就是rabbitmq实现延迟队列的两种方式。