消息代理(Broker)核心原理

消息代理,说白了就是整个订阅分发系统的「交通枢纽」。我刚开始接触数据交换时,总觉得它就是个简单的消息——收到消息,转发出去,完事。后来在项目中踩过几次坑才明白,Broker 承担的角色远比想象中复杂。

这一节,咱们就聊聊 Broker 到底在干什么,它的消息怎么路由,怎么保证消息不丢,以及万一挂了怎么办。

Broker 的角色与职责

Broker 不是简单的「传话筒」。它至少得干这几件事:

  • 连接管理:维护与生产者、消费者的长连接。我见过一个项目,连接数从几百涨到几万,Broker 直接 OOM 了——连接管理没做好,再好的业务逻辑也白搭。
  • 消息验证:检查消息格式、权限、大小。别让非法消息混进来。
  • 消息路由:根据订阅规则,把消息送到该去的地方。
  • 消息存储:持久化消息,防止丢失。
  • 负载均衡:多个消费者时,合理分配消息。
  • 心跳检测:监控客户端是否还活着。

核心职责一句话:Broker 要保证「消息不丢、不重、不乱序」,同时扛住高并发。

我个人习惯把 Broker 比作「邮局」。你寄信(生产者发消息),邮局分拣(路由),然后投递(转发给消费者)。如果邮局不靠谱,信就丢了——消息系统也一样。

消息路由机制

路由是 Broker 最核心的能力。它决定了消息到底发给谁。常见的路由模式有几种:

路由模式 工作原理 典型场景
直接路由 消息携带 Routing Key,匹配消费者绑定的 Key 点对点通信
主题路由 使用通配符匹配主题(如 order.*) 日志分类、事件广播
扇出路由 消息发给所有绑定的队列,不关心 Key 全局通知、配置同步
头部路由 根据消息头属性匹配 复杂过滤条件

你想想看,如果系统里有 100 种消息类型,每个消费者只关心其中 3 种。没有路由机制,Broker 就得把全部消息发给每个消费者——那网络和 CPU 都得炸。

我在项目中遇到过一个问题:主题路由用了 order.# 这种通配符,结果某个消费者绑定了 order.*,两者匹配逻辑不一样,导致部分消息没收到。嗯,这里要注意——通配符的语义一定要跟团队对齐。

消息存储与转发

消息存储是 Broker 的「保底机制」。消费者可能不在线,或者处理速度跟不上。这时候消息不能丢,得先存起来。

存储策略一般分两种:

  • 内存存储:快,但重启就丢。适合允许丢失的日志类消息。
  • 磁盘持久化:慢一点,但可靠。适合订单、支付等关键业务。

我建议关键业务一定要用磁盘持久化。曾经有个同事为了性能,把支付消息放内存里,结果 Broker 一重启,几万笔订单对不上账……那场面,你懂的。

存储后的转发逻辑也很讲究:

  1. 先写日志:消息先写入 WAL(Write-Ahead Log),保证不丢。
  2. 再入队列:写入内存队列,准备分发。
  3. 确认机制:消费者处理完发回 ACK,Broker 才删除消息。
  4. 重试机制:如果消费者没 ACK,Broker 会重新投递。

小技巧:消息重试次数要设上限。我曾经见过一个系统,消息重试了 10 万次,把磁盘写满了。设个 3 次,不行就进死信队列。

这里有个典型的存储转发流程,我画了张图:

消息存储与转发流程 生产者 WAL 日志 内存队列 消费者 ACK 确认 死信队列 重试(超时/失败) 说明:消息先写入 WAL 确保持久化,再入内存队列快速分发。 消费者处理完成后发送 ACK,Broker 才删除消息。超时未 ACK 则重试或进死信队列。

高可用设计

Broker 挂了怎么办?这是每个架构师都得想清楚的问题。高可用设计,说白了就是「别让单点搞死整个系统」。

常见的方案有几种:

  • 主从复制:一个主节点负责读写,从节点同步数据。主挂了,从顶上。
  • 集群模式:多个 Broker 组成集群,分担压力。一个挂了,其他继续干活。
  • 分区容错:把消息分散到不同分区,每个分区有副本。某个副本挂了,不影响整体。

注意:主从切换不是瞬间完成的。切换期间会有短暂的服务不可用。如果你的业务要求「零宕机」,那得用更复杂的多活架构。

我曾经在一个金融项目中踩过坑:主从复制用的是异步模式,主节点突然断电,有几千条消息还没同步到从节点。等从节点升为主后,那些消息就丢了。后来我们改成了同步复制——性能降了一点,但数据一致性有了保障。

高可用设计的核心指标,我列了个表:

指标 说明 典型值
RTO 恢复时间目标,从故障到恢复的时间 秒级 ~ 分钟级
RPO 恢复点目标,最多丢失多少数据 0(同步复制)~ 秒级(异步)
可用性 系统正常运行时间占比 99.9%(3个9)~ 99.999%(5个9)

你想想看,如果 RTO 是 5 分钟,那故障后 5 分钟内系统必须恢复。如果 RPO 是 0,那一笔数据都不能丢。这两个指标决定了你的高可用方案要花多少钱。

我个人习惯在设计高可用时先问三个问题:

  1. 业务能接受多久的停机?
  2. 能接受丢多少数据?
  3. 预算有多少?

这三个问题问完,方案基本就定了。别一上来就搞五副本、跨机房容灾——成本扛不住,运维也累。

经验之谈:中小规模系统,主从复制 + 定期备份就够了。大规模系统才需要考虑多分区、多副本、自动故障转移。别过度设计。