目录
1.概述
RabbitMQ是一个开源的AMQP
实现,服务端用Erlang
语言编写,支持多种客户端
。用于在分布式
系统中存储转发消息,在易用性、扩展性、高可用性等方面表现不俗。
2.RabbitMQ端口
RabbitMQ会绑定一些端口,安装完后,需要将这些端口添加至防火墙(或者关闭防火墙)。
-
4369
是Erlang端口、节点名称映射程序,用来跟踪节点名称监听地址,在集群中起到一个类似DNS的作用。 -
5672,5671
AMQP 0-9-1和1.0客户端端口,没有使用SSL和使用SSL的端口。 -
25672
用于RabbitMQ节点间和CLI工具通信,配合4369使用。 -
15672
HTTP_API端口,管理员用户才能访问,用于管理RabbitMQ,需要启用management插件。 -
61613,61614
当STOMP插件启用的时候打开,作为STOMP客户端端口(根据是否使用TLS选择)。 -
1883.8883
当MQTT插件启用的时候打开,作为MQTT客户端端口(根据是否使用TLS选择)。 -
15674
基于WebSocket的STOMP客户端端口(当插件Web STOMP启用的时候打开) -
15675
基于WebSocket的MQTT客户端端口(当插件Web MQTT启用的时候打开)
3.RabbitMQ角色
用户角色分类
none management policymaker monitoring administrator
none
不能访问 management plugin
management
用户可以通过AMQP做的任何事外加:
- 列出自己可以通过AMQP登入的virtual hosts
- 查看自己的virtual hosts中的queues,exchanges和bindings
- 查看和关闭自己的channels和connections
- 查看有关自己的virtual hosts的“全局”的统计信息,包含其他用户在这些virtual host中的活动。
policymaker
查看、创建和删除自己的virtual hosts所属的policies和parameters
monitoring
management可以做的任何事外加:
- 列出所有virtual host,包括它们不能登录的virtual hosts
- 查看其他用户的connections和channels
- 查看节点级别的数据如clustering和memory使用清空
- 查看真正的关于所有virtual hosts的全局的统计信息
administrator
policymarker和monitoring可以做的任何事外加:
- 创建和删除
- 查看、创建、删除users
- 查看、创建和删除permissions
- 关闭其他用户的connections
4.安装和运行
(1)安装依赖环境
复制下载地址后,使用wget命令下载
wget -P /home/download https://github.com/rabbitmq/erlang-rpm/releases/download/v21.2.3/erlang-21.2.3-1.el7.centos.x86_64.rpm
如果找不到wegt命令,输入下面命令进行下载
-bash: wget: command not found
[root@localhost ~]# yum -y install wget
安装 Erlang
sudo rpm -Uvh /home/download/erlang-21.2.3-1.el7.centos.x86_64.rpm
安装 socat
sudo yum install -y socat
(2)安装RabbitMQ
在官方下载页面找到CentOS7版本的下载链接,下载rpm安装包
wget -P /home/download https://github.com/rabbitmq/rabbitmq-server/releases/download/v3.7.9/rabbitmq-server-3.7.9-1.el7.noarch.rpm
安装RabbitMQ
sudo rpm -Uvh /home/download/rabbitmq-server-3.7.9-1.el7.noarch.rpm
(3)启动和关闭
•启动服务
sudo systemctl start rabbitmq-server
•查看状态
sudo systemctl status rabbitmq-server
•停止服务
sudo systemctl stop rabbitmq-server
•设置开机启动
sudo systemctl enable rabbitmq-server
(4)开启Web管理插件
开启插件
rabbitmq-plugins enable rabbitmq_management
RabbitMQ中有一个默认的用户"guest",但是这个用户默认只能通过本机访问,要让其他机器可以访问,需要创建一个新用户,为其分配权限。
添加admin用户
rabbitmqctl add_user admin admin
为用户分配操作权限
rabbitmqctl set_user_tags admin administrator
为用户分配资源权限
rabbitmqctl set_permissions -p / admin ".*" ".*" ".*"
- 浏览器输入IP地址:端口号,即可看到管理控制台登录页面
输入刚才设置的账号密码都是:admin,进入管理控制台页面
(5)防火墙添加端口
RabbitMQ 服务启动后,还不能进行外部通信,需要将端口添加都防火墙
添加端口
sudo firewall-cmd --zone=public --add-port=4369/tcp --permanent
sudo firewall-cmd --zone=public --add-port=5672/tcp --permanent
sudo firewall-cmd --zone=public --add-port=25672/tcp --permanent
sudo firewall-cmd --zone=public --add-port=15672/tcp --permanent
重启防火墙
sudo firewall-cmd --reload
5.使用
(1)Java中使用RabbitMQ
MAVNE依赖
<dependency>
<groupId>com.rabbitmq</groupId>
<artifactId>amqp-client</artifactId>
<version>5.5.1</version>
</dependency>
(2)Spring中使用RabbitMQ
MAVNE依赖
<dependency>
<groupId>org.springframework.amqp</groupId>
<artifactId>spring-amqp</artifactId>
<version>2.1.2.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.amqp</groupId>
<artifactId>spring-rabbit</artifactId>
<version>2.1.2.RELEASE</version>
</dependency>
【代码测试】
生产者代码:
/**
* 简单队列生产者
* 使用RabbitMQ的默认交换器发送消息
*/
public class Producer {
public static void main(String[] args) {
// 1、创建连接工厂
ConnectionFactory factory = new ConnectionFactory();
// 2、设置连接属性
factory.setHost("192.168.11.132");
factory.setPort(5672);
factory.setUsername("admin");
factory.setPassword("admin");
Connection connection = null;
Channel channel = null;
try {
// 3、从连接工厂获取连接
connection = factory.newConnection("生产者");
// 4、从链接中创建通道
channel = connection.createChannel();
/**
* 5、声明(创建)队列
* 如果队列不存在,才会创建
* RabbitMQ 不允许声明两个队列名相同,属性不同的队列,否则会报错
*
* queueDeclare参数说明:
* @param queue 队列名称
* @param durable 队列是否持久化
* @param exclusive 是否排他,即是否为私有的,如果为true,会对当前队列加锁,其它通道不能访问,并且在连接关闭时会自动删除,不受持久化和自动删除的属性控制
* @param autoDelete 是否自动删除,当最后一个消费者断开连接之后是否自动删除
* @param arguments 队列参数,设置队列的有效期、消息最大长度、队列中所有消息的生命周期等等
*/
channel.queueDeclare("queue1", false, false, false, null);
// 消息内容
String message = "Hello World!";
// 6、发送消息
channel.basicPublish("", "queue1", null, message.getBytes());
System.out.println("消息已发送!");
} catch (IOException e) {
e.printStackTrace();
} catch (TimeoutException e) {
e.printStackTrace();
} finally {
// 7、关闭通道
if (channel != null && channel.isOpen()) {
try {
channel.close();
} catch (IOException e) {
e.printStackTrace();
} catch (TimeoutException e) {
e.printStackTrace();
}
}
// 8、关闭连接
if (connection != null && connection.isOpen()) {
try {
connection.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
消费者代码
/**
* 简单队列消费者
*/
public class Consumer {
public static void main(String[] args) {
// 1、创建连接工厂
ConnectionFactory factory = new ConnectionFactory();
// 2、设置连接属性
factory.setHost("192.168.11.132");
factory.setUsername("admin");
factory.setPassword("admin");
Connection connection = null;
Channel channel = null;
try {
// 3、从连接工厂获取连接
connection = factory.newConnection("消费者");
// 4、从链接中创建通道
channel = connection.createChannel();
/**
* 5、声明(创建)队列
* 如果队列不存在,才会创建
* RabbitMQ 不允许声明两个队列名相同,属性不同的队列,否则会报错
*
* queueDeclare参数说明:
* @param queue 队列名称
* @param durable 队列是否持久化
* @param exclusive 是否排他,即是否为私有的,如果为true,会对当前队列加锁,其它通道不能访问,
* 并且在连接关闭时会自动删除,不受持久化和自动删除的属性控制。
* 一般在队列和交换器绑定时使用
* @param autoDelete 是否自动删除,当最后一个消费者断开连接之后是否自动删除
* @param arguments 队列参数,设置队列的有效期、消息最大长度、队列中所有消息的生命周期等等
*/
channel.queueDeclare("queue1", false, false, false, null);
// 6、定义收到消息后的回调
DeliverCallback callback = new DeliverCallback() {
public void handle(String consumerTag, Delivery message) throws IOException {
System.out.println("收到消息:" + new String(message.getBody(), "UTF-8"));
}
};
// 7、监听队列
channel.basicConsume("queue1", true, callback, new CancelCallback() {
public void handle(String consumerTag) throws IOException {
}
});
System.out.println("开始接收消息");
System.in.read();
} catch (IOException e) {
e.printStackTrace();
} catch (TimeoutException e) {
e.printStackTrace();
} finally {
// 8、关闭通道
if (channel != null && channel.isOpen()) {
try {
channel.close();
} catch (IOException e) {
e.printStackTrace();
} catch (TimeoutException e) {
e.printStackTrace();
}
}
// 9、关闭连接
if (connection != null && connection.isOpen()) {
try {
connection.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
分别运行生产者、消费者代码
查看,管理控制台输出结果:
管理控制台,查看消息的变化:
【AMQP协议】
AMQP(Advanced Message Queuing Protocol)是高级消息队列协议,是应用层协议的一个开放标准,为面向消息的中间件设计。
特性
事务支持、持久化支持,出生在金融行业,在可靠性消息处理上具备天然的优势。
AMQP生产者流转过程
AMQP消费者流转过程
6.RabbitMQ核心概念
RabbitMQ模型架构
(1)Producer
Producer:生产者,就是投递消息的一方。生产者创建消息,然后发布到RabbtiMQ中。
消息一般可以包含两个部分:消息体和附加信息。
- 消息体
在实际应用中,消息体一般是一个带有业务逻辑结构的数据,比如一个JSON字符串。当然可以进一步对这个消息体
进行序列化操作。
- 附加信息
用来表述这条消息,比如目标交换器的名称、路由键和一些自定义属性等等。
(2)Virtual Host
Virtual Host:虚拟主机,表示一批交换器、消息队列和相关对象。
虚拟主机是共享相同的身份认证和加密环境的独立服务器域、
每个vhost本质上就是一个mini版的RabbitMQ服务器,拥有自己的队列、交换器、绑定和权限机制。
vhost是AMQP概念的基础,必须在连接时指定, RabbitMQ默认的是/。
(3)Channel
Channel:频道或者信道,是简历在Connection连接之上的一种轻量级的连接。
大部分的操作都是在Channel这个接口中完成的,包括定义队列的声明queueDeclare、交换机的声明
exchangeDeclare、队列的绑定queueBind、发布消息basicPublish、消费消息basicConsume等。
如果把Connection比作一条光纤电缆的话,那么Channel信道就比作成光纤电缆中的其中一束光纤。
一个Connection上可以创建任意数量的Channel。
(4)RoutingKey
RoutingKey:路由键。生产者将消息发给交换器的时候,一般会指定一个RoutingKey,用来指定这个消息的路由规则。
RoutingKey需要与交换器类型和绑定键(BindingKey)联合使用
在交换器类型和绑定键(BindingKey)固定的情况下,生产者可以在发送消息给交换器时,通过指定RoutingKey
来决定消息流程哪里。
(5)Exchange
Exchange:交换器,生产者将消息发送到Exchange(交换器,通常也可以用大写的“X”来表示),由交换器将消息发路由到一个或者多个队列中。如果路由不到,或返回给生产者,或直接丢弃。
(6)Queue
Queue:队列,是RabbitMQ的内部对象,用于存储消息。
(7)Binding
Binding:绑定,RabbitMQ中通过绑定交换器与队列关联起来,在绑定的时候一般会指定一个绑定键(BindingKey),这样RabbitMQ就知道如何正确地将消息路由到队列了。
【Exchange类型】
RabbitMQ常用的交换器类型有fanout、 direct 、topic、 headers这四种。
fanout:扇形交换机。
它会把所有发送到该交换器的消息路由到所有与该交换器绑定的队列中。
direct:直连交换机
它会把消息路由到那些BindKey和RoutingKey完全匹配的队列中。
topic:主题交换机
与direct类似,但它可以通过通配符进行模糊匹配。(*:一个单词、#后面的一串多个单词)
headers:头部交换机
不依赖于路由键的匹配规则来路由消息,而是根据发送消息内容中的headers属性进行匹配。
headers类型的交换器性能很差,而且也不实用。
(8)Consumer
Consumer:消费者,就是接受消息的一方。消费者连接到RabbitMQ服务器,并订阅到队列上。
当消费者消费一条消息时,只是消费消息的消息体(payload)。在消息路由的过程中,消息的标签会丢弃,
存入到队列中的消息只有消息体,消费者也只会消费到消息体,也就不知道消息的生产者是谁,当然消费者也不需要知道。
【运转流程】
生产者发送消息的过程:
- 生产者连接到RabbitMQ Broker,建立一个连接(Connection),开启一个信道(Channel)
- 生产者声明一个交换器,并设置相关属性,比如交换机类型、是否持久化等。
- 生产者声明一个队列并设置相关属性,比如是否排他、是否持久化、是否自动删除等。
- 生产者通过路由键将交换器和队列绑定起来。
- 生产者发送消息至RabbitMQ Broker,其中包含路由键、交换器等信息。
- 相应的交换器根据收到的路由键查找相匹配的队列。
消费者接收消息的过程:
-
生产者连接到RabbitMQ Broker,建立一个连接(Connection),开启一个信道(Channel)
-
消费者向RabbitMQ Broker请求消费相应队列中的消息,可能会设置相应的回调函数,以及做一些准备工作。
-
等待RabbitMQ Broker回应并投递相应队列中的消息,消费者接收消息
-
消费者确认(ack)接受到的消息
-
RabbitMQ从队列中删除相应已经被确认的消息
-
关闭信道、关闭连接