RabbitMQ
rabbitmq服务默认端口 5672 web管理页面15672 支持持久化 消息不会丢失
AMQP协议
在tcp/ip、http的基础上产生的一种高级消息队列协议,http的请求头和响应头过于复杂,大部分都是短链接,所以产生一个通道保持一个长连接,提高性能,所以mq产生自己的协议
角色
- none:无法访问web页面
- managment:只能看到自己的相关信息无法看别人的,无法创建修改自己的queue、exchange等
- policymaker:和management一样能看自己的相关信息,还能创建修改自己的queue、exchange等
- monitoring:能看所有人的相关信息
- adminstrator:能看所有人的并且能修改新增删除,就是拥有所有的操作功能
核心概念
- serve:就是我们的rabbitMQ服务器
- connction:连接,tcp/ip 进行网络连接
- channel:连接建立后,创建通道,进行消息的读写
- message:通道中传递的消息
- virtual host:虚拟主机,“/”,“/hello”,类似于mysql中一个个数据库,一个虚拟主机中可以有多个交换机、队列
- exchange:交换机(路由),接收通道传递过来的消息
- bindings:交换机和消息队列之间建立连接,可以保护多个routing key
- routing key:路由规则,可以用它来确定如何路由一个特定消息,主要用于寻找队列
- queue:消息队列,保存消息的载体
消息分发策略的机制
支持发布订阅、轮询分发、公平分发、重发、消息拉取
假如mq中有100条消息,有三个消费者,不同的分发机制有不同分发方式,如下
- 发布订阅:每个消费者都会获取100条消息
- 轮询分发:每个消费者各获取33条,留下一条分给其中一个消费者
- 公平分发:那个消费者消费的快那个就多发一些,能者多劳,必须要手动的应答
- 重发:假如一条消息被某个消费者消费后,并没有给mq回复确认消费信息,那么该消息不会删除并向另两个的其中一个发送消息
- 消息拉取:rpc的形式,被动拉取的一种机制,基本不会用
6种工作模式 对路由的设定
- simple简单队列模式 默认队列 拥有一个默认交换机
生产者
package com.lly.mq.first;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.ConnectionFactory;
import java.io.IOException;
import java.util.concurrent.TimeoutException;
public class Customer {
public static void main(String[] args) throws IOException, TimeoutException {
ConnectionFactory connectionFactory = new ConnectionFactory();
connectionFactory.setHost("127.0.0.1");
connectionFactory.setPort(5672);
connectionFactory.setUsername("guest");
connectionFactory.setPassword("guest");
connectionFactory.setVirtualHost("/");
Connection connection = connectionFactory.newConnection("生产者");
//创建队列
Channel channel = connection.createChannel();
//声明队列 五个参数分别为 1.队列名称 2.是否持久化(false:非持久化) 3.排他性 4.队列是否自动删除(消息被消费完时) 5.携带附属参数
channel.queueDeclare("hello",false,false,false,null);
//发送消息 四个参数 1.交换机名称(没有指定,使用默认的) 2.队列名称
channel.basicPublish("","hello",null,"Hello RabbitMQ!".getBytes());
System.out.println("消息发送成功!");
channel.close();
connection.close();
}
}
消费者
package com.lly.mq.first;
import com.rabbitmq.client.*;
import java.io.IOException;
import java.util.concurrent.TimeoutException;
public class Producter {
public static void main(String[] args) throws IOException, TimeoutException {
ConnectionFactory connectionFactory = new ConnectionFactory();
connectionFactory.setHost("127.0.0.1");
connectionFactory.setPort(5672);
connectionFactory.setUsername("guest");
connectionFactory.setPassword("guest");
connectionFactory.setVirtualHost("/");
Connection connection = connectionFactory.newConnection("消费者");
//创建队列
Channel channel = connection.createChannel();
channel.queueDeclare("hello",false,false,false,null);
channel.basicConsume("hello", true, new DeliverCallback() {
@Override
public void handle(String s, Delivery delivery) throws IOException {
System.out.println("接收到消息是:" + new String(delivery.getBody(), "UTF-8"));
}
}, new CancelCallback() {
@Override
public void handle(String s) throws IOException {
System.out.println("接收到消息失败" );
}
});
System.in.read();
channel.close();
connection.close();
}
}
- work工作队列模式 拥有一个默认交换机
- fanout发布订阅模式
将多个队列和交换机绑定,当交换机接收到一条消息后,会分别分发到多个已绑定的队列中,每个队列都接受到这条消息。比如注册时,需要发短信、发邮件、添加数据库,可以使用这个这种模式进行一个异步的操作
例:如下是对fanout的模拟
1.创建消息队列fanout1、fanout2,各自有一条数据
2.创建一个fanout路由,名称fanout-exchange,并分别为两个队列绑定,注意并没有绑定routing key。
3.发送一个内容为message的消息,可见fanout1、fanout2数据由1变为2了
- Direct路由模式
将多个队列和交换机绑定,并将绑定设置一个routing key,当交换机接收到一条向指定routing key消息后,拥有相关绑定routing key的队列将收到一条消息,是一种精准的匹配,具体示例参考topics主题模式配图,Direct模式下routing key不带由#和*
- topics主题模式
topics和Direct基本相同,topics是一种模糊匹配 例:如下是对topic的模拟
1.首先创建4个队列 queue1 queue2 queue3 queue4,如下图:
2.创建一个topic路由,名称topic-exchange,并分别为四个队列绑定routing key,#和*表示模糊匹配,#表示0个或多个,*表示有且只有一个
3.当向routing key为xxx.com.xxx发送消息时,只有queue1收到了消息,可见queue1消息由2变为了3
4.当向routing key为com.user.xxx发送消息时 ,queue1和queue4会收到消息,queue1消息由3变为4,queue4消息由0变为1
5.当向routing key为xxx.course.xxx.xxx发送消息时,可见提示没有相对应的路由,queue2消息还是为1不变
总结:simple、work模式可以理解为就是fanout模式,simple和work是使用默认的路由,而fanout需要我们自己创建。而direct和topics也很相似,direct是一种对routing key的精准匹配,而topics是一种模糊匹配。