一个分布式事务的解决方案

下文是为应对我司分布式事务带来的问题所设计的解决方案,已在生产环境应用,由于之前是word版本写的就直接copy来了,其中一些代码和命名不用太在意,可以提供给大家参考的主要是设计和实现思路,当然,这也是基于公司现有业务和本人设计水平而决定的,一定是不完美甚至是不完善的,不足指出,欢迎指正。

一 背景


  库存系统现进行改进优化,目标将以前所有与库存有直接关系的数据库表逐渐拆离出去。将以前各系统对这些表的访问,变为访问远程服务。远程服务由库存系统carInventory提供。如下图如示(以ordercollect表为例):无论“原先的方式”,还是“现在的方式”我们的业务系统程序流程都是同步执行的。


image.png

二 问题


  由于采用远程服务调用方式执行程序,程序的稳定和可靠性相对降低,风险加大,比如:

  • 请求及响应过程中网络异常(包括超时,未响应等)
  • 调用及被调用端程序异常
  • 其它影响程序稳定性的异常

三 问题分析

  这里我们将整个的调用过程中的调用方称为系统A,将被调用方称为子系统B。子系统B中封装了远程调用的方法,其中针对数据库表的操作是带事务的,如在子系统B的程序执行过程中出现了异常,因为有事务,所以会回滚异常数据。相对的,在系统A中在程序的执行过程中,也是带事务执行的,所以A、B两端分别有两个事务。
尽管在两端我们都有事务,可还是会在一些节点出现问题,如下图所示,是两系统RPC的交互过程。


image.png

  因为两系统的事务解决了两端程序的异常问题(回滚),所以这里我们重点关注的是请求响应异常的情况:
如下图所示:在请求返回异常结果的时候会出现以下两个问题:

  1. 一次请求不成功,有可能子系统B的数据已经入库,只是可能由于网络原因,或其它原因,导致返回结果异常。如果进行多次重试,每一次重试,由于子系统B的程序都能执行成功,将会产生赃数据。只不过还是返回的过程中出现异常
  2. 系统A在所有请求全部失败的情况下,如何回滚子系统B可能已经产生的数据。


    image.png

四 解决方案


  如果系统在调用过程中一切正常,无论在任何节点,任何一段程序代码都不会出现问题,我们就不用考虑了。然而实际的情况是,系统有可能会在各种节点产生不一样的问题,虽然出现问题的概率比较小,但也需要我们准备好相应的解决方案来处理。
  由于之前我们已分析出问题可能出现的位置,所以下面来说明一下针对这些问题的解决办法。
  理论上,我们是可以将这两个事务做成分布式事务的,目前对于不要求强一致性的业务,比较流行的做法是将分布式事务,拆解为异步消息通知方式,通过消息队列处理任务,做到最终一致性。但由于我们的业务系统中的业务流程是同步的,而非异步的,而且库存计算结果是要求比较强的一致性和低延迟的效果,所以不能完全使用这个方法。如果使用分布式事务(深坑),又会增加复杂度和维护成本,所以这里也不建议采用分布式事务。
  综合考虑,我们的方案是:RPC重连机制+构造幂等接口+事务补偿机制

1 PRC 重连机制

  在各系统中通过maven引用的框架包中,关于RPC调用默认采用的是Hession,包中已经帮我们封装好了超时及重试。超时是在配置中心配置,如下图所示:


image.png

重试,则是通过传递自定义参数来进行的,如下代码所示:

 //自定义参数方式
RemoteClientContextVO vo = new RemoteClientContextVO();
    vo.setRepeatCount(5);
    vo.setRemoteType(RemoteType.HESSIAN);
    vo.setUrl("http://localhost:8096/carinventory");
    remoteClient = RemoteClientFactory.getInstance(vo);     

上面代码中repeatCount属性即为重试次数。重试的原理,如下图:
image.png

2幂等接口构造

  有关API的幂等性,简单说,就是对同一接口,调用多次和调用一次的情况一样。举例说明:对于ordercollect表的insert操作,如果第一次请求子系统B执行成功但返回异常,那么系统A将发起重试请求,这时子系统B,不会再进行数据库的insert操作,而是直接返回上一次的执行结果。
  具体做法是:我们将请求参加中,多加一个requestid参数,这个参数可以是uuid,即一次请求的唯一标识。每次请求都会带着这个requestid来进行请求。在子系统B中,我们用redis来存储requestid以及相对应的返回值,结构如下:<uuid,返回结果对象>,这样在每次请求的时候,都会先查询redis有没有与requestid相匹配的键值,如果有,直接返回,如果没有再进行程序流程。Redis由于我们具有主备,可以不用担心单点问题,redis中的数据,会定时进行一次清理(可能每天)。

3事务补偿机制

  此处我们来解决问题分析中的第二个问题,即系统A如何回滚子系统B的数据。由于数据库的DML中我们只关心insert、update和delete,所以解决方案也是围绕这些操作设计的。
拿orderCollect表来举例。

  • 我们在orderCollect表中建议一个requestid字段,用来存储请求标识。
  • 在系统A端加入消息队列,当系统A请求子系统B异常时,往消息队列中发一条消息,意为告知子系统B异步处理异常,即回滚异常数据。消息内容比较简单,即requestid+请求类型(insert,upate)。
  • 子系统B通过消息队列异步得到消息时,根据requestid去ordercollect表中查询字段requestid符合当前请求值的数据记录。
  • 根据请求类型(由于orercollect表没有物理删除操作,所以目前只考虑insert和update两种情况),对相应的数据进行回滚处理。
    --1) 如是insert,则删除相应的数据
    --2) 如是update,相对复杂些。首先,我们在子系统B每一次执行update操作的时候都会将数据copy一份存在一张表中。当消息过来要求回滚时,我们将原数据库表和copy数据表进行连表更新,即将copy的原数据覆盖回原表。Sql语句类似这样:


    image.png

综上所述,事务补偿这部分如下所示:


image.png
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 159,569评论 4 363
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,499评论 1 294
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 109,271评论 0 244
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,087评论 0 209
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,474评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,670评论 1 222
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,911评论 2 313
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,636评论 0 202
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,397评论 1 246
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,607评论 2 246
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,093评论 1 261
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,418评论 2 254
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,074评论 3 237
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,092评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,865评论 0 196
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,726评论 2 276
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,627评论 2 270

推荐阅读更多精彩内容