学而时习之,不亦说乎
前言
对于分布式系统,为了保证数据的一致性,需要使用到分布式事务,分布式事务实现的方式有多种,本文简单列举几种实现方式,分析最终一致性事务的实现思路和实现方式。
两阶段提交(Two-phase Commit)
参与者将操作成败通知协作者,再有协作者根据所有参与者的反馈情况决定各参与者是提交操作还是终止操作
典型实践:TX-LCN分布式事务架构
TCC补偿(Try-Confirm-Cancel)
通过Try锁住服务中的业务资源进行资源预留,只有资源预留成功后,后续的操作才能正常进行。Confirm则是在所有操作成功时的提交操作,Cancel则是存在操作失败时的回滚操作。
典型实践:spring-cloud-rest-tcc
最终一致性
基于消息中间件的异步流程中的最终一致性保证方案。
实现思路:
- 业务主动方本地事务失败,业务被动方不会受到消息的投递
- 只有业务主动方本地事务执行成功,那么消息服务一定会投递消息给下游的业务被动方,并最终保证业务被动方一定能成功消费该消息
实现步骤
-
方法调用开始,业务的主动推送方预先发送一条包含业务信息的消息至消息服务中
-
消息服务接受到消息,持久化该消息至数据库中,并设置记录状态为【待确认】,如果消息保存失败,则直接返回消息持久化失败,本次业务结束。
-
当主动方接收到消息存储成功的结果后,开始执行本地业务操作,根据本地事务操作结果,调用消息服务,这里分为两种情况
a. 如果本地事务执行成功,就将消息记录状态更新为【待发送】
b. 如果本地事务执行失败,就将消息记录状态更新为【已回滚】
-
被动方服务订阅主题消息后等待MQ投递消息,被动方接收到消息并在本地事务中执行,这里分为两种情况
a. 如果本地事务执行成功,就调用消息服务,更新消息记录状态为【已完成】
b. 如果本地事务执行失败,则不进行任何处理
-
负责发送消息的程序会将【待发送】的消息进行重新发送,直到消息被正确消费。
重复消费问题
为了消息确保可以被消费,所以会有重试机制,但由于重试机制的存在,有会导致重复消费的问题
如何解决重复消费,则需要保证接口幂等,所谓幂等即是相同的参数调用接口,调用多少次结果都一样。 如何保证幂等,可以按照不同业务场景:
强校验,适合比较敏感的数据比如金额场景下,记录一张流水表,将加钱和增加流水信息在一个事务中,保证原子性,每次调用接口先判断是否已经产生了流水,如果已经产生,则说明已经处理过,直接返回即可
弱校验,适合不怎么重要的场景,比如发短信,将ID+场景唯一性标识作为redis的key缓存起来,可以设定一定时间实效,在一定时间段内去redis判断是否存在对于key
最大努力通知
最大努力通知性事务适用于跟外部系统之间的通讯,通过定期通知的方式来达到数据的一致性。
开启掘金成长之旅!这是我参与「掘金日新计划 · 2 月更文挑战」的第 5 天,点击查看活动详情