1、RabbitMQ基本概念
消息队列有很多种,常见的是ActiveMQ、RabbitMQ、Kafka,三者依次能处理更好的数据量但是安全性也随之降低并且很可能出现数据的丢失,但是目的却是一致的:异步处理、应用解耦,流量削锋和消息通讯等问题实现高性能,高可用,可伸缩性和最终一致性。
RabbitMQ是用Erlang语言开发的AMQR的开源实现。最初起源于金融系统,用于在分布式系统中存储转发消息,在易用性、扩展性、高可用性等方面表现不俗,具体特点如下:
- 可靠性:使用一些机制来保证可靠性,如持久化、传输确认、发布确认
- 灵活的理由:进入消息队列之前,通过Exchange来路由信息的
- 消息集群:多个RabbitMQ服务器可以组成一个集群,形成一个逻辑broker
- 高可用:队列可以在集群中的机器上进行镜像,使得在部分节点出问题情况下队列仍然可用
- 多种协议:支持多种消息队列协议,如STOMP、MQTT等等
- 多语言客户端:几乎支持所有的语言
- 管理界面:提供了一个易使用的用户界面,使得用户可用监控和管理消息Broker的许多方面
- 跟踪机制:如果消息异常,RabbitMQ提供了消息跟踪机制,使用者可以找出发生了什么
- 插件机制:RabbitMQ提供了许多插件,来从多方面进行扩展,同样也可以编写自己的插件
架构图:
主要的几个概念:
- RabbitMQ Server:也叫做Broker Server,是一种传输服务。角色就是维护一条从Producer到Customer的路线,保证数据能够按照指定的方式进行传输
- Producer:消息生产者,消息生产者连接RabbitMQ服务器将消息投递到Exchange
- Consumer:消息消费者,消息消费者订阅,RabbitMQ将Queue中的消息发送到消息消费者
- Exchange:交换器,有Direct,Fanout,Topic,headers四种类型每种拥有不同的路由规则,本身不存储数据。
- Queue:队列,在RabbitMQ中负责存储消息。消息消费者通过订阅队列来获取消息,RabbitMQ中的消息都只能存储在Queue中,生产者生产消息并最终投递到Queue中,然后消费者再去使用。多对多的关系。
- RoutingKey:路由规则,通过指定路由规则指定消息流向哪。
安装:
使用docker 进行安装
docker run -di --name=rabbitmq -p 5671:5671 -p 5672:5672 -p 4369:4369 -p 15671:15671 -p 15672:15672 -p 25672:25672 rabbitmq:management
2、三种队列模式
2.1、Direct
在单节点进行消息传递的时候,可以使用这种方式。
这种情况下指定好RouteKey对应的那个指定的Queue就可以了。
使用步骤:
- 一般情况下可以使用RabbitMQ自带的Exchange
- 这种模式下不需要将Exchange进行任何绑定操作
- 消息传递,指定RouteKey,不然没法指向Queue
- 如果vhost中不存在RouteKey中指定的队列名,那么该消息会被抛弃。
具体实现:
不需要设置Exchange,是使用默认的。
代码实现分为两个部分:
- 生产者
- 消费者
pom.xml
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-amqp</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
</dependency>
application.yml
server:
port: 7100
spring:
rabbitmq:
host: localhost
生产者
我们可以先看看上面的架构图,首先将数据产生,然后进去Exchange,利用你指定的RouteKey去到达指定的Queue。
首先我们来到web界面,先创建好队列的RouteKey,方便我们去一会进行指定。
@RunWith(SpringRunner.class)
@SpringBootTest(classes = RabbitMQApplication.class)
public class Product1 {
@Autowired
private RabbitTemplate rabbitTemplate;
/**
* 直接模式
*/
@Test
public void send_msg1(){
rabbitTemplate.convertAndSend("zxc", "直接模式测试");
}
}
还需要一个消费者将队列中的消息消费掉
@Component
@RabbitListener(queues = "zxc")
public class Custom1 {
@RabbitHandler
public void receive_msg(String msg){
System.out.println("zxc:" + msg);
}
}
2.2、Fanout
- 什么是分裂模式
需要将消息一次发给多个队列时,需要使用这种模式:
- 新建两个队列
- 创建Exchange并绑定相应的Queue
由于我们要传送到不同Queue中,因此要去运送信息的Exchange也不能只是一个了,所以要额外创建Fanout的Exchange,然后将创建出的Exchange去指定好对应的Queue
启动方法写好,因为没有匹配规则,所以RouteKey为null就可以了,只是选好Exchange的名字就行
/**
* 分裂模式
*/
@Test
public void send_msg2(){
rabbitTemplate.convertAndSend("zxczxc", "", "分裂模式测试");
}
编写消费者
@Component
@RabbitListener(queues = "zxc1")
public class Custom2 {
@RabbitHandler
public void receive_msg(String msg){
System.out.println("zxc1:" + msg);
}
}
@Component
@RabbitListener(queues = "zxc2")
public class Custom3 {
@RabbitHandler
public void receive_msg(String msg){
System.out.println("zxc2:" + msg);
}
}
2.3、Topic
简单说一下主题模式的概念,刚才说到了分列模式意思就是没有RouteKey,而主题模式相当于分列模式的加强版有匹配规则的分列算法。
和之前的分列模式是差不多的,只是增加了RoutingKey
编写生产者:
/**
* 主题模式
*/
@Test
public void send_msg3(){
rabbitTemplate.convertAndSend("topic", "love.you", "主题模式测试");
}
消费者:
@Component
@RabbitListener(queues = "zxc")
public class Custom1 {
@RabbitHandler
public void receive_msg(String msg){
System.out.println("zxc:" + msg);
}
}
@Component
@RabbitListener(queues = "zxc1")
public class Custom2 {
@RabbitHandler
public void receive_msg(String msg){
System.out.println("zxc1:" + msg);
}
}
@Component
@RabbitListener(queues = "zxc2")
public class Custom3 {
@RabbitHandler
public void receive_msg(String msg){
System.out.println("zxc2:" + msg);
}
}