RabbitMQ是一个开源的消息代理和队列服务器,用来通过普通协议在完全不同的应用之间共享数据,RabbitMQ是使用Erlang语言来编写的,并且RabbitMQ是基于AMQP协议的。
即时性要求比较高的,往往采用RPC远程调用和HTTP/HTTPS来调用,比如用户下订单后,就要马上响应是否下单成功。那如果即时性要求不高的话,可以采用MQ来解决,比如你下完单后,进入物流环节,物流环节往往要等待很长时间,不可能商品马上就给你送过来,这时下单系统与物流系统之间就可以通过MQ来解耦。当请求过程不要求即时性,那我们就可以整个过程解耦,把整个过程的顺序性存放在MQ中,让整个过程慢慢去处理。
AMQP全称高级消息队列协议(Advanced Message Queuing Protocol)
RabbitMQ是一个开源的消息代理和队列服务器,用来通过普通协议在完全不同的应用之间共享数据,RabbitMQ是使用Erlang语言来编写的,并且RabbitMQ是基于AMQP协议的。
- Server: 又称Broker, 接受客户端的连接,实现AMQP实体服务;
- Connection: 连接,应用程序与Broker的网络连接;
- Channel:网络信道,几乎所有的操作都在Channel中进行,Channel是进行消息读写的通道。客户端可建立多个Channel, 每个Channel代表一个会话务;
- Message:消息,服务器和应用程序之间传送的数据,由Properties和Body组成。Properties可以对消息进行修饰,比如消息的优先级、延迟等高级特性;
Body则就是消息体内容;- Virtual host:虚拟地址,用于进行逻辑隔离,最上层的消息路由。一个Virtual Host里面可以有若干个Exchange和Queue,同一个VirtualHost里面不能有相同名称的Exchange或Queue;
- Exchange: 交换机,接收消息,根据路由键转发消息到绑定的队列; Binding: Exchange和Queue之间的虚拟连接, binding中可以包含routing key;
- Routing key: 一个路由规则,虚拟机可用它来确定如何路由一个特定消息; Queue: 也称Message Queue,消息队列,保存消息并将它们转发给消费者;
Exchange与Queue理论上是多对多关系,在实际开发中建议是一对多关系
一个Consume可以消费多个Queue,在实际开发中建议是一对一消费
RabbitMQ官网地址:http://www.rabbitmq.com
准备3台服务器,192.168.11.71、192.168.11.72、192.168.11.73
①yum下来一些基础的软件包,3台服务器都这么做
yum install build-essential openssl openssl-devel unixODBC unixODBC-devel make gcc gcc-c++ kernel-devel m4 ncurses-devel tk tc xz
②修改/etc/hosts和/etc/hostname文件,并测试能否ping通,3台服务器都这么做
vim /etc/hosts
vim /etc/hostname
③下载RabbitMQ所需软件包
wget www.rabbitmq.com/releases/erlang/erlang-18.3-1.el7.centos.x86_64.rpm
wget http://repo.iotti.biz/CentOS/7/x86_64/socat-1.7.3.2-1.1.el7.lux.x86_64.rpm
wget www.rabbitmq.com/releases/rabbitmq-server/v3.6.5/rabbitmq-server-3.6.5-1.noarch.rpm
④按顺序安装服务命令
rpm -ivh erlang-18.3-1.el7.centos.x86_64.rpm
rpm -ivh socat-1.7.3.2-1.1.el7.x86_64.rpm
rpm -ivh rabbitmq-server-3.6.5-1.noarch.rpm
⑤修改用户登录与连接心跳检测,注意修改
vim /usr/lib/rabbitmq/lib/rabbitmq_server-3.6.5/ebin/rabbit.app
修改点1:loopback_users 中的 <<“guest”>>,只保留guest (用于用户登录)
修改点2:heartbeat 为10(用于心跳连接)
⑥安装管理插件
首先启动服务(后面 | 包含了停止、查看状态以及重启的命令)
/etc/init.d/rabbitmq-server start | stop | status | restart
可查看管理端口有没有启动:
lsof -i:15672 或者 netstat -tnlp | grep 15672
查看服务有没有启动: lsof -i:5672 (5672是Rabbit的默认端口)
rabbitmq-plugins enable rabbitmq_management
⑦浏览器中访问RabbitMQ服务
跟着每一步骤去了解RabbitMQ的管理界面
1.RabbitMQ管理服务登录界面
- connections:无论生产者还是消费者,都需要与 RabbitMQ 建立连接后才可以完成消息的生产和消费,在这里可以查看连接情况
- channels:通道,建立连接后,会形成通道,消息的投递获取依赖的通道
- Exchanges:交换机,用来实现消息的路由
- Queues:队列,就是消息队列,消息存放在队列中,等待消费,消费后会被移除队列
反应连接数、通道数、交换机、队列、消费数总体个数
4.Node节点使用情况
核心配置文件优先读取/etc/rabbitmq/rabbitmq.config,如果没有读取
/usr/lib/rabbitmq/lib/rabbitmq_server-3.6.5/ebin/rabbit.app
6.Ports and contexts 端口情况
7.Import / export definitions 导入导出
用于数据迁移、MQ版本升级
Type:direct:直连 topic:主题 fanout:广播
Durability:durable 持久化(服务重启不会丢失) transient 不持久化
查看新建结果
②exchang要跟queue队列绑定,创建队列
③建立exchang与queue之间的关系
点击exchang-test
- ConnectionFactory:获取连接工厂
- Connection: 一个连接
- Channel:数据通信信道,可发送和接收消息
- Queue: 具体的消息存储队列
- Producer & Consumer:生产和消费者
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0modelVersion>
<groupId>com.bfxygroupId>
<artifactId>rabbitmq-apiartifactId>
<version>0.0.1-SNAPSHOTversion>
<packaging>jarpackaging>
<name>rabbitmq-apiname>
<description>rabbitmq-apidescription>
<parent>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-parentartifactId>
<version>2.1.5.RELEASEversion>
<relativePath/>
parent>
<properties>
<project.build.sourceEncoding>UTF-8project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8project.reporting.outputEncoding>
<java.version>1.8java.version>
properties>
<dependencies>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starterartifactId>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-testartifactId>
<scope>testscope>
dependency>
<dependency>
<groupId>com.rabbitmqgroupId>
<artifactId>amqp-clientartifactId>
<version>3.6.5version>
dependency>
dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-maven-pluginartifactId>
plugin>
<plugin>
<groupId>org.apache.maven.pluginsgroupId>
<artifactId>maven-compiler-pluginartifactId>
<configuration>
<source>1.8source>
<target>1.8target>
configuration>
plugin>
plugins>
build>
project>
public class Sender {
public static void main(String[] args) throws Exception {
// 创建ConnectionFactory
ConnectionFactory connectionFactory = new ConnectionFactory();
connectionFactory.setHost("192.168.11.71");
connectionFactory.setPort(5672);
connectionFactory.setVirtualHost("/");
// 创建Connection
Connection connection = connectionFactory.newConnection();
// 创建Channel
Channel channel = connection.createChannel();
String queueName = "test001";
// 参数: queue名字,是否持久化,独占的queue(仅供此连接),不使用时是否自动删除, 其他参数
channel.queueDeclare(queueName, false, false, false, null);
Map<String, Object> headers = new HashMap<String, Object>();
AMQP.BasicProperties props = new AMQP.BasicProperties.Builder()
.deliveryMode(2)
.contentEncoding("UTF-8")
.headers(headers).build();
for(int i = 0; i < 5;i++) {
String msg = "Hello World RabbitMQ " + i;
// 发布消息,第一个参数:exchange为""会选择默认的exchange
channel.basicPublish("", queueName , props , msg.getBytes());
}
// 关闭资源:略
}
}
public class Receiver {
public static void main(String[] args) throws Exception {
ConnectionFactory connectionFactory = new ConnectionFactory() ;
connectionFactory.setHost("192.168.11.71");
connectionFactory.setPort(5672);
connectionFactory.setVirtualHost("/");
// 服务宕机是否自动切换
connectionFactory.setAutomaticRecoveryEnabled(true);
connectionFactory.setNetworkRecoveryInterval(3000);
Connection connection = connectionFactory.newConnection();
Channel channel = connection.createChannel();
String queueName = "test001";
// durable 是否持久化消息
channel.queueDeclare(queueName, false, false, false, null);
QueueingConsumer consumer = new QueueingConsumer(channel);
// 参数:队列名称、是否自动ACK、Consumer
channel.basicConsume(queueName, true, consumer);
// 循环获取消息
while(true){
// 获取消息,如果没有消息,这一步将会一直阻塞
Delivery delivery = consumer.nextDelivery();
String msg = new String(delivery.getBody());
System.out.println("收到消息:" + msg);
}
}
}
Step1:生产者producer发送消息到broker;
Step2:broker接收消息成功,回应生产者producer;
Step3:消费者consumer监听broker中的消息,光标指向1,并消费;
Step4:消费之后,回应broker处理完成,这时候光标指向2,继续获取消息来消费。自动ACK指自动完成消息处理,也就是自动移动光标,一般在现实开发中都是手动ACK回应的。