RabbitMQ 学习资料
一、rabbitmq的离线安装
1.centos6下的安装教程
准备环境:安装包准备好之后通过XFTP传到虚拟机上
1.1下载环境
1)下载Erlang环境(三个rpm包)
esl-erlang_17.3-1centos6_amd64.rpm
esl-erlang-17.3-1.x86_64.rpm
esl-erlang-compat-R14B-1.el6.noarch.rpm
2)下载RabbitMQ离线rpm包(三个rpm包)
rabbitmq-server-3.4.1-1.noarch.rpm
1.2安装环境
1)安装ErLang环境
rpm -ivh esl-erlang_17.3-1~centos~6_amd64.rpm
esl-erlang-compat-R14B-1.el6.noarch.rpm
esl-erlang-17.3-1.x86_64.rpm
2)安装RabbitMQ包
rpm -ivh rabbitmq-server-3.4.1-1.noarch.rpm
1.3修改配置
vim /usr/lib/rabbitmq/lib/rabbitmq-server-3.4.1/ebin/rabbit.app
修改登陆MQ的Loopback_users这个配置,如下图{loopback_user,[guest]}
1.4启动rabbitmq
启动服务:systemctl start rabbitmq-server
查看服务状态,如图:systemctl status rabbitmq-server.service
开机自启: systemctl enable rabbitmq-server
停止服务: systemctl stop rabbitmq-server
启动成功
1.5安装MQ的web管理插件
安装命令:rabbitmq-plugins enable rabbitmq_management
然后查看:rabbitmq-plugins list
有E/e的代表已装的插件
一般情况下还需要手动开放端口15672与5672
firewall-cmd --add-port=5672/tcp --permanent
本地浏览器访问rabbitMQ管理界面:http://localhost:15672
远程访问地址:http://ip:15672 但是远程访问需要配置账户,不能用默认账户guest
tahairui:用户名;123456:密码
1.rabbitmqctl add_user tahairui 123456 //添加用户
2.rabbitmqctl set_permissions -p / tahairui “." ".” “.*” //添加权限
3.rabbitmqctl set_user_tags taharui administrator //修改用户角色
访问如下图:
登陆账号密码 :tahairui 123456 如下图
基本安装完成
二、RabbitMQ入门学习
2.1 为什么要使用RabbitMQ
1)降低耦合度
ex:用户下单后,订单系统需要通知库存系统
**传统做法:**订单系统调用库存系统的接口;
缺点:库存系统无法访问,则订单减库存将失败,从而导致订单失败;订单系统与库存系统吻合
引入消息队列
-
**订单系统:**用户下单后,订单系统完成持久化处理,将消息写入消息队列,返回用户下单成功
-
**库存系统:**订阅下单消息,采用拉/推的方式,获取下单信息,库存根据下单信息,进行库存操作
-
**假如:**在下单时候,库存系统不能正常使用,也不影响正常下单,因为下单后,订单系统写入消息队列就不再关心其他后续操作,实现了订单系统与库存系统的应用解耦。
2)RabbitMQ速度快,微秒级别
流量削峰:也是消息队列应用场景,一般在秒杀或团抢活动中使用广泛;假如MySql每秒预计能抗住2000个请求,而秒杀环节有100万的用户量,高峰期如果每秒有5000个请求,这时Mysql就会瘫痪,而引入MQ,可以将这5000多个请求写入MQ,系统再从MQ中以每秒2000个请求来处理消息。
3)学习成本低
4)支持多种语言
2.2 什么是RabbitMQ
1)RabbitMQ是一个由ErLang语言开发的AMQP(Advanced Message Queue Protocol 高级消息队列协议)的开源实现,AMQP是面向消息、队列、路由(包括点对点和发布/订阅)、可靠性、安全,消息队列是一种应用程序对一种应用程序的通讯方法;不需要专门的连接来链接。消息传递是指程序通过消息发送数据进行通信,而不是彼此直接调用。
2)能够实现异步消息处理
2.3 引入消息队列的优缺点
- **优点:**就是在特殊情况下,解耦、异步、削峰
- 缺点:
- **系统的可用性降低:**系统引入外部的依赖越多,系统越容易挂掉
- **系统的复杂性提高:**引入MQ之后,考虑的问题增多,如何保证消息没用被重复消费?消息不丢失?消息的传递顺序
- **一致性问题:**A系统发送完消息直接返回成功,但是BCD系统若有系统写库失败,则会产生数据不一致问题
2.4 RabbitMQ中的组成部分
- Broker:消息队列和服务进程。此进程包括两个部分:Exchange和Queue
- Exchange:消息队列交换机。按一定的规则将消息路由转发到某个队列
- Queue:消息队列,存储消息的队列
- Producer:消息生产者。生产方客户端将消息同交换路由发送到队列中
- Consumer:消息消费者。消费队列中存储的消息
这些组成部分工作原理图如下:
- 消息生产者连接到RabbitMQ Broker,创建connection,开启channel。
- 生产者声明交换机类型、名称、是否持久化等。
- 生产者发送消息,并指定消息是否持久化等属性和routing key。
- exchange收到消息之后,根据routing key路由到当前交换机绑定的相匹配的队列里面。
- 消费者监听接受到消息之后开始业务处理。
2.5 (Exchange)交换机的四种类型以及用法
-
Direct Exchange(直接交换机)
需要绑定一个队列,要求该消息与一个特殊的路由键完全匹配。简单点就是:一对一的,点对点的发送
-
Fanout Exchange(发布订阅)
一个发送到交换机的消息,都会被转发到与该交换机绑定的所有队列。简单的来说:就是发布订阅
-
Topic Exchange(通配符交换机)
这种交换机是使用通配符去匹配,路由到对应的队列。
通配符有两种:“ * ”、 “ # ”
符号* :a.* 可以匹配到 a.b、a.c ,匹配不到a.b.c,也就是只能匹配到一级
符号# :rabbit.#可以匹配到rabbit.a、 rabbit.b、rabbit.a.c,也就是能匹配到下面的所有子级
-
Hearders Exchange()
它的路由不是用routing key去匹配的,而是由请求头里的键值对进行路由。交换机会根据生产者发送过来的头部信息携带的键值对去匹配队列绑定的键值,路由到对应的队列
有两种模式:全部匹配模式、部分匹配模式
三、springBoot集成RabbitMQ
简单小例子
<!-- rabbitmq 依赖-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-amqp</artifactId>
</dependency>
import org.springframework.amqp.core.Binding;
import org.springframework.amqp.core.BindingBuilder;
import org.springframework.amqp.core.Queue;
import org.springframework.amqp.core.TopicExchange;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class MyConfig {
//1.创建exchange topic
/**
* 1.name: 交换机名称
* 2.durable: 是否持久化
* 3.autoDelete: 是否自动删除,也就是临时队列。当最后一个消费者断开连接后,会自动删除
* @return TopicExchange
*/
@Bean
public TopicExchange getTopicExchange () {
return new TopicExchange("boot-topic-exchange",true,false);
}
//2.创建queue
/**
* 1.name: 队列名称
* 2.durable: 是否持久化
* 3.exclusive: 是否独享,排外的。如果设置为true,定义为排他队列。则只有创建者可以使用此队列。也就是private私有的
* 4.autoDelete: 是否自动删除,也就是临时队列。当最后一个消费者断开连接后,会自动删除
* 5.arguments:
* @return Queue
*/
@Bean
public Queue getQueue () {
return new Queue("topic-queue",true,false,false,null);
}
//3.绑定
@Bean
public Binding getBinding(TopicExchange topicExchange, Queue queue){
return BindingBuilder
//绑定队列
.bind(queue)
//到交换机
.to(topicExchange)
//并设置匹配键
.with("ERROR");
}
}
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.stereotype.Component;
@Component
public class Consumer {
/**
* 消费消息
* topic-queue:队列名称
* @param message:消息对象呢
*/
@RabbitListener(queues = "topic-queue")
public void getMessage (Object message) {
System.out.println("接收到消息"+message);
}
import org.junit.jupiter.api.Test;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.boot.test.context.SpringBootTest;
import javax.annotation.Resource;
@SpringBootTest
class MyrabbitmqApplicationTests {
@Resource
RabbitTemplate rabbitTemplate;
@Test
void contextLoads() throws Exception {
//转化并且发送消息
rabbitTemplate.convertAndSend("boot-topic-exchange","ERROR","error");
}
}
运行contextLoads()方法,控制台打印如下:
接收到消息(Body:'error' MessageProperties [headers={}, contentType=text/plain, contentEncoding=UTF-8, contentLength=0, receivedDeliveryMode=PERSISTENT, priority=0, redelivered=false, receivedExchange=boot-topic-exchange, receivedRoutingKey=ERROR, deliveryTag=1, consumerTag=amq.ctag-pC0fL_aE5HZeYnKNpiwYww, consumerQueue=topic-queue])
并且访问 http://ip:15672/#/queues 如图看到创建了一个队列,并且有一条待消费的消息