Work Queues在消息队列(MQ)中扮演着基础且重要的角色,它主要用于实现任务的异步处理和负载均衡。其应用范围广泛,涵盖了从简单的任务分发到复杂的微服务架构间的通信。无论是处理耗时的任务、平滑流量峰值,还是增强系统的可扩展性和可靠性,Work Queues都能提供有效的解决方案。它是构建高效率、松耦合分布式系统的关键模式之一,适用于需要确保消息传递顺序及消费者间负载均衡的场景。
目录
[Work Queues是什么](#Work Queues是什么)
[为什么采用Work Queues](#为什么采用Work Queues)
[Work Queues测试](#Work Queues测试)
Work Queues是什么
Work Queues(工作队列)模型是一种消息队列模式,用于在生产者和多个工作者(消费者)之间分配耗时任务。在此模型中,每个任务作为一个消息发送到队列,然后由多个工作者之一接收并处理。这样可以并行处理多个任务,提高处理速度和系统效率,特别适合于需要执行耗时操作的任务分发场景。通过负载均衡的方式,Work Queues能够确保任务被均匀地分配给空闲的工作者,从而优化资源利用。(让 多个消费者 绑定到一个队列,共同消费队列中的消息)
如下图所示(未加入交换机):

为什么采用Work Queues
任务分配与负载均衡:在没有工作队列的情况下,如果多个消费者直接从同一个任务源获取任务,可能会导致某些消费者过载,而其他消费者闲置的问题。通过使用Work Queues,任务可以被均匀地分发给所有空闲的工作者,实现自动化的负载均衡。
提高处理效率:对于耗时的任务,单个消费者可能无法及时处理所有的请求,导致延迟增加。使用Work Queues可以让多个消费者同时处理队列中的任务,从而显著提高系统的整体处理能力和响应速度。
解耦生产者和消费者:生产者只需将任务发送到队列中,无需关心任务实际由谁处理、如何处理等细节。这种机制使得生产者和消费者之间实现了松耦合,方便了系统的扩展和维护。
增强系统可靠性:当一个消费者失败或需要维护时,其他消费者可以继续处理队列中的任务,保证了系统的高可用性和可靠性。此外,消息队列通常会提供持久化功能,确保即使系统崩溃,未完成的任务也不会丢失。
简而言之,使用work 模型,多个消费者共同处理消息,消息处理的速度就提高 **了,**提高了系统的灵活性、可靠性 。
Work Queues测试
开始测试
首先,新建一个队列work.queue

然后在publisher服务中的SpringAmqpTest类中添加一个测试方法:
java
/**
* 模拟消息堆积
* @throws InterruptedException
*/
@Test
public void testWorkQueue() throws InterruptedException {
// 队列名称
String queueName = "work.queue";
// 消息
String message = "hello rabbitmq";
// 发送消息
for (int i = 0; i < 50; i++) {
// 发送消息,每20毫秒发送一次,相当于每秒发送50条消息
rabbitTemplate.convertAndSend(queueName, message + i);
Thread.sleep(20);
}
}
要模拟多个消费者绑定同一个队列,我们在consumer服务的SpringRabbitListener中添加2个新的方法:
java
@RabbitListener(queues = "work.queue")
public void listenWorkQueue1(String msg) throws InterruptedException {
log.info("消费者1收到消息:{}", msg);
Thread.sleep(20);
}
@RabbitListener(queues = "work.queue")
public void listenWorkQueue2(String msg) throws InterruptedException {
log.info("消费者1收到消息:{}", msg);
Thread.sleep(200);
}
注意到这两消费者,都设置了Thead.sleep
,模拟任务耗时:
消费者1 sleep了20毫秒,相当于每秒钟处理50个消息.
消费者2 sleep了200毫秒,相当于每秒处理5个消息
运行后控制台结果如下:

结果描述:可以看到消费者1和消费者2竟然每人消费了25条消息,消息是平均分配给每个消费者,并没有考虑到消费者的处理能力。导致1个消费者空闲,另一个消费者忙的不可开交。没有充分利用每一个消费者的能力,最终消息处理的耗时远远超过了1秒。这样显然是有问题的。
问题解决
在spring中有一个简单的配置,可以解决这个问题。我们修改consumer服务的application.yml文件,添加配置:
java
spring:
rabbitmq:
listener:
simple:
prefetch: 1 # 每次只能获取一条消息,处理完成才能获取下一个消息
再次测试,发现结果如下:
java
消费者1接收到消息:【hello rabbitmq0】16:28:04.400892
消费者2----------接收到消息:【hello rabbitmq1】16:28:04.412429500
消费者1接收到消息:【hello rabbitmq2】16:28:04.443088500
消费者1接收到消息:【hello rabbitmq3】16:28:04.474896500
消费者1接收到消息:【hello rabbitmq4】16:28:04.505468900
消费者1接收到消息:【hello rabbitmq5】16:28:04.537058900
消费者1接收到消息:【hello rabbitmq6】16:28:04.568139200
消费者1接收到消息:【hello rabbitmq7】16:28:04.599120700
消费者1接收到消息:【hello rabbitmq8】16:28:04.629452700
消费者2----------接收到消息:【hello rabbitmq9】16:28:04.660120800
消费者1接收到消息:【hello rabbitmq10】16:28:04.691873500
消费者1接收到消息:【hello rabbitmq11】16:28:04.722122900
消费者1接收到消息:【hello rabbitmq12】16:28:04.754236300
消费者1接收到消息:【hello rabbitmq13】16:28:04.783756100
消费者1接收到消息:【hello rabbitmq14】16:28:04.814155600
消费者1接收到消息:【hello rabbitmq15】16:28:04.846354400
消费者1接收到消息:【hello rabbitmq16】16:28:04.877538200
消费者2----------接收到消息:【hello rabbitmq17】16:28:04.908657700
消费者1接收到消息:【hello rabbitmq18】16:28:04.939493800
消费者1接收到消息:【hello rabbitmq19】16:28:04.970395700
消费者1接收到消息:【hello rabbitmq20】16:28:05.000535100
消费者1接收到消息:【hello rabbitmq21】16:28:05.031434700
消费者1接收到消息:【hello rabbitmq22】16:28:05.061435400
消费者1接收到消息:【hello rabbitmq23】16:28:05.092037600
消费者1接收到消息:【hello rabbitmq24】16:28:05.124013300
消费者2----------接收到消息:【hello rabbitmq25】16:28:05.153791500
消费者1接收到消息:【hello rabbitmq26】16:28:05.184977800
消费者1接收到消息:【hello rabbitmq27】16:28:05.216572900
消费者1接收到消息:【hello rabbitmq28】16:28:05.247382300
消费者1接收到消息:【hello rabbitmq29】16:28:05.279566600
消费者1接收到消息:【hello rabbitmq30】16:28:05.309735600
消费者1接收到消息:【hello rabbitmq31】16:28:05.340732900
消费者1接收到消息:【hello rabbitmq32】16:28:05.370816400
消费者2----------接收到消息:【hello rabbitmq33】16:28:05.401774
消费者1接收到消息:【hello rabbitmq34】16:28:05.431728
消费者1接收到消息:【hello rabbitmq35】16:28:05.463604200
消费者1接收到消息:【hello rabbitmq36】16:28:05.494062400
消费者1接收到消息:【hello rabbitmq37】16:28:05.524519700
消费者1接收到消息:【hello rabbitmq38】16:28:05.555449200
消费者1接收到消息:【hello rabbitmq39】16:28:05.586951
消费者1接收到消息:【hello rabbitmq40】16:28:05.618628100
消费者2----------接收到消息:【hello rabbitmq41】16:28:05.648597700
消费者1接收到消息:【hello rabbitmq42】16:28:05.679561400
消费者1接收到消息:【hello rabbitmq43】16:28:05.710259900
消费者1接收到消息:【hello rabbitmq44】16:28:05.740510700
消费者1接收到消息:【hello rabbitmq45】16:28:05.771589
消费者1接收到消息:【hello rabbitmq46】16:28:05.801896700
消费者1接收到消息:【hello rabbitmq47】16:28:05.833378300
消费者1接收到消息:【hello rabbitmq48】16:28:05.863505700
消费者2----------接收到消息:【hello rabbitmq49】16:28:05.894284
可以发现,由于消费者1处理速度较快,所以处理了更多的消息;消费者2处理速度较慢,只处理了7条消息。而最终总的执行耗时也在1秒左右,大大提升。
总结
Work模型的使用:
多个消费者绑定到一个队列,同一条消息只会被一个消费者处理,通过设置prefetch来控制消费者预取的消息数量。
Work Queues成为优化分布式系统中任务处理流程的理想选择,尤其适用于需要异步处理、负载均衡和系统扩展的应用场景。