RabbitMQ是一个在AMQP( 一个提供统一消息服务的应用层标准高级消息队列协议)基础上完成的,可复用的企业消息系统。他遵循Mozilla Public License开源协议。
保证可靠性
:使用一些机制来保证可靠性,如持久化、传输确认、发布确认灵活的路由功能高可用性
:RabbitMQ集群中的某个节点出现问题时队列任然可用提供良好的管理界面
yum remove erlang*
# yum -y install make gcc gcc-c++
yum -y install make gcc gcc-c++ kernel-devel m4 ncurses-devel openssl-devel unixODBC unixODBC-devel httpd python-simplejson
# 下载erlang
wget http://www.erlang.org/download/otp_src_20.1.tar.gz
# 下载rabbitMQ
wget https://github.com/rabbitmq/rabbitmq-server/releases/download/v3.7.0/rabbitmq-server-generic-unix-3.7.0.tar.xz
mkdir erlang
解压erlang安装包
tar -xvf otp_src_20.1.tar.gz
进入解压文件夹
cd otp_src_20.1
指定安装目录及安装配置(需要先安装并配置JDK)
# erlang指定安装在/usr/local/erlang目录
./configure --prefix=/usr/local/erlang --enable-smp-support --enable-threads --enable-sctp --enable-kernel-poll --enable-hipe --with-ssl --without-javac
编译与安装
make && make install
配置erlang环境变量
vim /etc/profile
重新加载profile文件
source /etc/profile
xz -d rabbitmq-server-generic-unix-3.7.0.tar.xz
tar -xvf rabbitmq-server-generic-unix-3.7.0.tar
cd rabbitmq_server-3.7.0/sbin
./rabbitmq-server
lsof -i:5672
./rabbitmq-plugins enable rabbitmq_management
#关闭防火墙
systemctl stop firewalld
#开机禁用
systemctl disable firewalld
#查看状态
systemctl status firewalld
RabbitMQ默认提供了⼀个guests账号,但是此账号不能⽤作远程登录,也就是不能在管理系统的登录;我们可以创建⼀个新的账号并授予响应的管理权限来实现远程登录
## 进⼊到rabbit_mq的sbin⽬录
cd /usr/local/rabbitmq_server-3.7.0/sbin
## 新增⽤户
./rabbitmqctl add_user ytao admin123
## ⽤户级别:
## 1.administrator 可以登录控制台、查看所有信息、可以对RabbitMQ进⾏管理
## 2.monitoring 监控者 登录控制台、查看所有信息
## 3.policymaker 策略制定者 登录控制台、指定策略
## 4.managment 普通管理员 登录控制台
./rabbitmqctl set_user_tags ytao administrator
消息通信是由两个角色完成:消息生产者(producer)和 消息消费者(Consumer)
队列中的消息只能被消费一次
⼀个队列只有⼀个消费者
⽣产者将消息发送到队列,消费者从队列取出数据
多个消费者监听同⼀个队列,但多个消费者中只有⼀个消费者会成功的消费消息
⼀个交换机绑定多个消息队列,每个消息队列有⼀个消费者监听,消息⽣产者发送的消息可以被每⼀个消费者接收
⼀个交换机绑定多个消息队列,每个消息队列都有自己唯⼀的key,每个消息队列有⼀个消费者监听,消息生成者可以通过key指定将某消息发送到某队列
@Configuration
public class RabbitMQConfiguration {
//声明队列
@Bean
public Queue queue9(){
Queue queue9 = new Queue("queue9");
//设置队列属性
return queue9;
}
@Bean
public Queue queue10(){
Queue queue10 = new Queue("queue10");
//设置队列属性
return queue10;
}
//声明订阅模式交换机
@Bean
public FanoutExchange ex5(){
return new FanoutExchange("ex5");
}
//声明路由模式交换机
@Bean
public DirectExchange ex6(){
return new DirectExchange("ex6");
}
//绑定队列
@Bean
public Binding bindingQueue9(Queue queue9, DirectExchange ex6){
return BindingBuilder.bind(queue9).to(ex6).with("k1");
}
@Bean
public Binding bindingQueue10(Queue queue10, DirectExchange ex6){
return BindingBuilder.bind(queue10).to(ex6).with("k2");
}
}
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-amqpartifactId>
dependency>
<dependency>
<groupId>org.springframework.amqpgroupId>
<artifactId>spring-rabbit-testartifactId>
<scope>testscope>
dependency>
server:
port: 9001
spring:
application:
name: producer
rabbitmq:
host: 47.96.11.185
port: 5672
virtual-host: host1
username: ytao
password: admin123
@Service
public class TestService {
@Resource
private AmqpTemplate amqpTemplate;
public void sendMsg(String msg){
//1. 发送消息到队列
amqpTemplate.convertAndSend("queue1",msg);
//2. 发送消息到交换机(订阅交换机)
amqpTemplate.convertAndSend("ex1","",msg);
//3. 发送消息到交换机(路由交换机)
amqpTemplate.convertAndSend("ex2","a",msg);
}
}
@Service
//@RabbitListener(queues = {"queue1","queue2"})
@RabbitListener(queues = "queue1")
public class ReceiveMsgService {
@RabbitHandler
public void receiveMsg(String msg){
System.out.println("接收MSG:"+msg);
}
}
RabbitMQ是消息队列,发送和接收的都是字符串/字节数组类型的消息
要求:
传递的对象实现序列化接口
对应bean类implements Serializable 添加private static final long serialVersionUID = 1L;
传递的对象的包名、类名、属性名必须⼀致
@Service
public class MQService {
@Resource
private AmqpTemplate amqpTemplate;
public void sendGoodsToMq(Goods goods){
//消息队列可以发送 字符串、字节数组、序列化对象
amqpTemplate.convertAndSend("","queue1",goods);
}
}
@Service
@RabbitListener(queues = "queue1")
public class ReceiveService {
@RabbitHandler
public void receiveMsg(Goods goods){
System.out.println("Goods---"+goods);
}
}
要求:对象的属性名一致
@Service
public class MQService {
@Resource
private AmqpTemplate amqpTemplate;
public void sendGoodsToMq(Goods goods){
//消息队列可以发送 字符串、字节数组、序列化对象
ObjectMapper objectMapper = new ObjectMapper();
String msg = objectMapper.writeValueAsString(goods);
amqpTemplate.convertAndSend("","queue1",msg);
}
}
@Service
@RabbitListener(queues = "queue1")
public class ReceiveService {
@RabbitHandler
public void receiveMsg(Goods goods){
ObjectMapper objectMapper = new ObjectMapper();
Goods goods = objectMapper.readValue(msg,Goods.class);
System.out.println("String---"+msg);
}
}
spring:
rabbitmq:
publisher-confirm-type: simple ## 开启消息确认模式
publisher-returns: true ##使⽤return监听机制
@Component
public class MyConfirmListener implements RabbitTemplate.ConfirmCallback {
@Autowired
private AmqpTemplate amqpTemplate;
@Autowired
private RabbitTemplate rabbitTemplate;
@PostConstruct
public void init(){
rabbitTemplate.setConfirmCallback(this);
}
@Override
public void confirm(CorrelationData correlationData, boolean b, String s) {
//参数b 表示消息确认结果
//参数s 表示发送的消息
if(b){
System.out.println("消息发送到交换机成功!");
}else{
System.out.println("消息发送到交换机失败!");
//如果失败再次发送消息
amqpTemplate.convertAndSend("ex4","",s);
}
}
}
@Component
public class MyReturnListener implements RabbitTemplate.ReturnsCallback {
@Autowired
private AmqpTemplate amqpTemplate;
@Autowired
private RabbitTemplate rabbitTemplate;
@PostConstruct
public void init(){
rabbitTemplate.setReturnsCallback(this);
}
@Override
public void returnedMessage(ReturnedMessage returnedMessage) {
System.out.println("消息从交换机分发到队列失败");
//如果失败再次发送消息
String exchange = returnedMessage.getExchange();
String routingKey = returnedMessage.getRoutingKey();
String msg = returnedMessage.getMessage().toString();
amqpTemplate.convertAndSend(exchange,routingKey,msg);
}
}
@Service
@RabbitListener(queues="queue01")
public class Consumer1 {
@RabbitHandler
public void process(String msg,Channel channel, Message message) throws IOException {
try {
System.out.println("get msg1 success msg = "+msg);
//参数(该条消息的索引,是否批量)
channel.basicAck(message.getMessageProperties().getDeliveryTag(), false);
} catch (Exception e) {
//参数(该条消息的索引,是否批量,是否将该消息还原到队列)
channel.basicNack(message.getMessageProperties().getDeliveryTag(),false, true);
System.err.println("get msg1 failed msg = "+msg);
}
}
}
延迟队列——消息进入到队列之后,延迟指定的时间才能被消费者消费
指定将当前队列的消息在一定时间死亡后转存到其他指定的队列来实现消息的延迟消费
场景说明:用户下单之后,订单系统要通知库存系统
场景说明:用户注册成功之后,需要发送注册邮件及注册短信提醒
场景说明:应用系统之间的通信,例如聊天室
场景说明:秒杀业务,避免高并发导致服务崩溃
场景说明:系统中⼤量的⽇志处理