RabbitMQ的五种消息队列,字节跳动后端面试题java

本文详细介绍了Java中的消息队列操作,包括生产者使用`MQ`发送消息,消费者轮询接收,以及如何通过调整`basicQos`和`basicAck`实现能者多劳原则。还探讨了发布/订阅模式在解决效率问题上的应用。
摘要由CSDN通过智能技术生成

public class SimpleProducer {

public static void main(String[] args) throws IOException {

Connection connection = MQUtils.getConnection();

//创建通道

Channel channel = connection.createChannel();

//定义队列

channel.queueDeclare(MQUtils.QUEUE_NAME,false,false,false,null);

String msg = “Hello World!”;

//发布消息到队列

channel.basicPublish(“”,MQUtils.QUEUE_NAME,null,msg.getBytes());

channel.close();

connection.close();

}

}

运行生产者代码,管理页面点进myqueue01,在GetMessages中可以看到消息

在这里插入图片描述

消费者

/**

  • 消费者,从队列中读取简单的消息

*/

public class SimpleConsumer {

public static void main(String[] args) throws IOException, InterruptedException {

Connection connection = MQUtils.getConnection();

Channel channel = connection.createChannel();

//定义队列

channel.queueDeclare(MQUtils.QUEUE_NAME,false,false,false,null);

//创建消费者

QueueingConsumer queueingConsumer = new QueueingConsumer(channel);

//消费者消费通道中的消息

channel.basicConsume(MQUtils.QUEUE_NAME,true,queueingConsumer);

//读取消息

while(true){

QueueingConsumer.Delivery delivery = queueingConsumer.nextDelivery();

System.out.println(new String(delivery.getBody()));

}

}

}

运行读取消息

在这里插入图片描述

工作队列

==================================================================

在这里插入图片描述

工作队列,生产者将消息分发给多个消费者,如果生产者生产了100条消息,消费者1消费50条,消费者2消费50条。

生产者

/**

多对多模式的生产者,会发送多条消息到队列中

*/

public class WorkProductor {

public static void main(String[] args) throws IOException, InterruptedException {

Connection connection = MQUtils.getConnection();

Channel channel = connection.createChannel();

channel.queueDeclare(MQUtils.QUEUE_NAME,false,false,false,null);

for(int i = 0;i < 100;i++){

String msg = “Hello–>” + i;

channel.basicPublish(“”,MQUtils.QUEUE_NAME,null, msg.getBytes());

System.out.println(“send:” + msg);

Thread.sleep(10);

}

channel.close();

connection.close();

}

}

消费者1

/**

  • 多对多模式的消费者1

*/

public class WorkConsumer01 {

public static void main(String[] args) throws IOException, InterruptedException {

Connection connection = MQUtils.getConnection();

Channel channel = connection.createChannel();

channel.queueDeclare(MQUtils.QUEUE_NAME,false,false,false,null);

QueueingConsumer queueingConsumer = new QueueingConsumer(channel);

//消费者消费通道中的消息

channel.basicConsume(MQUtils.QUEUE_NAME,true,queueingConsumer);

while(true){

QueueingConsumer.Delivery delivery = queueingConsumer.nextDelivery();

System.out.println(“WorkConsumer1 receive :” + new String(delivery.getBody()));

Thread.sleep(10);

}

}

}

消费者2

/**

  • 多对多模式的消费者2

*/

public class WorkConsumer02 {

public static void main(String[] args) throws IOException, InterruptedException {

Connection connection = MQUtils.getConnection();

Channel channel = connection.createChannel();

channel.queueDeclare(MQUtils.QUEUE_NAME,false,false,false,null);

QueueingConsumer queueingConsumer = new QueueingConsumer(channel);

//消费者消费通道中的消息

channel.basicConsume(MQUtils.QUEUE_NAME,true,queueingConsumer);

while(true){

QueueingConsumer.Delivery delivery = queueingConsumer.nextDelivery();

System.out.println(“WorkConsumer2 receive :” + new String(delivery.getBody()));

Thread.sleep(1000);

}

}

}

在这里插入图片描述

在这里插入图片描述

生产者发送100个消息,两个消费者分别读取了50条。

看消息内容,发现队列发送消息采用的是轮询方式,也就是先发给消费者1,再发给消费者2,依次往复。

能者多劳


上面案例中有一个问题:消费者处理消息的速度是不一样的,消费者1处理后睡眠10毫秒(Thread.sleep(10)),消费者2是1000毫秒,速度相差100倍,但是最后处理的消息数还是一样的。这样就存在效率问题:处理能力强的消费者得不到更多的消息。

因为队列默认采用是自动确认机制,消息发过去后就自动确认,队列不清楚每个消息具体什么时间处理完,所以平均分配消息数量。

实现能者多劳:

  1. channel.basicQos(1);限制队列一次发一个消息给消费者,等消费者有了反馈,再发下一条

  2. channel.basicAck 消费完消息后手动反馈,处理快的消费者就能处理更多消息

  3. basicConsume 中的参数改为false

修改消费者1和2

/**

  • 多对多模式的消费者1

*/

public class WorkConsumer1 {

public static void main(String[] args) throws IOException, InterruptedException {

Connection connection = MQUtils.getConnection();

Channel channel = connection.createChannel();

channel.queueDeclare(MQUtils.QUEUE_NAME,false,false,false,null);

//同一时刻服务器只发送一条消息给消费者

channel.basicQos(1);

QueueingConsumer queueingConsumer = new QueueingConsumer(channel);

//true是自动返回完成状态,false表示手动

channel.basicConsume(MQUtils.QUEUE_NAME,false,queueingConsumer);

while(true){

QueueingConsumer.Delivery delivery = queueingConsumer.nextDelivery();

System.out.println(“WorkConsumer1 receive :” + new String(delivery.getBody()));

Thread.sleep(10);

//手动确定返回状态,不写就是自动确认

channel.basicAck(delivery.getEnvelope().getDeliveryTag(),false);

}

}

}

