概述
RabbitMQ是一个由Erlang语言开发的基于AMPQ标准的开源实现。
具有以下特点:
1.可靠性:可以通过消息确认,消息持久化来保证可靠性
2.具有灵活的路由:消息在进入队列之前是通过Exchange来路由消息的。
3.支持消息集群
4.支持多语言客户端
5.支持跟踪机制
基本概念
如上图所示,Rabbit的关键元素
关键需要理解的有两点
1.路由机制
消息到达Broker后会先经过Exchange,这过程还隐藏着一个元素,那就是route key,一般发消息会指定一个route key,Exchange通过检查这个route key与Bindingz中的binding key来决定投到哪一个Queue。
2.信道
我们知道连接是一种很昂贵的资源,RabbitMQ为了尽量的减少Connection的开销,采用信道也就是Channel来多路复用,即在一个连接中可以存在多个Channel,Channel是建立在真实的TCP连接中的虚拟连接。
note
上图还是有一定的误导性
那个connection 和 Channel 并不是只有消费者和broker进行通讯时才用到,生产者和broker进行通信的时候是要建立连接和信道的,信道相当于一个操作broker的客户端,我们可以通过它声明队列 交换器 以及交换器与队列的绑定关系
我们可以把交换器比作邮局 队列相当于住户 邮局与住户的关系是多对多的 我们可以通过信道 让住户把自己注册到邮局,告诉他什么样的信件发给我。当然邮局也有不同的类型。就是如下的概念
交换器类型
不同的交换器发生消息的策略也不同,目前交换器有四种,Direct, Fannot, Topic, Headers,其中Headers由于和Direct交换机差不多,所以基本不用,不作解释。
Direct
这种方式强调的是单播,完全匹配。即消息中的路由键要和Binding中的绑定建完全一致,交换器就会把消息发送到对应的队列中去。
Fanout
Fanout强调广播,Fanout不处理路由键,只是简单的将队列绑定到交换器上。通过Fanout是最快的。
Topic
Topic 交换器是通过模式匹配分配消息的路由键属性,将录用后键和某种模式进行匹配。
关键点,路由键通过点分割,绑定建通过#来表示0或多个,*表示一个
java访问实例
public class Consumer {
public static void main(String[] args) throws IOException, TimeoutException {
ConnectionFactory connectionFactory = new ConnectionFactory();
connectionFactory.setUsername("guest");
connectionFactory.setPassword("guest");
connectionFactory.setHost("129.204.174.193");
connectionFactory.setVirtualHost("/");
Connection connection = connectionFactory.newConnection();
Channel channel = connection.createChannel();
String exchangeName = "hello-exchange";
channel.exchangeDeclare(exchangeName, "direct", true);
String queueName = channel.queueDeclare().getQueue();
String routingKey = "testRoutingKey";
channel.queueBind(queueName, exchangeName, routingKey);
while (true) {
boolean autoAck = false;
String consumerTag = "";
channel.basicConsume(queueName, autoAck, consumerTag, new DefaultConsumer(channel) {
@Override
public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties,
byte[] body) throws IOException {
String routingKey = envelope.getRoutingKey();
String contentType = properties.getContentType();
System.out.println("消费的路由键:" + routingKey);
System.out.println("消费的内容类型:" + contentType);
long delivryTag = envelope.getDeliveryTag();
channel.basicAck(delivryTag, false);
System.out.println("消费的信息体内容:");
String bodyStr = new String(body, "UTF-8");
System.out.println(bodyStr);
}
});
}
}
}
public class Producer {
public static void main(String[] args) throws IOException, TimeoutException {
//创建连接工厂
ConnectionFactory factory = new ConnectionFactory();
factory.setUsername("guest");
factory.setPassword("guest");
factory.setHost("129.204.174.193");
factory.setVirtualHost("/");
Connection conn = factory.newConnection();
Channel channel = conn.createChannel();
String exchangeName = "hello-exchange";
channel.exchangeDeclare(exchangeName, "direct", true);
String routingKey = "testRoutingKey";
byte[] messageBodyBytes = "quit".getBytes();
channel.basicPublish(exchangeName, routingKey, null, messageBodyBytes);
channel.close();
conn.close();
}
}
以上是直接用java连接,当然我们可以选择用Spring 或 springboot来处理,这样我们就不必自己来创建连接,做配置了,直接操作RabbitTemplate要方便的多。
持久化
为了消息不丢失,我们需要做持久化,关键点是,持久化我们要对交换器,队列,消息都进行持久化,交换器和队列在声明时候有个durable的参数设置成ture就可以了,消息在发生时,配置BasicProperties,把deliveryMode设置成2就可以了
消息确认
消息确认存在两个地方,一个是由生产者向Broker,二是Broker向消费者
使用场景
消息异步
消息推送
能够推送在于RabbitMQ居然连js都能操作,我们在js里声明客户端,然后监听队列。