訊息確認機制
當把basic_consume的引數no_ack設定為true時,訊息達到消費者時就立刻被標記為刪除狀態,如果這時一個worker的訊息來不及執行完成就被中止掉,那麼這條訊息就會丟失,所以需要一個訊息確認機制,當worker掛掉後,把訊息重新分發給另一個woker執行
方法:將no_ack設定為false,然後在回撥函式中確認訊息
$callback = function($msg){
echo " [x] Received ", $msg->body, "
";
sleep(substr_count($msg->body, `.`));
echo " [x] Done", "
";
$msg->delivery_info[`channel`]->basic_ack($msg->delivery_info[`delivery_tag`]);
};
$channel->basic_consume(`task_queue`, ``, false, false, false, false, $callback);
需要特別注意的是,如何忘記確認訊息,將耗盡記憶體。檢視未確認訊息命令:
sudo rabbitmqctl list_queues name messages_ready messages_unacknowledged
訊息持久化問題
雖然訊息確認機制能夠保證消費者掛掉時訊息不丟失,但是當rabbitmq掛掉時,那就沒法保證了,這時就需要持久化
了。
方法:佇列和訊息必須設定為持久化
(1) 佇列持久化:生成者和消費者宣告佇列引數durable設定為true,已存在的佇列不能重新設定引數值。命令如下:
$channel->queue_declare(`task_queue`, false, true, false, false);
(2) 訊息持久化:訊息delivery_mode設定為2,如下:
$msg = new AMQPMessage($data,
array(`delivery_mode` => AMQPMessage::DELIVERY_MODE_PERSISTENT)
);
公平分發問題
問題:當多個worker處理佇列訊息,rabbitmq迴圈均勻分配訊息到分一個worker,如果此時其中一個worker分配到比較耗時的任務,那麼會出現這個worker會比較忙碌,而其他worker比較清閒的情況。
方法:在worker處理和確認訊息之前,不要再向worker傳送新訊息,而是向下一個清閒的worker傳送,把prefetch引數設定為1.
當然,如果所有的worker都很忙,這時候應該增加worker數量
$channel->basic_qos(null, 1, null);