李伟山

读完需要

12

分钟

速读仅需 4 分钟

李伟山,目前是一家人工智能公司的技术总监,主要负责 AI 产品化的工作,开发设计中国一款云同步社交平台——号簿管家;曾参与设计开发亿万级流量的阿里虚拟业务平台——话费充值、网游联运平台。

标志着 iPhone 新纪元开始的 iPhone12 今天正式发布了,不出意料的话,又会掀起抢购热潮,对各大电商网站也是一次考验,技术人更想要深度了解电商订单系统的架构知识,今天带来李伟山老师的电商中的订单系统架构,关于双十一大促,中生代也会推出系列架构文章解析

电商系统之订单系统

1

概述

订单系统作为电商系统的“纽带”贯穿了整个电商系统的关键流程。其他模块都是围绕订单系统进行构建的。订单系统的演变也是随着电商平台的业务变化而逐渐演变进化着,接下来就和大家一起来解析电商平台的“生命纽带”。

订单系统的作用是:管理订单类型、订单状态,收集关于商品、优惠、用户、收货信息、支付信息等一系列的订单实时数据,进行库存更新、订单下发等一系列动作。订单系统业务的基本模型涉及用户、商品(库存)、订单、付款,订单基本流程是下订单——>减库存,这两步必须同时完成,不能下了订单不减库存(超卖),或者减了库存没有生成订单(少卖)。超卖商家库存不足,消费者下了单买不到东西,体验不好;少卖商家库存积压或者需要反复修改商品信息,反复麻烦,体验也不好。

2

订单基本概念

设计订单系统时包含几个大的方向需要考虑,这些内容决定了订单系统的稳定性和可持续性。

订单的多样性特点

主要由来源和操作的多样导致了订单多样性点。

订单字段

订单字段包含了订单中需要记录的信息,他的作用主要用于沟通其他系统,为下游系统提供信息依据。

  • 订单信息订单号作为订单识别的标识,一般按照某种特定规则生成,根据订单的增加进行自增,同时在设计订单号的时候考虑订单无序设置(防止竞争者或者第三方来估算订单量)。订单号后续用作订单唯一标示用于对接 WMS(仓存管理系统)和 TMS(运输管理系统)时的订单识别。

  • 订单状态订单状态在下面章节会详细描述

  • 用户信息指买家的相关信息,包括名称、地址、手机号。O2O 还会多一种情况就是自提点,这样地址则会变为自提点的地址。地址信息在后续会作用在 WMS 和 TMS 上用于区分区域和配送安排。

  • 商品信息商品的基本信息和库存,金额由于比较特殊所以我把金额独立在商品信息以外说,不过逻辑上其实都属于商品信息范畴。商品信息主要影响库存更新和 WMS 产生。

  • 金额信息订单产生的商品信息,这里面除了要记录最终的金额,过程金额也需要记录。比如商品分摊的优惠金额、支付金额,应付金额等。在后续的订单结算、退换货、财务等环节都需要使用。

  • 时间信息记录订单每个状态节点的触发时间。

3

订单流程

订单流程是指整个订单从产生到完成整个流转过程,包括了正向和逆向流程的过程。

正向流程

这里面主要是涉及主流电商系统中的通用订单流程,部分细节可以根据自己平台的特殊性进行调整。

需要注意的地方

  1. 订单生成环节存在超时未支付自动取消的过程,库存的占用会在订单取消后释放。

  2. 如果选择 COD(货到付款)则支付环节相应转移到订单配送之后,而过程中所有与款项相关的逻辑变为只操作金额数字,不对结算和账户进行打退款操作。

  3. 金额分摊需要到商品

  4. 订单系统审核主要对恶意用户或者刷单情况进行处理。系统可根据白名单、黑名单、消费频次、促销品购买量方面做风控规则。如果后续会进入到人工审核,则规则上可以适当从宽。当触发规则需要进行订单退订的行为。此处设计时要小心对用户体验的损害,往往前台文案上说明当前节点是审核状态或者是等待接单。

  5. 传统电商则是通过关联第三方物流的物流信息进行跟踪。

  6. 预售等货和移仓需要做成 SOA 服务,以便在交易页面计算预计时间和预计到货时间。移仓处理依赖仓库的情况,也会涉及到后续拆分和合并包裹的逻辑。

  7. 订单产生时先要判断报缺情况,如果出现报缺问题则要考虑整单报缺、部分报缺、换货或者换转退的情况(库存,仓促调拨和退款)。报缺情况分为系统报缺和实物报缺,这是承接但相对独立的两个环节。

  8. 电商系统要考虑 7 天无理由退货的情景,即订单状态完成后申请退货。此时主要涉及的是金额上的计算以及一些财务程序(如发票等)问题的处理。

