文章目录如何设计一个消息队列组件设计持久化与集群设计注册中心注册中心的作用高可用设计关键特性实现可靠性延时性事务消息消息队列工作流程如何设计一个消息队列组件设计上游任务发送一个消息到队列下游服务监听队列消息此时上游服务就是消息的生产者下游服务就是消息的消费者这种模式叫队列模式或点对点模式。一个消息被发送到队列然后多个消费者竞争消费每个消息只能够被一个消费者处理如果有多个消费者想消费同一个消息那就只能复制多个队列然后每个消费者都消费自己的队列。问题来了复制多个队列不仅浪费资源而且队列和消费者强绑定了那如果某个消费者不消费了就要去掉对应的队列这完全违背了解耦的目标。怎么办呢可以让每个消费者都订阅某个主题也就是topic生产者把消息发送到这个topic然后队列可以把收到的这个消息发送给所有订阅了这个topic的消费者这个叫主题模式或者发布订阅模式。消费者不再依赖队列了而是订阅topic。一个topic中可以有一个或多个队列这样队列就可以随意的水平扩容。消息队列可能不止有一个topic可能有多个topic所以得在外面包一层来管理多个topic这个就叫broker生产者把消息发送到brokerbroker根据消息的topic放到对应的队列当中然后消费者根据topic去获取消息。持久化与集群设计那么问题来了把消息存内存里他不是很安全重启他就会丢失所以broker收到消息之后需要把收到的这个消息保存到磁盘里做持久化。那么问题又来了如果说你的broker只有一个那就会有单点故障问题所以得做个主从写消息只能写到broker的主节点从节点只能用来读。从节点定期去从主节点同步数据这与 MySQL 的读写分离、Redis 的主从架构简直一样。那么问题又来了broker主从存的数据是一样的那每个broker所能承载的消息数量也是有上限的 而且主节点并发写的能力也是具有瓶颈的怎么办呢部署多个主从节点构成一个broker集群然后把每个topic的队列和数据分散存储到不同的broker节点上那这样集群里面不同的主节点都各自保存topic的部分数据然后每个节点的压力就减少了。类似于 MySQL 的分库分表Redis 的分片集群。注册中心那么问题又来了那么多个broker生产者发消息的时候怎么知道应该发给哪个broker呢消费者获取消息的时候怎么知道应该从哪个broker中获取消息呢所以这时候就需要一个注册中心专门去管理broker集群。注册中心的作用保存集群的状态信息通过broker定时去上报心跳来实时感知这个节点上下线确保这个请求不会达到一个故障节点掌管消息路由让生产者知道消息应该发送给哪个broker让消费者知道应该从哪个broker去读取消息负责集群的负载均衡、故障转移为了保证注册中心的高可用注册中心自身也得做集群。高可用设计生产者 通过注册中心感知 Broker 列表根据 Key 做 Hash 保证局部有序或轮询保证全局均衡。消费者组 实现多实例并发消费。当成员变化时触发 Rebalance重平衡。借鉴 Kafka 的 ISR 机制。只有在 ISR 列表中的副本都写成功才返回 ACK平滑权衡可用性与可靠性。关键特性实现可靠性生产者 等待 ACK 成功。broker 同步刷盘 多副本。消费者 处理完业务手动提交 Offset。延时性建立时间轮或多级延时队列如 1s, 5s, 10s…。到期后再投递到真实topic。事务消息采用两阶段提交 (2PC) 反查机制。先发半消息本地事务执行完后再提交失败则回滚。消息队列工作流程broker集群定期向注册中心去发送心跳包上报自身消息。注册中心掌管了所有broker的节点信息和消息的路由信息生产者要给某个topic发送消息的时候通过访问注册中心获取到某个topic的路由表就能知道自己的消息应该发送给哪个broker的哪个队列然后对应的broker的主节点收到消息后同步消息给从节点然后将消息持久化。消息的消费者访问注册中心订阅对应的topic就能够获取到这个topic的一个路由表然后就能知道应该去哪个broker哪个队列里去拉取消息了。