可靠消息的最终一致性解决方案
本地消息服务的方案
实现思路
- 消息生产者通过业务操作完成数据的操作,在准备发送消息的时候,先将消息存储一份,然后发送给消息中间件集群。
- 消息消费者监听消息中间件中的消息,消费者消息处理之后,调用消息生产者接口,进行消息消费确认。
- 消息生产者接受消息确认之后,删除消息数据。
- 消息查询服务查询消息在被接收之后没有返回消息消费确认,那么就通过消息恢复系统进行消息重新发送。
架构图
优点
- 消息时效性比较高
- 从应用设计角度实现了消息的可靠性,弱化了对 MQ中间件特性的依赖。
- 方案比较轻量级,容易实现。
缺点
- 与具体的业务场景强耦合,不可以其他业务场景共用。
- 消息数据与业务数据同步,占用业务系统资源
- 业务系统在使用关系型数据的情况下,消息服务性能会受到关系型数据库的限制。
独立消息服务实现方案
实现思路
- 预发送消息:消息生产者系统预先发送消息,由消息服务子系统负责消息存储,如果存储失败,那么消息生产者不能进入业务操作,如果消息存储成功,消息生产者模块可进行后续业务操作。
- 执行业务操作:执行业务操作成功后,将业务操作执行的状态,发送到消息服务子系统,消息服务子系统性消息的标识为 “可发送” 状态。
- 发送消息到 MQ 集群服务:宕消息的状态发生改变,变成可发送的时候,立即将消息发生到 MQ 集群中,消息通过 MQ 集群被消费者监听到,被消费处理。
- 消息状态子服务:定时任务系统,在消息服务子系统中,定时查找消息中定时查找确认超时的消息,在主动方应用系统中去定时查找确认超时的消息,并且去消息生产者方查询没有处理成功的任务,进行相应处理。
- 消息恢复子系统:当消息生产者发送消息的时候,出现了网络中断等原因,出现了还没有及时确认,那么需要消息恢复子系统定时查出消息中未确认的消息,将未确认的消息进行消息重发,这也需要消息消费者皆是幂等的。
优点
- 消息服务独立部署,独立维护,独立伸缩。
- 消息存储可以选择不同的数据库来实现
- 消息服务可以被相同的使用昌吉使用,降低重复建设服务成本
- 从分布式服务应用设计角度时间消息数据的可靠性,消息数据的可靠性,弱化了对 MQ 中间件的依赖。
缺点
- 一次那个消息发生需要两次请求
- 消息生产者需要显示业务状态校验和查询接口。
实现架构
表结构设计
名称 | 数据类型 | 允许空 | 默认值 | 属性 | 释义 |
uuid | varchar(50) | No | — | unique | UUID |
version | int(11) | No | 0 | — | 版本号 |
editer | varchar(100) | Yes | NULL | — | 修改者 |
creater | varchar(100) | Yes | NULL | — | 创建者 |
edit_time | datetime | Yes | 0000-00-00 00:00:00 | — | 最后修改时间 |
create_time | datetime | No | 0000-00-00 00:00:00 | — | 创建时间 |
msg_id | varchar(50) | No | — | — | 消息ID |
msg_body | longtext | No | — | — | 消息内容 |
msg_date_type | varchar(50) | Yes | — | — | 消息数据类型 |
consumer_queue | varchar(100) | No | — | — | 消费队列 |
send_times | int(6) | No | 0 | — | 消息重发次数 |
is_dead | varchar(20) | No | — | — | 是否死亡 |
status | varchar(20) | No | — | — | 状态 |
remark | varchar(200) | Yes | — | — | 备注 |
field0 | varchar(200) | Yes | — | — | 扩展字段0 |
field1 | varchar(200) | Yes | — | — | 扩展字段1 |
field2 | varchar(200) | Yes | — | — | 扩展字段2 |