订单与交易的设计原则

标签: | 发表时间:2020-10-26 20:04 | 作者:
出处:https://m.weibo.cn
[cp]一,订单与交易的设计原则,可以写在设计文档的前面,作为总纲

设计原则一:历史可追溯、可还原、有快照!

互联网核心服务很容易产生数据不一致,一旦出现数据不一致,一定要有旁证来修正,这个旁证尽量不要是文件日志,而应该是数据库直观的数据,否则会累煞人、愁白头。
数据库中关键记录的关键字段,原则上不允许直接修改历史数据。这里的“直接修改”指的是,没有把变更行为记录到操作日志表里,而是直接在原始记录上 update 甚至 delete,这种“毁尸灭迹”是明文禁止的,即使留下了文件日志也是不允许的。

对此注意两点:
第一,修改关键记录的关键字段时,必须在操作日志表里保留变更日志(old value和new value),并记录发起人、操作人和发起系统,一定要确保历史可回溯、可还原、有快照。
第二,严禁对关键记录做物理删除,只能是软删除。

商品中心、订单中心、库存中心等中心服务要记录清楚商品核心属性、订单核心属性、库存的每一次变更,强调记录“过程”,而不是仅仅在“结果”上Update(即覆盖)。
比如说每一次库存增减、盘点(盘盈盘亏)等变更,在哪一个系统发起的,哪一个操作员发起的,因为什么原因变更(有变更类型),从什么变成了什么。这样记录下来之后,如果从某一天上线之后引入了BUG,就能够追溯所有变更,并能够彻底地还原数据。
比如说对于记录了订单信息的 order_info 表,会员如果点击使用账户余额支付了订单的应付金额,那么该订单操作日志表就会做如下记录,原订单记录的重要字段(what)由谁(who)因为什么(why)在什么时候(when)从什么变为了什么(how),都会详细记录。
 
设计原则二:接口从一开始就要做幂等性和防并发(这俩本质上是一回事)!

特别说明:所有与支付交易相关的订单,都必须有一个全局唯一的clientOrderID(或者叫客户端流水号),作为客户端提交时的幂等性依据。
为什么特别写这个说明,因为我们有兄弟公司的重复扣款事故,短短几个月内已经连续三次了,就是因为他们没有设计客户端流水号,无法利用客户端流水号在服务端、或者在定时任务里阻止重复提交或重复扣款:
a)   某日,扫脸后,收银员“手抖”致“双击”确认按钮(在弹出对话框之前),导致重复扣款;
b)   离线支付又出现重复交易;
c)   某日系统定时自动补扣时,补扣慢,现场运营人员担心用户欠费影响就餐,所以在商家中心后台点击了手动补扣,导致重复扣费;
三次重复扣款分别在三个业务逻辑上,其实背后是一个毛病。
 
设计原则三:要求必须建立校验订单交易数据一致性的定时任务,做数据补偿!
进一步说明:以数据库操作日志为依据,校验单个订单、交易的各项数据是否一致,如果发现不一致,第一要告警,第二尽量自动修复,比如说原路退返。
 
设计原则四:凡是收银系统最终肯定是要接入异地双活体系的,这是躲不过去的,因为单机房是不可靠的!

由于我司有异地双活机制,所以与订单操作、资金账户划转、券操作等敏感操作的设计都需要提前考虑双活,免得回头还要推倒重做。
比如说订单号、券号、卡号等序列号的生成规则里,都应该有机房ID,能看出来这个订单是在哪一个机房生成的。
举例:我们某团队利用Twitter SnowFlake算法生成如下规则的订单号:
25位 = 时间戳(13位)+机房ID(2位)+容器ID/IP(5位)+线程号(2位)+序列号(3位)
另一个团队的订单号规则为:
起始位固定2(1位)+日期(6位)+根据商户ID获取hashRoute(2位)+步长(7位)+机房ID(1位)
再比如说事先划定“多活表”(如订单表和退款表)、“非多活表”(如队列表)和全局表(如支付配置表)。
 