/**

  • 多对多模式的消费者2

*/

public class WorkConsumer2 {

public static void main(String[] args) throws IOException, InterruptedException {

Connection connection = MQUtils.getConnection();

Channel channel = connection.createChannel();

channel.queueDeclare(MQUtils.QUEUE_NAME,false,false,false,null);

//同一时刻服务器只发送一条消息给消费者

channel.basicQos(1);

QueueingConsumer queueingConsumer = new QueueingConsumer(channel);

//true是自动返回完成状态,false表示手动

channel.basicConsume(MQUtils.QUEUE_NAME,false,queueingConsumer);

while(true){

QueueingConsumer.Delivery delivery = queueingConsumer.nextDelivery();

System.out.println(“WorkConsumer2 receive :” + new String(delivery.getBody()));

Thread.sleep(1000);

//手动确定返回状态,不写就是自动确认

channel.basicAck(delivery.getEnvelope().getDeliveryTag(),false);

}

}

}

再次执行消费者2只消费了5条,消费者消费95条消息

在这里插入图片描述

在这里插入图片描述

发布/订阅

===================================================================

在这里插入图片描述

发布/订阅模式和Work模式的区别是:Work模式只存在一个队列,多个消费者共同消费一个队列中的消息;而发布订阅模式存在多个队列,不同的消费者可以从各自的队列中处理完全相同的消息。

实现步骤:

  1. 创建交换机(Exchange)类型是fanout

  2. 交换机需要绑定不同的队列

  3. 不同的消费者从不同的队列中获得消息

  4. 生产者发送消息到交换机

  5. 再由交换机将消息分发到多个队列

新建队列

在这里插入图片描述

新建交换机

在这里插入图片描述

点击交换机,在bindings里面绑定两个队列

在这里插入图片描述

生产者

/**

  • 发布和订阅模式的生产者,消息会通过交换机发到队列

*/

public class PublishProductor {

public static void main(String[] args) throws IOException {

Connection connection = MQUtils.getConnection();

Channel channel = connection.createChannel();

//声明fanout exchange

channel.exchangeDeclare(MQUtils.EXCHANGE_NAME,“fanout”);

String msg = “Hello Fanout”;

//发布消息到交换机

channel.basicPublish(MQUtils.EXCHANGE_NAME,“”,null,msg.getBytes());

System.out.println(“send:” + msg);

channel.close();

connection.close();

}

}

消费者1

/**

  • 发布订阅模式的消费者1

  • 两个消费者绑定的消息队列不同

  • 通过交换机一个消息能被不同队列的两个消费者同时获取

  • 一个队列可以有多个消费者,队列中的消息只能被一个消费者获取

*/

public class SubscribeConsumer1 {

public static void main(String[] args) throws IOException, InterruptedException {

Connection connection = MQUtils.getConnection();

Channel channel = connection.createChannel();

channel.queueDeclare(MQUtils.QUEUE_NAME,false,false,false,null);

//绑定队列到交换机

channel.queueBind(MQUtils.QUEUE_NAME,MQUtils.EXCHANGE_NAME,“”);

QueueingConsumer queueingConsumer = new QueueingConsumer(channel);

channel.basicConsume(MQUtils.QUEUE_NAME,true,queueingConsumer);

while(true){

QueueingConsumer.Delivery delivery = queueingConsumer.nextDelivery();

System.out.println(“Consumer1 receive :” + new String(delivery.getBody()));

}

}

}

消费者2

自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数Java工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则几千的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

因此收集整理了一份《2024年Java开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
img
img
img
img

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Java开发知识点,真正体系化!

img
img

由于文件比较大,这里只是将部分目录大纲截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且后续会持续更新
如果你觉得这些内容对你有帮助,可以添加V:vip1024b 备注Java获取(资料价值较高,非无偿)
img

最后

文章中涉及到的知识点我都已经整理成了资料,录制了视频供大家下载学习,诚意满满,希望可以帮助在这个行业发展的朋友,在论坛博客等地方少花些时间找资料,把有限的时间,真正花在学习上,所以我把这些资料,分享出来。相信对于已经工作和遇到技术瓶颈的朋友们,在这份资料中一定都有你需要的内容。

576334161)]
[外链图片转存中…(img-wMofNL1J-1711576334162)]
[外链图片转存中…(img-EWbo58UO-1711576334162)]

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Java开发知识点,真正体系化!

[外链图片转存中…(img-FhtpOMwq-1711576334163)]
[外链图片转存中…(img-DL3Nvoj2-1711576334163)]

由于文件比较大,这里只是将部分目录大纲截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且后续会持续更新
如果你觉得这些内容对你有帮助,可以添加V:vip1024b 备注Java获取(资料价值较高,非无偿)
[外链图片转存中…(img-X0pSFr6N-1711576334164)]

最后

文章中涉及到的知识点我都已经整理成了资料,录制了视频供大家下载学习,诚意满满,希望可以帮助在这个行业发展的朋友,在论坛博客等地方少花些时间找资料,把有限的时间,真正花在学习上,所以我把这些资料,分享出来。相信对于已经工作和遇到技术瓶颈的朋友们,在这份资料中一定都有你需要的内容。

  • 5
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值