1. 基础知识
1. 常见问题
- 发送端没有设置接收的队列名称, rabbitMQ如何处理?
答案:若没有设置“queue”的名字时,会根据“Routing Key”去找是否存在接收队列的名称和“Routing key”一致的队列。存在,则可以传递消息成功,否则,无法传递数据。使用的队列是(AMQP default),若是找不到接收队列,会删除传递的数据。 - RabbitMQ的优点:
- 因为开发语言为Erlang语言,而Erlang语言最初作为交换机使用。因此,对于数据的通信可以达到Socket的水平,因此,性能较好。
2. Exchange(交换机)
1. 属性
- name: 名称
- Type:交换机类型:direct,topic,fanout,headers;
- DuDurability:是否需要持久化;
- Auto delete:当最后一个绑定到exchange上的队列删除后,自动删除该exchange;
- InterInternal:当前exchange是否用于rabbitMQ内部使用,默认为false;
2. Direct Exchange(直连交换机)
- 概念:所有发送到Direct Exchange的消息被转发到Routing key中指定的Queue。
- 操作:可以使用RabbitMQ自带的Exchange:default Exchange,所以不需要将Exchange进行任何绑定操作,消息传递时,Routing Key完全匹配时,才能被队列接收,否则该消息被丢弃。
3. Topic Exchange(主题交换机)
- 概念:
- 所有发送到Topic Exchange的消息被转发到所有关心Routing key中指定的Topic的Queue上。
- Exchange将Routing key和某个Topic进行模糊匹配,此时队列需要绑定一个Topic。
- 可以使用通配符进行模糊匹配;"#":匹配一个或多个词;"*":只能匹配一个词;
- eg: "log.#“能够匹配到"log.ingo.aa”;
- eg: “log.*” 能够匹配到"log.erro"
- 注意事项
- 使用log.*的时候, 查看是否会出现两个routing key, 一个为
log.#、log.*
;? - queue绑定了routing key 不会自动删除routing key;?
4. Fanout Exchange
- 概念:
- 不处理路由键,只需要简单的将队列绑定到交换机上;
- 发送到交换机的消息都会被转发到与该交换机绑定的所有队列上;
- 是转发消息最快的;
- 不需要使用routing key, 直接转发到队列,减少了很多匹配规则,所以,速度很快;
3. Binding(绑定)
- 可以绑顶Exchange和Exchange、Queue之间的联系关系;也就是说,可以Exchange之间进行绑定,发送消息的路径就是:Queue-> Exchange->Exchange->Queue。
- Binding中可以包含Routing Key或参数。
4. Queue(消息队列)
- 参数:
- Durability:是否持久化;Durable:持久化;Transient:不持久化;
- Auto Delete:当最后一个监听被移除的时候,该Queue也会被删除。
5. Message(消息)
- 本质上就是一段数据,由properties和payload(body)组成。
- 常用属性:delivery mode:1不持久化 2持久化, headers(自定义属性)。
- 其他属性:
- content_type:消息格式,eg:json、xml等等。
- content——encoding:消息编码;
- priority:优先级。优先级高的优先被消费,但是,在集群模式下,无法保证消息消费的顺序性。
- correlation_id:消息唯一id,常用业务id+时间戳组成;可以用于ACK以及幂等性的控制。
- replay_to:消息失败时,返回到哪个队列。
- expiration:消息的过期时间。
- message_id/timestamp/type/user_id/app_id/cluster_id;
- 用例:
public class RabbitMQMessageProduct {
public static void main(String[] args) throws Exception {
ConnectionFactory connectionFactory = new ConnectionFactory();
connectionFactory.setHost("127.0.0.1");
connectionFactory.setPort(5672);
connectionFactory.setVirtualHost("/");
Connection connection = connectionFactory.newConnection();
Channel channel = connection.createChannel();
String message = "Hello world!, RabbitMQ!";
Map<String, Object> headers = new HashMap<>();
headers.put("pro1", "1111");
headers.put("pro2", "2222");
AMQP.BasicProperties properties = new AMQP.BasicProperties().builder()
.deliveryMode(JmsProperties.DeliveryMode.PERSISTENT.getValue())
.contentEncoding("UTF-8")
.expiration("15000")
.headers(headers)
.build();
IntStream.range(0, 5).forEach(item -> {
try {
channel.basicPublish("", "test001", properties, message.getBytes());
} catch (IOException e) {
e.printStackTrace();
}
});
channel.close();
connection.close();
}
public class RabbitMQMessageConsumer {
public static void main(String[] args) throws Exception {
ConnectionFactory connectionFactory = new ConnectionFactory();
connectionFactory.setHost("127.0.0.1");
connectionFactory.setPort(5672);
connectionFactory.setVirtualHost("/");
Connection connection = connectionFactory.newConnection();
Channel channel = connection.createChannel();
String queueName = "test001";
channel.queueDeclare(queueName, true, false, false, null);
QueueingConsumer consumer = new QueueingConsumer(channel);
channel.basicConsume(queueName, true, consumer);
while (true) {
QueueingConsumer.Delivery delivery = consumer.nextDelivery();
String body = new String(delivery.getBody());
System.out.println("消费端: " + body);
AMQP.BasicProperties properties = delivery.getProperties();
}
}
}
6. Virtual host(虚拟主机)
- 虚拟主机,用于进行逻辑分离,最上层的消息路由;
- 一个Virtual host里面可以有多个Exchange和Queue;
- 但是,在同一个Virtual host中不能存在同名的Exchange和Queue。