1. RabbitMQ简介
RabbitMQ是一个开源的消息代理和队列服务器,用来通过普通协议在完全不同的应用之间共享数据。RabbitMQ是使用Erlang语言来编写的,并且基于AMQP(Advanced Message Queuing Protocol,高级消息队列协议)协议实现。
1.1 RabbitMQ的核心概念
- Virtual Host(虚拟主机)
- 用于逻辑隔离,最上层的消息路由
- 一个Virtual Host里面可以有若干个Exchange和Queue
- 同一个Virtual Host里面不能有相同名称的Exchange或Queue
- Exchange(交换机)
- 接收消息,根据路由键转发消息到绑定的队列
- 四种类型:direct、topic、fanout、headers
- 每种类型对应不同的路由策略
- Queue(队列)
- 存储消息的实体
- FIFO原则
- 可以设置持久化、自动删除等属性
- Binding(绑定)
- Exchange和Queue之间的虚拟连接
- 包含routing key(路由键)
- 决定消息如何从Exchange路由到Queue
- Channel(信道)
- 建立在Connection连接内的虚拟连接
- 复用TCP连接,减少性能开销
- 会话的最小单位
1.2 Exchange类型详解
Exchange是RabbitMQ中最核心的组件之一,负责接收消息并将其路由到一个或多个队列。RabbitMQ提供了四种不同类型的Exchange,每种类型有不同的路由算法,适用于不同的业务场景。
1.2.1 Direct Exchange(直接交换机)
工作原理:Direct Exchange将消息路由到binding key与routing key完全匹配的队列中。
使用场景:适用于明确定向的消息传递,如特定服务的任务分发、精确的指令下发等。
常用性:高,是最常用的Exchange类型之一。
示例:
@Bean
public DirectExchange userExchange() {
return new DirectExchange("user.exchange");
}
@Bean
public Queue userCreateQueue() {
return new Queue("user.create.queue");
}
@Bean
public Queue userUpdateQueue() {
return new Queue("user.update.queue");
}
@Bean
public Binding bindUserCreate() {
return BindingBuilder.bind(userCreateQueue())
.to(userExchange())
.with("user.create"); // routing key
}
@Bean
public Binding bindUserUpdate() {
return BindingBuilder.bind(userUpdateQueue())
.to(userExchange())
.with("user.update"); // routing key
}
消息路由示例:
- 发送routing key为
user.create
的消息,只有user.create.queue
队列会收到 - 发送routing key为
user.update
的消息,只有user.update.queue
队列会收到 - 发送routing key为
user.delete
的消息,由于没有对应的binding,消息会被丢弃
1.2.2 Topic Exchange(主题交换机)
工作原理:Topic Exchange根据通配符匹配规则将消息路由到binding key与routing key模式匹配的队列中。
*
表示匹配一个单词#
表示匹配零个或多个单词
使用场景:适用于消息的分类订阅,如日志系统的多级别过滤、多条件组合的消息订阅等。
常用性:高,在需要灵活匹配的业务场景中广泛使用。
示例:
@Bean
public TopicExchange logExchange() {
return new TopicExchange("log.exchange");
}
@Bean
public Queue errorQueue() {
return new Queue("error.log.queue");
}
@Bean
public Queue allOrdersQueue() {
return new Queue("all.orders.queue");
}
@Bean
public Queue createEventsQueue() {
return new Queue("create.events.queue");
}
@Bean
public Binding bindErrorLogs() {
return BindingBuilder.bind(errorQueue())
.to(logExchange())
.with("log.error.#"); // 匹配所有error日志
}
@Bean
public Binding bindAllOrders() {
return BindingBuilder.bind(allOrdersQueue())
.to(logExchange())
.with("order.#"); // 匹配所有订单消息
}
@Bean
public Binding bindCreateEvents() {
return BindingBuilder.bind(createEventsQueue())
.to(logExchange())
.with("*.*.create"); // 匹配所有create事件
}
消息路由示例:
- 发送routing key为
log.error.database
的消息,error.log.queue
队列会收到 - 发送routing key为
order.created
的消息,all.orders.queue
队列会收到 - 发送routing key为
user.profile.create
的消息,create.events.queue
队列会收到 - 发送routing key为
order.shipping.create
的消息,两个队列都会收到:all.orders.queue
和create.events.queue
1.2.3 Fanout Exchange(扇形交换机)
工作原理:Fanout Exchange将消息广播到所有绑定的队列,忽略routing key。
使用场景:适用于广播消息,如系统公告、群发通知、实时数据更新等需要一对多传递的场景。
常用性:中等,在广播场景中使用频率较高。
示例:
@Bean
public FanoutExchange notificationExchange() {
return new FanoutExchange("notification.exchange");
}
@Bean
public Queue emailQueue() {
return new Queue("email.queue");
}
@Bean
public Queue smsQueue() {
return new Queue("sms.queue");
}
@Bean
public Queue pushQueue() {
return new Queue("push.queue");
}
@Bean
public Binding bindEmail() {
return BindingBuilder.bind(emailQueue())
.to(notificationExchange());
}
@Bean
public Binding bindSms() {
return BindingBuilder.bind(smsQueue())
.to(notificationExchange());
}
@Bean
public Binding bindPush() {