RabbitMQ消息队列
为什么使用MQ?
- 异步提速
- 应用解耦
- 削峰填谷
- 保证有序性
- 可恢复性
消息队列的产品
- RabbitMQ:基于JMS实现, 比较均衡, 不是最快的, 也不是最稳定的
- ActiveMQ
- RocketMQ:基于JMS,阿里巴巴产品,目前已经捐献给apahce, 还在孵化器中孵化.
- Kafaka:类似MQ的产品;分布式消息系统,高吞吐量, 目前最快的消息服务器, 不保证数据完整性
- ZeroMQ
AMQP和JMS
- AMQP协议:一个提供统一消息服务的应用层标准高级消息队列协议,是应用层协议的一个开放标准,为面向消息的中间件设计
- 跨语言
- 跨平台
- JMS:JMS即Java消息服务(JavaMessage Service)应用程序接口,是一个Java平台中关于面向消息中间件
(MOM)的API,用于在两个应用程序之间,或分布式系统中发送消息,进行异步通信
- 只适用于java
应用场景
- 双十一商品秒杀/抢票功能实现
- 积分兑换(积分可用于多平台)
- 积分兑换模块,有一个公司多个部门都要用到这个模块,这时候就可以通过消息队列解耦这个特性来实 现。 各部门系统做各部门的事,但是他们都可以用这个积分系统进行商品的兑换等。其他模块与积分模 块完全解耦。
- 大平台用户注册:用户大数据分析、发送邮件
- 用户注册真实操作步骤:
- 注册后需要送短信给用户
- 可能发送邮件给用户
- 用户注册选择的兴趣标签,进行用户分析,推荐内容
- 发送给用户指南的系统通知
- 用户注册真实操作步骤:
Rabbit结构图
- Producer:消息的提供者
- Connection:publisher/consumer 和 broker 之间的 TCP 连接
- Channel: 消息通道,在客户端的每个连接里,可建立多个channel,每个channel代表一个会话 任务
- broker:RabbitMQ Server
- VHost: 虚拟主机,一个broker里可以开设多个vhost,用作不同用户的权限分离
- Exchange:消息交换机,它指定消息按什么规则,路由到哪个队列
- Queue:消息队列载体,每个消息都会被投入到一个或多个队列
- VHost: 虚拟主机,一个broker里可以开设多个vhost,用作不同用户的权限分离
- Consumer:消息的消费者
Spring Boot整合RabbitMQ
1. Product
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.1.9.RELEASE</version>
<relativePath/>
</parent>
<dependencies>
<!--amqp协议的起步依赖坐标-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-amqp</artifactId>
</dependency>
<!--rabbit测试依赖坐标-->
<dependency>
<groupId>org.springframework.amqp</groupId>
<artifactId>spring-rabbit-test</artifactId>
<scope>test</scope>
</dependency>
<!--SpringBoot测试依赖坐标-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
spring:
rabbitmq:
host: xxx.xxx.xxx.xxx
port: 5672
virtual-host: /wangqyjs
username: guest
password: guest
2. Consumer
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.1.9.RELEASE</version>
<relativePath/>
</parent>
<dependencies>
<!--amqp协议的起步依赖坐标-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-amqp</artifactId>
</dependency>
</dependencies>
spring:
rabbitmq:
host: xxx.xxx.xxx.xxx
port: 5672
virtual-host: /wangqyjs
username: guest
password: guest
RabbitMQ五种工作模式
1. 简单模式
-
有一个默认交换机
-
创建queue
-
Type : Classic
-
Name:自定义(simple_queue)
-
-
生产者代码:向simple_queue发送100条数据
@RunWith(SpringRunner.class) @SpringBootTest public class RabbitmqProductorApplicationTests { @Autowired private RabbitTemplate rabbitTemplate; @Test public void testSimpleQueue() { for (int i = 0; i < 100; i++) { rabbitTemplate.convertAndSend("simple_queue","测试simplequeue"+i); } } } -
消费者代码:创建监听器
- @RabbitListener(queues = "simple_queue")
- @RabbitHandler
@Component @RabbitListener(queues = "simple_queue") public class SimpleListener { @RabbitHandler public void simpleHandler(String msg) { System.out.println(msg); } }
2. Work queues工作队列模式
-
有一个默认交换机
-
该模式,创建的消息会平均分配给监听者处理。
-
创建queue
- Type : Classic
- Name:自定义(work_queue)
-
生产者代码:向simple_queue发送100条数据
@RunWith(SpringRunner.class) @SpringBootTest public class RabbitmqProductorApplicationTests { @Autowired private RabbitTemplate rabbitTemplate; @Test public void testSimpleQueue() { for (int i = 0; i < 100; i++) { rabbitTemplate.convertAndSend("work_queue","测试workqueue"+i); } } } -
消费者代码
@Component @RabbitListener(queues = "work_queue") public class WorkListener1 { @RabbitHandler public void workQueueHandler(String msg) { System.out.println("workQueueHandler1 处理了" + msg); } } @Component @RabbitListener(queues = "work_queue") public class WorkListener2 { @RabbitHandler public void workQueueHandler(String msg) { System.out.println("workQueueHandler2 处理了" + msg); } }
3. 发布订阅模式Publish/Subscribe
-
交换机绑定多个队列,交换机接受的消息会发送给所有绑定的队列
-
该方式实现异步解耦
-
每个消费者监听自己的队列
-
生产者将消息发给broker,由交换机将消息转发到绑定此交换机的每个队列,每个绑定交换机的 队列都将接收到消息
-
创建queue
- Type : Classic
- Name:自定义(fanout_queue1)
- Name:自定义(fanout_queue2)
-
创建exchange
- Name:fanout_exchange
- Type:fanout
- Bingings:fanout_queue1、fanout_queue2
-
生产者代码
- exchange 指定交换器
- routingKey 路由键设定为 ”“
- object 发送的内容
@RunWith(SpringRunner.class) @SpringBootTest public class RabbitmqProductorApplicationTests { @Autowired private RabbitTemplate rabbitTemplate; @Test public void fanoutTest() { for (int i = 0; i < 100; i++) { rabbitTemplate.convertAndSend("fanout_exchange","","测试fanout_exchange"+i); } } } -
消费者代码
@Component @RabbitListener(queues = "fanout_queue1") public class fanoutQueue1 { @RabbitHandler public void fanoutHandler(String msg) { System.out.println(msg); } } @Component @RabbitListener(queues = "fanout_queue2") public class fanoutQueue2 { @RabbitHandler public void fanoutHandler(String msg) { System.out.println(msg); } }
4. Routing路由模式
-
队列与交换机的绑定,而是要指定一个RoutingKey
-
创建queue
- Type : Classic
- Name:自定义(routing_queue1)
- Name:自定义(routing_queue2)
- Name:自定义(routing_queue3)
-
创建exchange
- Name:routing_exchange
- Type:direct
- Bingings:routing_queue1、routing_queue2、routing_queue3
-
消息的发布者代码
@RestController public class ExchangeQueueController { @Autowired private RabbitTemplate rabbitTemplate; @RequestMapping("/rabbit/info") public String testRountingC(@RequestParam String exchange, @RequestParam String routingKey, @RequestParam String msg){ System.out.println(exchange); System.out.println(routingKey); System.out.println(msg); rabbitTemplate.convertAndSend(exchange,routingKey,msg); return "发送成功"; } } -
消息的消费者代码
@Component @RabbitListener(queues = "routing_queue1") public class RountingQueue1 { @RabbitHandler public void rountingQueueTest(String msg){ System.out.println("rounting_queue1处理" + msg); } } @Component @RabbitListener(queues = "routing_queue2") public class RountingQueue2 { @RabbitHandler public void rountingQueueTest(String msg){ System.out.println("rounting_queue2处理" + msg); } } @Component @RabbitListener(queues = "routing_queue3") public class RountingQueue3 { @RabbitHandler public void rountingQueueTest(String msg){ System.out.println("rounting_queue3处理" + msg); } }
5. Topics通配符模式
-
队列与交换机的绑定,而是要指定一个RoutingKey
- #:匹配一个或多个词,多个词用点号分隔
- *:匹配不多不少恰好1个词
-
创建queue
- Type : Classic
- Name:自定义(topic_queue1)
- Name:自定义(topic_queue2)
-
创建exchange
- Name:topic_exchange
- Type:topic
- Bingings:topic_queue1、topic_queue2
-
消息的发布者代码
@RestController public class ExchangeQueueController { @Autowired private RabbitTemplate rabbitTemplate; @RequestMapping("/rabbit/info") public String testRountingC(@RequestParam String exchange, @RequestParam String routingKey, @RequestParam String msg){ System.out.println(exchange); System.out.println(routingKey); System.out.println(msg); rabbitTemplate.convertAndSend(exchange,routingKey,msg); return "发送成功"; } } -
消息的消费者代码
@Component @RabbitListener(queues = "topic_queue1") public class TopicQueue1 { @RabbitHandler public void topicHandler(String msg) { System.out.println("topic_queue1 "+msg); } } @Component @RabbitListener(queues = "topic_queue2") public class TopicQueue2 { @RabbitHandler public void topicHandler(String msg) { System.out.println("topic_queue2 "+msg); } }