持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第5天,点击查看活动详情
啥是RabbitMQ
消息中间件
创始人1983 MIT(麻省)
一个pc发信息到另一个pc,我使用TCP或者http你就必须使用TCP或者http
我使用啥你都用啥,然后这个小伙子想,能不能不这样
集成的多了,一个系统内部实现的通信协议就很多了
减少复杂度
,只用一种协议
就是上图的Bus
就是MQ,集成到一起
各种公司有自己的MQ,这样下来又复杂了
2007RabbitMQ的第一年
Rabbit是兔子,跑的快,繁殖的快
(创始人用的ErLang,天生支持高并发)
使用MQ
- MQ可以把同步变成异步
- 系统解耦合
解耦之后:
- 流量削峰(队列的特性)
就相当于火车站售票员,就算火车站人再多,也是一个窗口一个窗口的(一个个队列)
峰值的访问量平摊到后面的时间
问题:
- MQ必须不能挂,整个系统的可用性降低
- 系统的复杂度增加
安装可以看这个
结果是:
查看用户
rabbitmqctl.bat list_users
可以访问:
工作模型
高可靠
灵活的路由
多客户端(多种语言)
集群与扩展性
高可用队列
权限管理(每种用户有自己的权限)
插件系统
可靠性
与Spring集成
运行MQ的软件我们叫做Broker,这个单词的意思的“中介,代理”
Producer和Consumer要与Broker建立连接TCP长连接,太消耗资源,所以在TCP的长连接里建立了虚连接channel,我们把这个叫做信道,通信完之后释放一个个channel
发送过来的消息存queue中
Exchange是交换机,本质是绑定列表,实现消息灵活分发
默认端口5672
可以在一台服务器上运行多个Broker,但是没有必要
可以在一个个Broker里创建多个VHost
不同用户用不同的Vhost,他们之间是相互隔离的
Exchange路由消息详解
交换机类型
1、Direct Exchange直连路由的交换机
channel.basicPublish(exc_name,"spring",msg)
(exchange的名字,路由键名字,消息)
只有当router_key和binding_key一样的时候,消息才会送到对应的queue中
2、TopicExchange主题类型的交换机
符号*表示一个单词,符号#表示0个或者多个单词
就比如,第一个binding key匹配的路由键是junior或者junior.a.b或者junior.a.b.c.d.e
比如:
channel.basicPublish("myexc","junior.abc.jvm","msg3");
这条消息能发送给哪个队列?
答案是只有第一个队列
3、FanoutExchange风扇交换
没有绑定的
广播类型的交换机
RabbitMQ的基本使用
安装ErLang环境
不演示了
注意版本对应
docker安装教程:gper.club/articles/7e…
流程
- 引入依赖
- 消费者
- 生产者
- 参数详解
实操
- 引入依赖
<dependency>
<groupId>com.rabbitmq</groupId>
<artifactId>amqp-client</artifactId>
<version>5.6.0</version>
</dependency>
- 消费者
谁使用,谁管理,所以在消费者里创建一些
import com.rabbitmq.client.*;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.util.concurrent.TimeoutException;
public class MyConsumer {
private final static String EXCHANGE_NAME = "SIMPLE_EXCHANGE";
private final static String QUEUE_NAME = "SIMPLE_QUEUE";
public static void main(String[] args) throws IOException, TimeoutException {
ConnectionFactory factory = new ConnectionFactory();
// 连接IP
factory.setHost("127.0.0.1");
// 默认监听端口
factory.setHost("5672");
// 虚拟机
factory.setVirtualHost("/");
// 设置访问的用户
factory.setUsername("guest");
factory.setPassword("guest");
// 建立连接
Connection conn = factory.newConnection();
// 创建消息通道
Channel channel = conn.createChannel();
// 声明交换机
// String exchange, String type, boolean durable, boolean autoDelete, Map<String, Object> args
// 交换机名字 种类 是否持久化 是否自动删除 其他参数
channel.exchangeDeclare(EXCHANGE_NAME, "direct", false, false, null);
// 声明队列
// String queue, boolean durable, boolean exclusive, boolean autoDelete, Map<String, Object> args
// 队列名字 是否持久化 是否重复定义 是否自动删除 其他参数
channel.queueDeclare(QUEUE_NAME, false, false, false, null);
System.out.println("Waiting for message....");
// 绑定队列和交换机
channel.queueBind(QUEUE_NAME, EXCHANGE_NAME, "gupao.best");
// 创建消费者
Consumer consumer = new DefaultConsumer(channel){
@Override
public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties basicProperties, byte[] body ) throws UnsupportedEncodingException {
String msg = new String(body, "UTF-8");
System.out.println("Received message:'"+msg+"'");
System.out.println("consumerTag:"+consumerTag);
System.out.println("deliveryTag:"+envelope.getDeliveryTag());
}
};
// 开始获取消息
// String queue, boolean autoAck, Consumer callback
channel.basicConsume(QUEUE_NAME, true, consumer);
}
}
- 生产者
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.ConnectionFactory;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.concurrent.TimeoutException;
public class MyProducer {
private final static String EXCHANGE_NAME = "SIMPLE_EXCHANGE";
public static void main(String[] args) throws IOException, TimeoutException {
ConnectionFactory factory = new ConnectionFactory();
// 连接IP
factory.setHost("127.0.0.1");
// 默认监听端口
factory.setHost("5672");
// 虚拟机
factory.setVirtualHost("/");
// 设置访问的用户
factory.setUsername("guest");
factory.setPassword("guest");
// 建立连接
Connection conn = factory.newConnection();
// 创建消息通道
Channel channel = conn.createChannel();
// 发送消息
String msg = "Hello world, Rabbit MQ!";
// String exchange, String routingKey, BasicProperties props, byte[] body
channel.basicPublish(EXCHANGE_NAME, "gupao.best", null, msg.getBytes());
channel.close();
conn.close();
}
}
\