RabbitMQ 使用中的注意事项

2019-09-11 0 By admin

一、轮询调度

我们使用任务队列的好处之一就是使任务可以并行化,增加系统的并行处理能力。如果我们正在建立一个积压的工作,我们可以紧紧增加更多的Worker实例就可以完成大量工作的处理,修改和维护就很容易。
默认情况下,RabbitMQ将会发送每一条消息给序列中每一个消费者。每个消费者都会得到相同数量的信息。这种分发消息的方式叫做轮询。

二、消息确认

处理一个任务可能需要几秒钟。如果有一个消费者开始了一个长期的任务,并且只做了一部分就发生了异常,你可能想知道到底发生了什么。
如果代码中没有设置消息确认机制,RabbitMQ发送一个消息给客户后,会立即将消息从内存中移除。在这种情况下,如果你关掉了一个Worker,我们将失去它正在处理的信息。我们也将丢失发送给该特定worker但尚未处理的所有信息。
但我们不想失去任何任务。如果一个Worker出现了问题,我们希望把这个任务交给另一个Woker。
为了确保消息不会丢失,RabbitMQ支持消息确认机制。ACK(Nowledgement)确认消息是从【消息使用者】发送回来告诉RabbitMQ结果的一种特殊消息,确认消息告诉RabbitMQ指定的接受者已经收到、处理,并且RabbitMQ你可以自由删除它。
如果一个【消费者Consumer】死亡(其通道关闭,连接被关闭,或TCP连接丢失)不会发送ACK,RabbitMQ将会知道这个消息并没有完全处理,将它重新排队。如果有其他用户同时在线,它就会快速地传递到另一个【消费者】。这样你就可以肯定,没有消息丢失,即使【Worker】偶尔死了或者出现问题。
在没有任何消息超时;当【消费者】死亡的时候RabbitMQ会重新发送消息。只要是正常的,即使处理消息需要很长很长的时间也会重发消息给【消费者】。
消息确认的机制默认是打开的。

三、持久性的消息

我们已经学会了如何确保即使【消费者】死亡,任务也不会丢失。但是如果RabbitMQ服务器停止了,我们的任务仍然会丢失的。
当RabbitMQ退出或死机会清空队列和消息,除非你告诉它即使宕机也不能丢失任何东西。要确保消息不会丢失。
有两件事情我们是必需要做的:我们需要将队列和消息都标记为持久的。

3.1、关于消息持久性的注意

将消息标记为持久性并不能完全保证消息不会丢失。
虽然该设置告诉RabbitMQ时时刻刻把保存消息到磁盘上,但是这个时间间隔还是有的,当RabbitMQ已经接受信息但并没有保存它,此时还有可能丢失。
另外,RabbitMQ不会为每个消息调用fsync(2)–它可能只是保存到缓存并没有真正写入到磁盘。
虽然他的持久性保证不强,但它我们简单的任务队列已经足够用了。如果您需要更强的保证,那么您可以使用Publisher Comfirms。

四、公平调度

你可能已经注意到,调度仍然没有像我们期望的那样的工作。
例如,在两个Workers的情况下,当所有的奇数消息是沉重的,甚至消息是轻的,一个Worker忙个不停,而另一个Worker几乎没事可做。RabbitMQ对上述情况一无所知,仍将消息均匀发送。
发生这种情况是因为当有消息进入队列的时候RabbitMQ才仅仅调度了消息。它根本不看【消费者】未确认消息的数量,它只是盲目的把第N个消息发送给第N个【消费者】。

为了避免上述情况的发生,我们可以使用 prefetchcount = 1 的设置来调用BasicQos方法。
这个方法告诉RabbitMQ在同一时间不要发送多余一个消息的数据给某个【Worker】。或者,换句话说,当某个消息处理完毕,并且已经收到了消息确认之后,才可以继续发送消息给那个【Worker】。相反,它将把消息分配给给下一个不忙的【Worker】。

4.1、注意队列大小

如果所有的工人都很忙,你的队列可以填满。你要留意这一点,也许会增加更多的【Worker】,或者有其他的策略。