RabbitMQ快速入门
简介
-
MQ全称是Message Queue,可以理解为消息队列的意思,先搞清楚几个概念
-
在了解消息通讯之前首先要了解3个概念:生产者、消费者和代理。
生产者:消息的创建者,负责创建和推送数据到消息服务器;
消费者:消息的接收方,用于处理数据和确认消息;
代理:就是RabbitMQ本身,用于扮演“快递”的角色,本身不生产消息,只是扮演“快递”的角色。
- 总结:消费者生产消息,发送到代理,消费者从代理获取消息
RabbitMQ重要关键词解释:
- ConnectionFactory(连接管理器):应用程序与Rabbit之间建立连接的管理器,程序代码中使用;
- Channel(信道):消息推送使用的通道;
- Exchange(交换器):用于接受、分配消息;
- Queue(队列):用于存储生产者的消息;
- RoutingKey(路由键):用于把生成者的数据分配到交换器上;
- BindingKey(绑定键):用于把交换器的消息绑定到队列上;
RabbitMQ角色之间如何运作
-
消费者获取和rabbitmq的连接,然后通过信道传输消息,消息传输时我们绑定一个key在信道上,也就是路由键,这时交换机登场将消息按照路由键分类,发往和路由键匹配的队列中完成发送。
-
这里值得注意得是
channel只是用来与队列交互的一个东西,不能直接操作队列
接受消息是通过channel订阅指定路由键的队列的消息
发送一般是通过channel带上routingKey发送到指定的exchange,exchange上根据routingKey绑定queue来决定发送到什么队列
不显式声明交换机时并且发送消息不指定交换机,则默认使用Direct交换机,并且声明队列时,不显式绑定队列与交换机,则队列以队列名为routing-key绑定到默认的direct交换机,发送消息不指定交换机时,则将消息发到默认的direct交换机
交换器分类
direct(默认)=》如果路由键匹配的话,消息就投递到相应的队列
headers
fanout=》发布/订阅模式,,当你发送一条消息的时候,交换器会把消息广播到所有附加到这个交换器的队列上,对于fanout交换器来说routingKey(路由键)是无效的,这个参数是被忽略的。
topic=》topic交换器运行和fanout类似,但是可以更灵活的匹配自己想要订阅的信息,这个时候routingKey路由键就排上用场了,使用路由键进行消息(规则)匹配。可以进行模糊匹配,这样可以更灵活的接受消息
##如何保证消息送到
- 通过AMQP提供的事务机制实现;(事物性能差,这里不做解释)
- 使用发送者确认模式实现;
Confirm的三种实现方式:(推荐异步确认方式)
方式一:channel.waitForConfirms()普通发送方确认模式;
// 开启发送方确认模式
channel.confirmSelect();
String message = String.format("时间 => %s", new Date().getTime());
channel.basicPublish("", config.QueueName, null, message.getBytes("UTF-8"));
if (channel.waitForConfirms()) {
System.out.println("消息发送成功" );
}
方式二:channel.waitForConfirmsOrDie()批量确认模式;
channel.confirmSelect();
for (int i = 0; i < 10; i++) {
String message = String.format("时间 => %s", new Date().getTime());
channel.basicPublish("", config.QueueName, null, message.getBytes("UTF-8"));
}
channel.waitForConfirmsOrDie(); //直到所有信息都发布,只要有一个未确认就会IOException
System.out.println("全部执行完成");
方式三:channel.addConfirmListener()异步监听发送方确认模式;
//异步监听确认和未确认的消息
channel.addConfirmListener(new ConfirmListener() {
@Override
public void handleNack(long deliveryTag, boolean multiple) throws IOException {
System.out.println("未确认消息,标识:" + deliveryTag);
}
@Override
public void handleAck(long deliveryTag, boolean multiple) throws IOException {
System.out.println(String.format("已确认消息,标识:%d,多个消息:%b", deliveryTag, multiple));
}
});
数据持久化
Rabbit队列和交换器有一个不可告人的秘密,就是默认情况下重启服务器会导致消息丢失,那么怎么保证Rabbit在重启的时候不丢失呢?
答案就是消息持久化。
当你把消息发送到Rabbit服务器的时候,你需要选择你是否要进行持久化,但这并不能保证Rabbit能从崩溃中恢复,想要Rabbit消息能恢复必须满足3个条件:
- 投递消息的时候durable设置为true,消息持久化,代码:channel.queueDeclare(x, true, false, false, null)
- 设置投递模式deliveryMode设置(持久),代码:
channel.basicPublish(x, x, MessageProperties.PERSISTENT_TEXT_PLAIN,x)
MessageProperties.PERSISTENT_TEXT_PLAIN设置为存储纯文本到磁盘 - 消息已经到达持久化交换器上
- 消息已经到达持久化的队列