简介
消息中心(MsgBroker)作为一种典型的消息代理组件,是企业级应用系统中常用的消息中间件。MsgBroker 主要应用于分布式系统或组件之间的消息通讯,提供具有可靠、异步和事务等特性的消息通信服务。应用 MsgBroker 可以降低系统间耦合度,提高系统的吞吐量、可扩展性和高可用性。
核心角色
分布式消息服务主要涉及以下五个核心角色:
- 消息发布者(Publisher)
负责发送消息的应用系统,一个应用系统可以发送一种或者多种消息类型,发布者发送消息到消息中心。
- 消息中心(MsgBroker)
消息代理组件,负责接收发布者发送的消息,同时根据消息类型和订阅关系将消息分发投递给一个或多个消息订阅者。
- 消息订阅者(Subscriber)
负责订阅消息的应用系统,一个应用系统可以订阅一种或者多种消息类型,消息订阅者处理收到的消息并返回处理结果。
- 注册中心(ConfigServer)
负责发布者与订阅者寻址到消息中心的协调组件,和 SOFARPC 复用同样的注册中心。
- 数据库(DataBase)
存放数据的仓库,负责持久化存储消息和消费状态。主要使用 OceanBase,也可以支持 MySQL,Oracle 等多种数据库产品。
核心配置
发布者Topic、Group、事务回查监听器
Topic 是消息的一级分类,在抽象上看可以理解为是作为一个领域/应用级别的分类,我们可以理解为所有的消息都是会发送到一个 Topic ,它是发送者的目标。在实际交互上,Topic是消息中心的服务发现、请求路由与管理等机制实现的基础,也是连接生产者、消费者、MsgBroker的基础。
EventCode 是消息的二级分类,EventCode 相比于Topic更为细粒度。EventCode 是作为一种具有规定格式契约的具有特定业务场景的消息类型(实际上没有强类型),就相当于一个确定的远程调用接口。只有具有相同的 EventCode 的发布者和生产者才能真正的进行通信。
GroupId 不是针对于消息而言,而是针对于发布者与生产者而言的要素。通过Topic和事件码,我们确定了一个消息的投递方向和消息契约格式。但是消息中心的另一个特性:每个类型的消息可能会是多发布者-多订阅者的模式。即一条消息可能会被多个系统发出,也可能会被多组消费者消费。
Topic用来让客户端能够找到MsgBroker的服务地址,而GroupId则是让服务端可以用来准确找到客户端(发布者和生产者)的服务地址。更确切地说,GroupId是通过一个 group编码 映射了一组连接/接口,这个映射是维护在应用本地的。
- 在消息投递的过程中,MsgBroker会通过 Topic + 事件码来过滤出对应的消息需要投递的订阅关系列表,然后再通过 GroupId 对订阅关系列表分组,从而向每个 group 中投递消息至少一次。
- 在消息回查的过程中,MsgBroker也会通过 GroupId 来找到消息发送者的应用服务列表,来对消进行回查请求。
事务型消息
正常投递,在本地事务中先将消息发送到消息队列,然后根据本地事务状态提交或回滚消息队列消息。只有提交成功的事务消息才会被消息队列推送到订阅端。
异常状态下本地食物结果没能提交到消息队列,需要提供回查接口,给消息队列回查事务结果
如何写一个事务回查器?
注意问题:
问题一:多次发送问题
消息会查可能导致多次发送消息,需要与下游约定好幂等处理
问题二:回查注意数据状态
不能仅通过单据是否存在来决策回查,注意业务场景下的状态判断
问题三:回查时间问题
回查时可能本地还未处理结束,直接被认定为回滚导致消息丢失。可以通过判断业务时间15分钟以后再做回查判断。
常见故障
- 幂等问题
- 应该幂等但是没有幂等住消息导致多消费
- 不应该幂等但是把消息幂等住导致少消费
- 幂等时间不够导致幂等键丢失,比如用缓存做幂等键
- 消息时效性
- 本地发送消息逻辑导致消息发送不及时
- 消息消费处理不及时
- 消息堆积
- 消息逻辑异常无法消费导致消息堆积影响系统负载和业务时效性
- 系统本身提高请求负载、机器IO/CPU负载高导致当前消息堆积,最终致使处理不及时、消息无法消费、消息未处理被丢弃
- 不需要消费没有过滤,消息重复投敌,从而形成消息堆积影响业务系统
- 消息发送
- 由于部署环境原因、网路原因无法发送消息导致故障或者发送延时高
- 消息格式变更、字段缺失、字段变更,消息被发送出去但是不满足下游契约,导致下游无法消费
- 消息文本容量过大导致无法发送
- 由于代码实现逻辑导致漏发消息,多发消息
- 环境/切流
- 消息线上推到预发消费,推送到灰度消费等未做消息环境隔离导致正式环境丢消息,多消息
- 业务切换或业务升级过程中,使用两个订阅者同时作为新老业务的消费者,但是没有做好新老系统的隔离和幂等规则导致消息重复消费、消息丢失
- 配置问题
- 消息线上推到预发消费,推送到灰度消费等未做消息环境隔离导致正式环境丢消息,多消息
- 业务切换或业务升级过程中,使用两个订阅者同时作为新老业务的消费者,但是没有做好新老系统的隔离和幂等规则导致消息重复消费、消息丢失
- 中间件问题
- 消息中间件自身扩容,宕机,中间件升级等导致故障
- 消息磁盘、数据库IO/CPU打满导致无法消费
- 数据一致性问题
- 业务在执行过程中,业务单据数据与发送消息不一致,导致状态数据不一致。进而引发业务故障
- 消息乱序
- 消息乱序导致数据状态机不一致