消息代理(Broker)核心原理
消息代理,说白了就是整个订阅分发系统的「交通枢纽」。我刚开始接触数据交换时,总觉得它就是个简单的消息——收到消息,转发出去,完事。后来在项目中踩过几次坑才明白,Broker 承担的角色远比想象中复杂。
这一节,咱们就聊聊 Broker 到底在干什么,它的消息怎么路由,怎么保证消息不丢,以及万一挂了怎么办。
Broker 的角色与职责
Broker 不是简单的「传话筒」。它至少得干这几件事:
- 连接管理:维护与生产者、消费者的长连接。我见过一个项目,连接数从几百涨到几万,Broker 直接 OOM 了——连接管理没做好,再好的业务逻辑也白搭。
- 消息验证:检查消息格式、权限、大小。别让非法消息混进来。
- 消息路由:根据订阅规则,把消息送到该去的地方。
- 消息存储:持久化消息,防止丢失。
- 负载均衡:多个消费者时,合理分配消息。
- 心跳检测:监控客户端是否还活着。
核心职责一句话:Broker 要保证「消息不丢、不重、不乱序」,同时扛住高并发。
我个人习惯把 Broker 比作「邮局」。你寄信(生产者发消息),邮局分拣(路由),然后投递(转发给消费者)。如果邮局不靠谱,信就丢了——消息系统也一样。
消息路由机制
路由是 Broker 最核心的能力。它决定了消息到底发给谁。常见的路由模式有几种:
| 路由模式 | 工作原理 | 典型场景 |
|---|---|---|
| 直接路由 | 消息携带 Routing Key,匹配消费者绑定的 Key | 点对点通信 |
| 主题路由 | 使用通配符匹配主题(如 order.*) |
日志分类、事件广播 |
| 扇出路由 | 消息发给所有绑定的队列,不关心 Key | 全局通知、配置同步 |
| 头部路由 | 根据消息头属性匹配 | 复杂过滤条件 |
你想想看,如果系统里有 100 种消息类型,每个消费者只关心其中 3 种。没有路由机制,Broker 就得把全部消息发给每个消费者——那网络和 CPU 都得炸。
我在项目中遇到过一个问题:主题路由用了 order.# 这种通配符,结果某个消费者绑定了 order.*,两者匹配逻辑不一样,导致部分消息没收到。嗯,这里要注意——通配符的语义一定要跟团队对齐。
消息存储与转发
消息存储是 Broker 的「保底机制」。消费者可能不在线,或者处理速度跟不上。这时候消息不能丢,得先存起来。
存储策略一般分两种:
- 内存存储:快,但重启就丢。适合允许丢失的日志类消息。
- 磁盘持久化:慢一点,但可靠。适合订单、支付等关键业务。
我建议关键业务一定要用磁盘持久化。曾经有个同事为了性能,把支付消息放内存里,结果 Broker 一重启,几万笔订单对不上账……那场面,你懂的。
存储后的转发逻辑也很讲究:
- 先写日志:消息先写入 WAL(Write-Ahead Log),保证不丢。
- 再入队列:写入内存队列,准备分发。
- 确认机制:消费者处理完发回 ACK,Broker 才删除消息。
- 重试机制:如果消费者没 ACK,Broker 会重新投递。
小技巧:消息重试次数要设上限。我曾经见过一个系统,消息重试了 10 万次,把磁盘写满了。设个 3 次,不行就进死信队列。
这里有个典型的存储转发流程,我画了张图:
高可用设计
Broker 挂了怎么办?这是每个架构师都得想清楚的问题。高可用设计,说白了就是「别让单点搞死整个系统」。
常见的方案有几种:
- 主从复制:一个主节点负责读写,从节点同步数据。主挂了,从顶上。
- 集群模式:多个 Broker 组成集群,分担压力。一个挂了,其他继续干活。
- 分区容错:把消息分散到不同分区,每个分区有副本。某个副本挂了,不影响整体。
注意:主从切换不是瞬间完成的。切换期间会有短暂的服务不可用。如果你的业务要求「零宕机」,那得用更复杂的多活架构。
我曾经在一个金融项目中踩过坑:主从复制用的是异步模式,主节点突然断电,有几千条消息还没同步到从节点。等从节点升为主后,那些消息就丢了。后来我们改成了同步复制——性能降了一点,但数据一致性有了保障。
高可用设计的核心指标,我列了个表:
| 指标 | 说明 | 典型值 |
|---|---|---|
| RTO | 恢复时间目标,从故障到恢复的时间 | 秒级 ~ 分钟级 |
| RPO | 恢复点目标,最多丢失多少数据 | 0(同步复制)~ 秒级(异步) |
| 可用性 | 系统正常运行时间占比 | 99.9%(3个9)~ 99.999%(5个9) |
你想想看,如果 RTO 是 5 分钟,那故障后 5 分钟内系统必须恢复。如果 RPO 是 0,那一笔数据都不能丢。这两个指标决定了你的高可用方案要花多少钱。
我个人习惯在设计高可用时先问三个问题:
- 业务能接受多久的停机?
- 能接受丢多少数据?
- 预算有多少?
这三个问题问完,方案基本就定了。别一上来就搞五副本、跨机房容灾——成本扛不住,运维也累。
经验之谈:中小规模系统,主从复制 + 定期备份就够了。大规模系统才需要考虑多分区、多副本、自动故障转移。别过度设计。