分布式事务一致性:本地消息表设计与实践
概念
本地消息表是一种常见的解决分布式事务问题的方法。其核心思想是将分布式事务拆分成本地事务来处理,通过消息队列来保证各个本地事务的最终一致性。
实现步骤
-
创建本地消息表:在数据库中创建一个本地消息表,用于存储待发送的消息以及消息的发送状态和相关信息。表结构通常包含字段如 message_id(消息唯一标识)、message_body(消息内容)、status(消息状态,如待发送、已发送等)、create_time(消息创建时间)等;
-
业务处理与消息记录:在业务逻辑中,当需要发送消息时,首先将消息插入到本地消息表中,设置状态为待发送。然后执行业务逻辑,并将业务变更信息与消息记录插入操作放在同一个本地事务中;
-
消息发送:创建一个后台线程或定时任务,定时扫描本地消息表中状态为待发送的消息,并将这些消息发送到消息队列。在成功发送到消息队列后,将消息表中对应的状态修改为已发送;
-
消息消费:消费者监听消息队列,解析消息内容,并执行相应的业务逻辑处理。此步骤必须保证幂等性,即多次消费相同的消息不会导致数据不一致;
-
消息状态确认:当消息消费完成后,进行状态变更。如果消费失败,需要根据失败原因进行重试或人工处理;
注意事项
- 消息的幂等性:消费者必须保证接口的幂等性,以防止消息重复处理导致的数据不一致;
- 本地消息表的设计:需要考虑到消息状态、重试次数、创建时间等字段,以便实现消息的跟踪和管理;
- 定时任务和重试机制:实现定时任务或者重试机制来确保消息的可靠发送和处理;
缺点及解决方式
- 消息堆积、扫表效率慢:可以通过索引优化、分页查询、分库分表、多线程分段查询等方法提高效率;
- 定时任务扫表延迟问题:可以通过异步发送MQ改为同步调用接口、发送MQ延迟消息、分布式定时任务等方法减少延迟;
应用场景
本地消息表适用于金融、电商等领域,尤其适用于涉及多个服务交互的复杂交易场景,如资金转账、订单创建等。通过其强大功能,可以确保在分布式环境中实现事务的一致性和可靠性,有效防止数据不一致的问题。
通过上述方法,可以在不使用开源框架的情况下,利用本地消息表实现分布式事务,保证数据的一致性和系统的稳定性。
实际使用
下面是一个消息表的设计
CREATE TABLE ` mq_notify ` (
` id ` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增主键',
` payment_no ` varchar(30) NOT NULL COMMENT '订单号',
` message ` varchar(1000) DEFAULT NULL COMMENT 'mq message',
` retry ` tinyint(4) NOT NULL COMMENT '发送剩余次数',
` status ` tinyint(4) NOT NULL COMMENT '状态',
` yn ` tinyint(4) NOT NULL COMMENT '是否有效',
` create_time ` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
` update_time ` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '修改时间',
PRIMARY KEY (` id `) ,
KEY ` idx_status ` (` status `)
) ENGINE = InnoDB COMMENT = 'mq消息表'
在插入消息表时,可以设置重试的最大次数,比如 3。
在定时任务扫描时,筛选retry > 0 且 status = 'init'
的消息记录,发送mq成功,status 更新为'finish'
,发送mq失败,retry 次数减一。
如果消息发送 3 次还没有成功,此时就需要报警人工介入了。