RabbitMQ工作队列
工作队列也叫任务队列,主要思想就是避免立即执行资源密集型任务,必须等待完成,才能继续下一个任务,你可以运行多个工人,队列里的工作他们可以共同不重复的完成。
1:队列优点之一就是能够轻松平行的工作。如果积压工作,我们可以增加更多的工人。默认情况下,rabbitMQ将按顺序将每条消息发送给下一个工作者。平均而言工作者将获得相同的数量消息。这种分发消息的方式成为循环法。
2:一般rabbitMQ像工作者发送消息完毕后会立即将其标记为删除,在这种情况下,如果你杀死了一个工作者,我们将失去刚刚处理的消息,我们也将失去所有派发给这个工作者未处理的消息。如果你不想失去任何消息,比如一名工作者死亡后,你希望将他的任务交于另外一名工人,为了确保消息永不丢失,rabbitMQ支持消息确认,就是工作者发回确认告知rabbitMQ已经收到消息并且已经处理,rabbitMQ可以自由的删除该消息。
增加消息确认:
channel.BasicConsume(queue: "task_queue", autoAck: false, consumer: consumer);
3:在消息确认情况下,工作者死亡(通道关闭,链接关闭或TCP链接丢失),rabbitMQ将理解消息尚未被完全处理,并将未完全处理的消息重新排队,如果有其他工作者同时上线,则会迅速发送给其他工作者处理,这样的话即使工作者偶尔死亡,也可以确保没有任何信息丢失。
4:如果工作者人没有消息确认的话,后果很严重。当该工作者退出时,消息将重新传递,但是rabbitMQ将会消耗越来越多的内存,因为rabbitMQ不能释放未被处理的消息。
5:消息的持久性,上面讲述了即使工作者死亡,任务也不会丢失。但是如果rabbitMQ服务器挂掉,我们的任务仍然会丢失,如果想要解决该问题则需要做两件事,我们分别把队列和消息标记为持久。
定义队列为持久的:
channel.QueueDeclare(queue: "hello",
durable: true,
exclusive: false,
autoDelete: false,
arguments: null);
注意:该命令本身是正确的,但是如果在此之前已经一定了一个名为hello的队列,那么该设置就不起作用了,因为rabbitMQ不允许你使用不同的参数定义一个已经存在的队列,并且会向任何尝试这样做的程序返回一个错误。有一个快速的解决办法就是生命一个不同名称的队列,哈哈哈哈。。。。
这样的话,及时rabbitMQ挂掉或者重新启动,该队列也不会丢失,接下来就需要将该队列里的消息标记为持久的了,怎么标记呢?这样做:
通过设置IBasicProperties.SetPersistent为true
var properties = channel.CreateBasicProperties();
properties.Persistent = true ;
再次注意:将消息标记为持久的并不能完全保证邮件不会丢失,尽管它告诉rabbitMQ将消息保存到磁盘,但是当rabbitMQ接受消息并且还没有保存消息时,仍然有一个很短暂的窗口,它可能只是保存在缓存中,而不是写入磁盘。持久性保证并不强,但对于我们简单的任务队列来说已经足够了,但是你如果需
要消息队列的持久化的强保证,则可以使用 publisher confirms
6:公平分发,你可能注意到调度仍然不能按照我们的要求工作,例如在有两名工作者的情况下,当所有奇怪信息都很重或者很轻时,一个工作人员就会一直忙,另外一名工作人员几乎很闲,那么rabbitMQ可能并不知道,仍然的均匀发送消息。发生这种情况是因为rabbitMQ只在消息进入队列时调度消息,它并
没有考虑工作者未完成的消息数量。只是盲目地不停把n条消息分发给n个工作者。为了改变这种行为,我们可以使用 basicQos 方法个 prefetchCount=1 设置,这样设置就是告诉rabbitMQ一次不能给一个工作者多个消息,换句话来说就是不要像工作者发送新消息,直到处理并确认了前一个消息。相反它会将
消息分派给下一个还不忙的工作人员。
在工作者里面设置:
channel.BasicQos(0,1,false);