前言
上一篇 RabbitMQ 入门 对 RabbitMQ 做了入门了解并介绍了他的一种工作模式-简单模式。本篇来学习一下 RabbitMQ 的第二种工作模式 - work queue。
worke queue介绍
先来看官网的一张图, 如图所示,我们可以看到,与上一篇介绍的简单模式不同之处在于,这里存在多个消费者。多个消费者如何处理队列中的消息,我们后面会说道。
work queue 的作用
work queue 的思想 是避免立即去执行一些耗时任务,并且一直等待任务完成, 而是分发耗时的任务给多个worker, 也就是生产者将消息发送到队列,然后消费者可以轮流从队列中读取消息。
RabbitMQ 的一些特性
接下来介绍 RabbitMQ 使用过程中容易遇到的问题,以及解决办法。
消息确认机制
消息确认机制作用是当某个客户端突然挂掉了,消息不会丢失。
处理一个消息需要几秒钟,你可能想知道,当一个消费者正在处理一个很耗时的任务时,挂掉了会发生什么。如果不做特殊处理,当mq把消息传递给消费者时, 这个消息就会被立即删除。所以此时如果你杀掉一个消费者时,这个消费者正在处理以及未处理的消息都会丢失。面对以上的情况,我们通常想把消息交给其他消费者去处理。这个时候我们就可以使用rabbitmq的消息确认机制-消费者收到消息后,会去通知mq我已经收到消息了,然后你可以把消息删除了。如果一个消费者挂掉了,并且没有发送 ack 给生产者,此时生产者就会立即把消息重新发送到另一个还活着的消费者手中。消息确认机制默认是打开的,(autoAck=false)channel.basicAck(delivery.getEnvelope().getDeliveryTag(), false); 如果忘记 basicAck,会带来很严重的后果,如果你的客户端退出,消息会重新发送,最终RabbitMQ 会吃掉很多内存。
消息持久化
消息持久化的作用是当RabbitMQ Server 挂掉了,消息不会丢失
当mq 退出或崩掉的时候,它就会“忘记”那些队列和消息,除非你告诉他。解决这种问题的办法就是将队列 和 消息本地持久化。
1. 队列持久化
在消费者和生产者客户端同时声明
channel.queueDeclare("hello", durable, false, false, null);// durable = true;
这里需要注意的是: RabbitMQ 是不允许创建一个已存在的队列的,即使你使用不同参数。
2. 消息持久化
channel.basicPublish("", "task_queue", MessageProperties.PERSISTENT_TEXT_PLAIN, message.getBytes());
注意: 即使做了消息持久化,也不能完全保证消息丢失,在RabbitMQ 接收到消息还没保存的这段时间,消息仍有可能会丢失。因此消息持久化仅仅能满足一些简单的任务队列。如果需要更加健壮的机制,需要学习下 Publisher Confirms
Fair dispatch
如果我们有奇数个 "重量级" 的消息,和偶数个 "轻量级" 的消息, 那么在我们的程序运行中,会出现一个 worker 总是很忙的情况, 因为它不停地在处理 那些 "重量级" 的消息。但是RabbitMQ 却不知道谁轻松谁不轻松。
如何预防?
`channel.basicQos(prefetchCount);// prefetchCount = 1;`
这行代码的作用就是告诉 RabbitMQ 不要在某一时刻,发送多个消息给worker, 等worker 确认完之后,再发送