免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
查看: 2396 | 回复: 5

[其他] 关于数据库设计种遇到的分布式事务的设计经验 [复制链接]

论坛徽章:
4
水瓶座
日期:2013-09-06 12:27:30摩羯座
日期:2013-09-28 14:07:46处女座
日期:2013-10-24 14:25:01酉鸡
日期:2014-04-07 11:54:15
发表于 2015-04-28 15:16 |显示全部楼层
设计一个分布式数据库总是会遇到这种问题,也就是进行了分表设计,同时希望保证多维度的一致性。

例如做一个订单系统,包含2个维度:

1,用户维度:用户向特定商家下单,查看自己的所有订单。(uid分表)
2,商家维度:查看自己收到的订单,确认用户的订单。(bid分表)

典型操作1:用户下单。
      流程:生成order id(oid),根据uid写入用户订单表,根据bid写入商家订单表。  
      初衷:向2个维度都写入同样的数据,在分布式数据库设计下保证用户维度和商家维度都可以高效的完成订单的查询。
      问题:写用户订单表成功,写商家订单表失败,导致商家无法看到订单,用户空等订单。
      折衷:在用户查看订单的流程中,对商家订单表进行重查,如果记录不存在则重试插入。

典型操作2:商家接单。
      流程:根据bid筛选该商家订单表,选中一个订单(包含uid,oid信息),根据uid更新用户订单表的oid订单状态为已接单,接单商家为bid,最终更新商家订单表中该oid的状态为已接单。
      问题:更新用户订单表成功,更新商家订单表失败,导致用户认为预定成功,而商家查看订单状态没有改变。
      折衷:在商家查看订单的流程中,对用户订单表进行重查,如果订单已被该商家接单,那么更新商家订单表状态。


上面就是举一个典型的场景,对于分布式数据库,没法通过单机事务保障多表修改的一致性,准确的说是没法保障不同维度间的一致性,同一个维度是可以通过相同的分表算法保证可以做到单机事务。在业务场景上,业务可以容忍不一致,有的场景业务没法忍受。

各位大神们对这种问题是否有什么经验可以分享一下,谢谢。

论坛徽章:
275
射手座
日期:2013-08-23 12:04:38射手座
日期:2013-08-23 16:18:12未羊
日期:2013-08-30 14:33:15水瓶座
日期:2013-09-02 16:44:31摩羯座
日期:2013-09-25 09:33:52双子座
日期:2013-09-26 12:21:10金牛座
日期:2013-10-14 09:08:49申猴
日期:2013-10-16 13:09:43子鼠
日期:2013-10-17 23:23:19射手座
日期:2013-10-18 13:00:27金牛座
日期:2013-10-18 15:47:57午马
日期:2013-10-18 21:43:38
发表于 2015-04-28 15:21 |显示全部楼层
分布式事务可以做,但效率低,所以一般避免这种设计

论坛徽章:
43
15-16赛季CBA联赛之四川
日期:2018-10-13 23:26:5015-16赛季CBA联赛之新疆
日期:2016-04-25 10:55:452016科比退役纪念章
日期:2016-04-23 00:51:2315-16赛季CBA联赛之山东
日期:2016-04-17 12:00:2815-16赛季CBA联赛之福建
日期:2016-04-12 15:21:2915-16赛季CBA联赛之辽宁
日期:2016-03-24 21:38:2715-16赛季CBA联赛之福建
日期:2016-03-18 12:13:4015-16赛季CBA联赛之佛山
日期:2016-02-05 00:55:2015-16赛季CBA联赛之佛山
日期:2016-02-04 21:11:36程序设计版块每日发帖之星
日期:2016-07-02 06:20:0015-16赛季CBA联赛之天津
日期:2016-11-02 00:33:1215-16赛季CBA联赛之浙江
日期:2017-01-13 01:31:49
发表于 2015-04-28 15:43 |显示全部楼层
本帖最后由 windoze 于 2015-04-28 15:44 编辑