设计原则五:数据库设计和变更必须提前与DBA沟通!

大表(如订单表)上预留足够多(如10个)扩展字段,后期复用时改字段名即可,不影响业务,无需停服。
大表真的被迫加字段的话,请提前一天加好,不要与上线动作绑在一起。
大表加字段,选择凌晨执行,因为以5G的数据量为例可能耗时10分钟左右,对业务有致命影响。
异地双活里,对于双活数据库而言,有主机房概念,如果先在主机房的双活数据库上做表结构变更,会导致otter同步中断,所以请先变更从机房的双活数据库的表结构,然后再变更主机房的。
 
二,回顾订单与交易上容易发生的错误
经典错误一:高并发高性能的竞争环境,设计方案完全不同,大家一定要画时序图,而不是流程图。

分布式系统最常见的就是未能做到防重复提交和防并发提交。这是传统软件开发者转入互联网开发时最容易犯的错误。
所以做系统设计时,最好画业务时序图。
通过时序图的辅助,以及同事的设计评审,能帮助你想清楚你的业务依托哪些点上的原子级操作来阻止重复提交和并发提交。
 
经典错误二:主从延迟问题,是传统软件开发者转入互联网开发时最容易犯的第二个错误。

进一步说明:当读写分离成为常态时,低估了数据库主从延迟对代码的影响。
开发者特别容易进入如下陷阱:
代码A向主库写入一条记录,立即通知代码B;
代码B去从库查询,由于主从延迟(比如大于半秒),没查到记录;
于是代码B报错。
 
经典错误三:不了解线程安全
举两个RCA报告的例子来说明这一点:
《RCA:转换日期格式线程不安全导致支付时间错误》:SimpleDateFormat 类的 java doc 中明确指明该类非线程安全,多线程情况下需要同步处理或者每个线程创建一个实例。
《RCA:TaskMall线程不安全致死循环》:HashMap 是线程不安全的,如果多个线程对 HashMap 做 put 和遍历操作,就有可能出现 HashMap 中的 Entry 实例的 next=它自身,导致死循环,cpu 空转。
 
经典错误四:先删除旧值,再插入新值
进一步说明:刚删了旧值,服务就宕机了,导致新值也没插入。
大家可能会觉得这是废话,但总是有先删后插的程序员。
举例:当年商品手动排序页面交互中,
——当点击“提交排序”时,先把旧排序序位删掉,再把提交的新排序序位存入;
——当程序有BUG时,旧排序序位删掉了,但接下来程序爆出异常而中断,导致新排序未存入。
……

三,(再次重复)设计之前请先把大的设计原则写下来

每一位设计师都需要知道这个常识:
    当你开始构建或重构一个复杂系统的时候,请先把大的设计原则写下来,然后在这些设计原则的框架内做推演。
而不是这种常见的工作方式:
    根据需求分析,天马行空,想到哪儿是哪儿,给出一个设计方案,自己做一番推演之后,自我感觉良好。
阿里巴巴资深技术专家毕玄这样总结自己的系统设计方法:
    回顾了下自己做过的几个系统的设计,发现在自己在做系统设计的时候确实是会按照一个套路去做,这个套路就是:
    系统设计的目的->系统设计的目标->围绕目标的核心设计->围绕核心设计形成的设计原则->各子系统、模块的详细设计。

之前我写过《技术人间自有法则在》,不妨对照着看看,再想想你的设计有没有遵循什么原则、什么法则,有没有脚踩西瓜皮滑到哪里算哪里?[/cp]

相关 [交易 设计 原则] 推荐:

订单与交易的设计原则

- -
[cp]一,订单与交易的设计原则,可以写在设计文档的前面,作为总纲. 设计原则一:历史可追溯、可还原、有快照. 互联网核心服务很容易产生数据不一致,一旦出现数据不一致,一定要有旁证来修正,这个旁证尽量不要是文件日志,而应该是数据库直观的数据,否则会累煞人、愁白头. 数据库中关键记录的关键字段,原则上不允许直接修改历史数据.

Android设计原则

- - 所有文章 - UCD大社区
译者按: 在 iOS HIG已经强大经典了N年之后,Android终于推出了一套比较系统的 HIG(大概是为了配合Android 4.0 Ice Cream Sandwich). 仔细比较两套HIG的“设计原则”部分,发现完全是截然不同的两种风格. iOS HIG走的是更专业型的路线,描述严谨且有不少的专业词汇(比如Metaphors、Consistency之类的).

设计指导原则

- - 企业架构 - ITeye博客
避免在循环内部new一些没有必要每次都new的对象. 所有与IO相关的操作,都需要考虑性能问题,一般采取的措施是连接池,缓存,减少调用次数,合并请求. 每个业务都要分析整个请求链路,找到瓶颈,通过压测的方式确认问题及验证解决方案. 根据业务情况,使用异步化和最终一致性. CPU,内存,网络IO,磁盘IO这些瓶颈,需要知道在合适的场景牺牲什么换取什么.

MySql 之表设计原则

- - 互联网 - ITeye博客
1) 不应该针对整个系统进行数据库设计,而应该根据系统架构中的组件划分,针对每个组件所处理的业务进行组件单元的数据库设计;不同组件间所对应的数据库表之 间的关联应尽可能减少,如果不同组件间的表需要外键关联也尽量不要创建外键关联,而只是记录关联表的一个主键,确保组件对应的表之间的独立性,为系统或表 结构的重构提供可能性.

设计模式和设计原则

- - 编程 - 编程语言 - ITeye博客
26.1  设计模式和设计原则. 26.1.1  设计模式和设计原则的关系. 面向对象的分析设计有很多原则,这些原则大都从思想层面,给我们指出了面向对象分析设计的正确方向,是我们进行面向对象分析设计应该尽力遵守的准则.        而设计模式已经是针对某个场景下某些问题的某个解决方案. 也就是说这些设计原则是思想上的指导,而设计模式是实现上的手段,因此设计模式也是应该遵守这些原则的,换句话说,设计模式就是这些设计原则的一些具体体现.

大师们认为最重要的交易原则

- - 厚德载福
    冠军交易员,起初交易的十年,经常亏损,长期处于濒临破产的边缘,1979年之后成为一个顶尖的交易员. 他一共参加过10次的全美投资大赛中的四个月期交易竞赛项目,获得9次冠军,平均投资回报率为210%,他赚到的钱几乎是其他参赛者的总和.     他认为最重要的交易原则就是资金管理.     假如我错了,我得赶紧脱身,有道是留得青山在,不怕没柴烧.

一些软件设计的原则

- 夕角 - 酷壳 - CoolShell.cn
以前本站向大家介绍过一些软件开发的原则,比如优质代码的十诫和Unix传奇(下篇)中所以说的UNIX的设计原则. 相信大家从中能够从中学了解到一些设计原理方面的知识,正如我在《再谈“我是怎么招聘程序”》中所说的,一个好的程序员通常由其操作技能、知识水平,经验层力和能力四个方面组成. 在这里想和大家说说设计中的一些原则,我认为这些东西属于长期经验总结出来的知识.

web交互设计原则和模式

- shallwelin - 译言-
原文作者:Bill Scott. 原文链接:Designing Web Interfaces Principles and Patterns for Rich Interaction. web界面设计(丰富交互设计的原则和模式). (本书英文版大家可以到我blog下载:http://blog.youmila.com/?p=325).

分层架构设计原则

- - 博客园_首页
通常一个软件系统都包含不同部分互相交互耦合,我们希望设计能够将系统划分为有意义的各个部件,各个部件能够独立的开发、演进、部署. 这时整体性的设计已经无法满足这些挑战,这就需要我们对系统进行合理清晰的划分. 通常我们为待开发的系统定义多个层次,每一层完成独立的功能. 1:系统分为多层,每层完成独立的功能,层内部继续细分子模块,每层能够独立演进、部署.