逆向流程

逆向流程指订单发生取消、退货等情况时引发的订单流程过程。触发逆向流程的触发主要有几种情况:

  • 用户自主取消订单(整单)

  • 风控系统触发取消订单(整单)

  • 客服接到客诉仲裁后触发取消订单(整单)

  • 超时未支付取消订单(整单)

  • 换货报缺转为退单(整单、部分报缺)

关注点

  • 订单状态(某一节点后如订单产生后不允许取消订单)

  • 当退单被商家拒绝后需要转入客服仲裁的环节

  • 部分退的订单促销一般保持享用状态,但金额按照分摊的金额进行退款

订单状态

从订单状态设计目的和存在价值去分析和理解它背后设计机制:维度及维度颗粒度大小。

1. 正向和逆向流程维度

  • 正向订单:已锁定、已确认、已付款、已发货、已结算、已完成、已取消等

  • 正向预售订单:预付款已付未确认、已确认未付尾款(变更)

  • 正向问题单:未确认、未锁定、未发货、部分付款、未付款等

  • 逆向退单:待结算、未收到货、未入库、质检不通过、部分收货、已取消、客户已收货等

  • 逆向换单:完成、已结算、客服已收货等

2.服务对象维度

  • 顾客/用户:待付款、待发货、待收货、待评价、买家已付款、交易成功/失败、卖家已发货、退款成功、交易关闭。

  • ERP 等其他交互系统:已锁定、已确认、已分仓、已分配、已出库、已收货、已完成等

  • 等待买家付款、待付款和待发货订单、退款中的订单、定金已付、买家已付款、

  • 卖家已发货、交易成功、交易失败、异常订单

订单推送

当状态发生变化时,需要将对应的变化情况告知给相关人员以便了解当前订单的情况,这就是订单推送的作用。订单推送的触发依赖于状态机的变化,涉及到的信息包括

  • 推送对象(用户、物流人员、商家)

  • 推送方式(push、短信、微信)

  • 推送节点(状态改变)

4

订单系统设计的挑战和实践

4.1

订单系统需求演变

第一步:实现购买流程

  1. 实现订单的创建、发货、确认等信息闭环

  2. 支持订单审核(初期可支持人工审核即可)

  3. 支持用户端显示订单相关信息

  4. 支持促销金额的计算

第二步:提供服务

  1. 提供订单分布式服务

  2. 支持跨平台交易单生成(即同一个大交易单内既有商家商品又有自营商品或者是多个商家的商品)

  3. 支持拆单、合并逻辑(配送单、支付单等)

  4. 提供更丰富的订单推送服务,完善订单状态

第三步:支持不同营销手段下的订单类型平台发展到足够大的规模,提效、稳定变成一个重要的话题。可以提供不同营销场景下的订单,如:团购、预购等。

4.2

订单系统架构的演变

第一代:简单粗暴

第一代的问题第一代系统由于,订单状态是在特定的服务器进行处理,如果服务一旦出现问题就会造成订单的丢失,导致订单流程无法进行下去。总结:

  1. 服务单点

  2. 数据库单点

第二代:无状态异步驱动

第二代系统对于第一代有了很好的提升,应用服务器不再保留订单状态,但是这样的系统设计同时也给数据库服务器造成了高频查询带来的压力,导致数据库相对比较脆弱。总结:状态扫描带来的负载

第三代:队列模式

第三代是对于第二代的升级,订单的状态流转不再依靠高频查询数据库来获得,通过队列模式,很好减轻了数据库的压力,但是第三代依然有问题,就是该系统中 server2 成了核心,该模块的维护就会变得很复杂,这也是架构设计的关键,没有完全的完美架构,只能得到一个平衡架构。

4.3

三代系统演变中的最佳实践

实践 1: 重试和补偿

  • 多个机器重试不能同步, 需要随机跳跃(Jitter)和指数回退 (exponential back-off)

  • 正在重试的服务也可能宕机,需要保存状态 (State)

实践 2: 幂等性

  • 你没收到响应不见得失败了

  • 你响应了不见得别人以为你成功了

  • 重试必需带上唯一的有意义的 ID

  • 每一个服务的调用都必须是幂等的

  • 非只读的服务必须保存状态

实践 3: 一致性实践

  • 订单系统有强一致性需求

  • 无单点故障的分布式系统的一致性是非常困难的问题

  • 已有算法:Paxos,现有开源系统(e.g. Zookeeper)

  • 有时候单点故障并不可怕,常用的,成熟的关系数据库方案也是一个不错的选择

  • 云端分布式无单点故障的系统

实践 4: 工作流 (Workflow)

  • 可扩展性:无状态的 Worker,分布式部署,分布式存储 工作流状态

  • 可靠性:定时器、重试、幂等性、强一致性的状态

  • 可维护性:工作流的描述和执行 Activity 描述相分离, 支持异步触发支持版本和升级

4.4

系统优化

数据库读写分离基本的原理是让主数据库处理事务性查询,而从数据库处理 SELECT 查询。数据库复制被用来把事务性查询导致的变更同步到集群中的从数据库。当然,主服务器也可以提供查询服务。使用读写分离最大的作用无非是环境服务器压力。

好处

  1. 增加冗余

  2. 增加了机器的处理能力

  3. 对于读操作为主的应用,使用读写分离是最好的场景,因为可以确保写的服务器压力更小,而读又可以接受点时间上的延迟。

读写分离提高性能之原因

  1. 物理服务器增加,负荷增加

  2. 主从只负责各自的写和读,极大程度的缓解 X 锁和 S 锁争用

  3. 从库可配置 myisam 引擎,提升查询性能以及节约系统开销

  4. 从库同步主库的数据和主库直接写还是有区别的,通过主库发送来的 binlog 恢复数据,但是,最重要区别在于主库向从库发送 binlog 是异步的,从库恢复数据也是异步的

  5. 读写分离适用于读远大于写的场景,如果只有一台服务器,当 select 很多时,update 和 delete 会被这些 select 访问中的数据堵塞,等待 select 结束,并发性能不高。对于写和读比例相近的应用,应该部署双主相互复制

  6. 可以在从库启动时增加一些参数来提高其读的性能,例如--skip-innodb、--skip-bdb、--low-priority-updates 以及--delay-key-write=ALL。当然这些设置也是需要根据具体业务需求来定的,不一定能用上

  7. 分摊读取。假如我们有 1 主 3 从,不考虑上述 1 中提到的从库单方面设置,假设现在 1 分钟内有 10 条写入,150 条读取。那么,1 主 3 从相当于共计 40 条写入,而读取总数没变,因此平均下来每台服务器承担了 10 条写入和 50 条读取(主库不承担读取操作)。因此,虽然写入没变,但是读取大大分摊了,提高了系统性能。另外,当读取被分摊后,又间接提高了写入的性能。所以,总体性能提高了,说白了就是拿机器和带宽换性能。

  8. MySQL 复制另外一大功能是增加冗余,提高可用性,当一台数据库服务器宕机后能通过调整另外一台从库来以最快的速度恢复服务,因此不能光看性能,也就是说 1 主 1 从也是可以的。

4.5

实现方案

数据库分库分表

不管是采用何种分库分表框架或者平台,其核心的思路都是将原本保存在单表中太大的数据进行拆分,将这些数据分散保存到多个数据库的多个表中,避免因为单表数据量太大给数据的访问带来读写性能的问题。所以在分库分表场景下,最重要的一个原则就是被拆分的数据尽可能的平均拆分到后端的数据库中,如果拆分的不均匀,还会产生数据访问热点,同样存在热点数据因为增长过快而又面临数据单表数据量过大的问题。

而对于数据以什么样的纬度进行拆分,大家看到很多场景中都是对业务数据的 ID(大部分场景此 ID 是以自增长的方式)进行 HASH 取模的方式将数据进行平均拆分,这个简单的方式确实在很多场景下都是非常合适的拆分方法,但并不是在所有的场景中这样拆分的方式都是最优的选择。也就是说数据如何拆分并没有所谓的金科玉律,更多的是需要结合业务数据的结构和业务场景来决定。

下面以大家最熟悉的电商订单数据拆分为例,订单是任何一个电商平台都有的业务数据,每个平台用户提交订单都会在平台后端生成订单相关的数据,一般记录一条订单数据的数据库表结构如下:

订单数据主要由三张数据库表组成,主订单表对应的就是用户的一个订单,每提交一次都会生成一条主订单表的数据。在有些情况下,用户可能在一个订单中选择不同卖家的商品,而每个卖家又会按照该订单中自己提供的商品计算相关的商品优惠(如满 100 元减 10 元)以及按照不同的收货地址设置不同的物流配送,所以会出现子订单的相关概念,即一个主订单会由多个子订单组成,而真正对应到具体每个商品订单信息,则保存在订单详情表中。

如果一个电商平台的业务发展健康的话,订单数据是比较容易出现因为单个数据库表中的数据量过大而造成性能的瓶颈,所以需要对他进行数据库的拆分。此时从理论上对订单拆分是可以由两个纬度进行的,一个纬度是通过订单 ID(一般为自增长 ID)取模的方式,即以订单 ID 为分库分表键;一个是通过买家用户 ID 的纬度进行哈希取模,即以买家用户 ID 为分库分表键。两种方案做一下对比:1、如果是按照订单 ID 取模的方式,比如按 1024 取模,则可以保证主订单以及相关子订单,订单详情数据平均落入到后端 1024 个数据库表中,原则上很好地满足了数据尽可能平均拆分的原则。

2、通过采用买家 ID 取模的方式,比如也是按照 1024 取模,技术上则也能保证订单数据拆分到后端的 1024 个数据库表中,但这里就会出现一个业务场景中带来的问题,就是如果有些卖家是交易量非常大的,那这些卖家的订单数据量(特别是订单详情表的数据量)会比其他卖家要多处不少,也就是会出现数据不平均的现象,最终导致这些卖家的订单数据所在的数据库会相对其他数据库提前进入数据归档(为避免在线交易数据库的数据的增大带来数据库性能的问题,一般将 3 个月内的订单数据保存在线交易数据库中,超过 3 个月的订单会归档后端专门的归档数据库)。所以从对『数据尽可能平均拆分』这条原则来看,按照订单 ID 取模的方式看起来更能保证订单数据的平均拆分,但我们暂时不要这么快下结论,也要根据不同的业务场景和最佳实践角度多思考不同纬度带来的优缺点。

5

总结

电商平台的需求一直在变化,随之订单系统的架构也会随之变化,架构设计就是一个持续改进的过程,这篇文章还有好多细节未提及,如果你想把订单系统做的更好,需要更加深入系统的每一个环节,比如:容灾、灾备、分流、流控都需要慢慢雕琢,在架构中没有完美的架构只有平衡的架构,不要追求单点的完美,而是要追求多点的平衡

- EOF -

想要加入中生代架构群的小伙伴,请添加群合伙人大白的微信

申请备注(姓名+公司+技术方向)才能通过哦!

扩展阅读

DDD专家张逸:构建领域驱动设计知识体系

京东架构师闫文广:订单系统高可用架构及演变过程

阿里高级技术专家张建飞:面对复杂业务,if-else coder 如何升级? 2020-09-30

   END
#架构师必备#

点分享点点赞点在看

架构专家李伟山:电商系统之订单系统相关推荐

  1. 电商项目中订单系统到底该怎么设计才好?(至尊典藏版)

    目录 前言 一.订单系统架构 1. 订单系统在企业中的角色 2. 订单系统与各业务系统的关系 3. 订单系统上下游关系​编辑 4. 订单系统的业务架构​编辑 二.订单系统核心功能 1. 订单中所包含的 ...

  2. 一线电商公司的订单系统是如何进行数据库设计的?

    一般互联网公司的订单系统是如何做分库分表的,既然要聊订单系统的分库分表,那么就得先说说为什么订单需要分库分表,其实最关键的一点就是要分析一下订单系统的数据量,那么订单系统的数据量有多大?这个就得看具体 ...

  3. (九十八)大白话一线电商公司的订单系统是如何进行数据库设计的?

    今天我们来给大家讲讲第二个案例拓展,也就是一般互联网公司的订单系统是如何做分库分表的,既然要聊订单系统的分库分表,那么就得先说说为什么订单需要分库分表,其实最关键的一点就是要分析一下订单系统的数据量, ...

  4. 010_电商实时交易风控系统_第5天(行业知识、需求分析、架构设计、代码开发) ---没用...

    1.课程名称 电商实时交易风控系统 2.课程目标 1.了解电子商务交易的风险点 2.了解电子商务交易中风险点的处理策略 3.利用Storm技术开发基于规则判定的风控系统 4.掌握企业中风控系统的一般架 ...

  5. Java生鲜电商平台-深入订单拆单架构与实战

    Java生鲜电商平台-深入订单拆单架构与实战 Java生鲜电商中在做拆单的需求,细思极恐,思考越深入,就会发现里面涉及的东西越来越多,要想做好订单拆单的功能,还是相当有难度, 因此总结了一下拆单功能细 ...

  6. 系统设计题:如何设计一个电商平台积分兑换系统!

    本文来自公众号:狸猫技术窝 作者:原子弹大侠,阿里高级技术专家 1.拉开差距的一类面试题 现在面试经常会遇到一类问题,面试官让你现场设计出某个业务场景下的一个系统,这个系统往往在业务或者技术上有一定难 ...

  7. 电商实时交易风控系统

    1.课程名称 电商实时交易风控系统 2.课程目标 1.了解电子商务交易的风险点 2.了解电子商务交易中风险点的处理策略 3.利用Storm技术开发基于规则判定的风控系统 4.掌握企业中风控系统的一般架 ...

  8. java毕业设计电商后台管理系统Mybatis+系统+数据库+调试部署

    java毕业设计电商后台管理系统Mybatis+系统+数据库+调试部署 java毕业设计电商后台管理系统Mybatis+系统+数据库+调试部署 本源码技术栈: 项目架构:B/S架构 开发语言:Java ...

  9. java计算机毕业设计跨境电商网站源代码+数据库+系统+lw文档

    java计算机毕业设计跨境电商网站源代码+数据库+系统+lw文档 java计算机毕业设计跨境电商网站源代码+数据库+系统+lw文档 本源码技术栈: 项目架构:B/S架构 开发语言:Java语言 开发软 ...

最新文章

  1. 谈谈Linux打补丁的原理以及如何判别打补丁的错误 --- 从补丁学内核
  2. mysql 触发器 插入或者更新_MySQL 在触发器里中断记录的插入或更新?
  3. 如何判断应用已经安装,如何判断Service,BroastCastReceiver,ContentProvider是否存在...
  4. 02:输出最高分数的学生姓名
  5. 在 PostgreSQL 中使用码农很忙 IP 地址数据库
  6. hibernate脏数据_Hibernate脏检查的剖析
  7. 一文重新认识联邦学习
  8. jquery截取字符串中的数字
  9. 制作自己的特色PE----Mr.Zhang
  10. 当我的master被fork后,我把master删了,然后我就成了他人的bitch
  11. android开发比例图表,Android开发中如何使用绘制图表
  12. 揭露微信朋友圈当中出现刷票群0.01一票微信号、刷票0.01一票微信号的虚假面目
  13. 集成海康威视Sadp SDK实现修改设备网络参数
  14. 亲爱的,别把上帝缩小了 ---- 读书笔记1
  15. 计算机专业拜年语,适合拜年发的朋友圈祝福语:过年拜年的说说
  16. redis探索之常用的三种缓存读写策略
  17. linux双线路由,双线机房双IP linux设置路由
  18. Mysql 快速生成日期时间维度表
  19. 20210505 秀米导入已发布微信推送的所有内容
  20. python虽然火为什么工作少_学Python开发干什么工作 人工智能方面的吗

热门文章

  1. 学妹哭着问我:测试工程师应掌握什么?不知道自己是否适合做这个?
  2. 人生中重要抉择:读研还是工作?
  3. 可以手机安装电脑版chrome插件的安卓浏览器
  4. linux 截取某一段时间的日志,存储到另一个文件中
  5. 微信web开发者工具、网易云音乐、为知笔记等软件崩溃无法打开等问题的解决
  6. 微软的exchange服务器和域怎么填,配置远程域属性: Exchange 2010 帮助 | Microsoft Docs...
  7. STM32CubeMX学习笔记(24)——通用定时器接口使用(电容按键检测)
  8. 阶段三-02 用例之间上下文传递
  9. 浅谈AI绘图工具Midjourney
  10. 解绑数字身份,解锁新玩法与构建方式(下)