这实际上是个master/detail表结构,master表是订单,买家卖家是detail表或者说辅助表。一个类似的场景是银行转账,交易流水是master表,帐户表是detail表。
这种结构的分解有很多种做法,一个典型方案是:
1、在订单表里维护所有核心状态,比如订单状态、金额、付款状态等。订单表本身不要显示的join其它表,而且订单之间没有关联,所以可以简单分区。
2、在生成订单时维护一组“回退”的数据,即撤销这一定单所需的操作和数据,这组数据随着订单状态变化需要更新。这组数据可以保存在订单表里,如果业务规则够简单也可以直接从订单数据里临时生成
有了上面两组数据,你就可以放心的更新订单了,反向的关联不是关键事务数据,可以独立更新,比如用户查询自己所有的订单,这一类操作可以通过更新订单状态时附加更新独立的“用户订单”数据来完成,这组数据可以定期重建,以免偶发的数据不一致。
商户端数据可以通过消息队列之类的东西更新,使用持久化的消息队列外加一个超时撤销或重试就可以避免丢失订单,加点dedup逻辑就可以避免重复订单。

总之,你只要降低你的SLA就几乎可以避免所有问题,话说即使你用TPC一样不能保证百分百可靠。

论坛徽章:
4
水瓶座
日期:2013-09-06 12:27:30摩羯座
日期:2013-09-28 14:07:46处女座
日期:2013-10-24 14:25:01酉鸡
日期:2014-04-07 11:54:15
发表于 2015-04-28 15:53 |显示全部楼层
回复 3# windoze


的确, 我理解类似问题是无法避免的, 我认为设计时可以抱着几个核心原则:

1,接口幂等性:简单说一笔钱从一个账户里扣过一次,不能再扣。
2,业务容忍性:技术故障,对业务方不造成或者尽量减少利益损失。
3,自动化回滚:在接口幂等前提下,一些业务可以通过消息队列实现自动回滚。

论坛徽章:
43
15-16赛季CBA联赛之四川
日期:2018-10-13 23:26:5015-16赛季CBA联赛之新疆
日期:2016-04-25 10:55:452016科比退役纪念章
日期:2016-04-23 00:51:2315-16赛季CBA联赛之山东
日期:2016-04-17 12:00:2815-16赛季CBA联赛之福建
日期:2016-04-12 15:21:2915-16赛季CBA联赛之辽宁
日期:2016-03-24 21:38:2715-16赛季CBA联赛之福建
日期:2016-03-18 12:13:4015-16赛季CBA联赛之佛山
日期:2016-02-05 00:55:2015-16赛季CBA联赛之佛山
日期:2016-02-04 21:11:36程序设计版块每日发帖之星
日期:2016-07-02 06:20:0015-16赛季CBA联赛之天津
日期:2016-11-02 00:33:1215-16赛季CBA联赛之浙江
日期:2017-01-13 01:31:49
发表于 2015-04-28 16:05 |显示全部楼层
回复 4# linux_c_py_php

接口不一定总能做到幂等,只要能回滚就行,问题不大。
就算银行也是发现问题就回冲账目的。

论坛徽章:
1
2015年辞旧岁徽章
日期:2015-03-03 16:54:15
发表于 2015-04-28 18:08 |显示全部楼层
银行的分布式事务以分支行为分布边界。
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

SACC2019中国系统架构师大会

【数字转型 架构演进】SACC2019中国系统架构师大会,7折限时优惠重磅来袭!
2019年10月31日~11月2日第11届中国系统架构师大会(SACC2019)将在北京隆重召开。四大主线并行的演讲模式,1个主会场、20个技术专场、超千人参与的会议规模,100+来自互联网、金融、制造业、电商等领域的嘉宾阵容,将为广大参会者提供一场最具价值的技术交流盛会。

限时七折期:2019年8月31日前


----------------------------------------

大会官网>>
  

北京盛拓优讯信息技术有限公司. 版权所有 16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122
中国互联网协会会员  联系我们:huangweiwei@it168.com
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP