文章纲要
- 此次分享的缘由
- 目前分布式事务问题是怎么解决的
- 行业中有什么解决方案
- 这些解决方案分别有什么优缺点
- 别人是怎么做的
- 我们可以怎么来做
- 此次分享的缘由
支付重构
考虑支付重构的时候,自然想到原本属于一个本地事务中的处理,现在要跨应用了要怎么处理。拿充值订单举个栗子吧,假设:原本订单模块和账户模块是放在一起的,现在需要做服务拆分,拆分成订单服务,账户服务。原本收到充值回调后,可以将修改订单状态和增加金币放在一个mysql事务中完成的,但是呢,因为服务拆分了,就面临着需要协调2个服务才能完成这个事务
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-XymvVKng-1582120176378)(https://upload-images.jianshu.io/upload_images/15462057-41d07ec6605b9c95.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)]
所以就带出来,我们今天要分享和讨论的话题是:怎么解决分布式场景下数据一致性问题,暂且用分布式事务来定义吧。
同样的问题还存在于其他的场景:
送礼:
调用支付服务:先扣送礼用户的金币,然后给主播加相应的荔枝,确认第一步成功后,播放特效,发聊天室送礼评论等复制代码
充值成功消息:
完成充值订单,发送订单完成的kafka消息,在涉及支付交易等付费接口的时候,数据一致性的问题就显得尤为重要,因为都是钱啊
目前分布式事务是怎么解决的呢?
问题肯定不是新问题,也就是目前已经有相应的解决方案了,那就看一下现在是怎么来解决这类问题的吧。
以购买基础商品成功后发送支付订单完成消息为例:假设支付下单购买基础商品,此刻已经收到支付回调,订单已经处理成功了,这个时候kafka服务故障,消息发送失败;而这个时候处理订单的事务已经提交了,怎么保证订单完成的消息一定能发出去呢?
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-sfnREAqA-1582120176379)(https://upload-images.jianshu.io/upload_images/15462057-dd5ed02e9652e210.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)]
解读一下这个流程:
绿色部分,表示流程正常运行的交互过程:
先往JobController中提交一个job(用于故障恢复)
提交成功后,开始处理订单逻辑
处理完订单逻辑之后,开始发送kafka消息
消息也发送成功后,删除第一步提交的job
黄色部分,表示流程出现了异常,数据可能存在不一致现象。这个时候就需要进行流程恢复
JobController任务控制器定时去redis查询延时任务列表(每个任务都有一个时间戳,按时间戳排序过滤)
将任务进行恢复(调用job注册时定义的处理方法)
任务执行成功,表示流程完成;否则下一个定时周期重试
问题:
基于redis存储恢复任务,可能存在数据丢失风险
架构体系中没有统一的分布式事务规范,可否将这层逻辑独立为分布式事务中间件
缺少事务执行策略管理,如:控制最大重试次数等
事务执行状态没有记录,追查需要去翻看日志
行业中有什么解决方案
说解决方案之前,我们先了解一下这些方案的理论依据,有助于帮助我们来理解和实践这些方案
理论依据(讨论的前提)
本地事务、分布式事务
如果说本地事务是解决单个数据源上的数据操作的一致性问题的话,那么分布式事务则是为了解决跨越多个数据源上数据操作的一致性问题。
强一致性、弱一致性、最终一致性
从客户端角度,多进程并发访问时,更新过的数据在不同进程如何获取的不同策略,决定了不同的一致性。对于关系型数据库,要求更新过的数据能被后续的访问都能看到,这是强一致性。如果能容忍后续的部分或者全部访问不到,则是弱一致性。如果经过一段时间后要求能访问到更新后的数据,则是最终一致性
从服务端角度&