订单初版—分布式订单系统的简要设计文档
1.订单系统核心业务流程
这里主要介绍生单和退款两个核心链路:一是订单正向核心链路,二是订单逆向核心链路。
(1)生成订单时序图

(2)支付订单流程图

(3)取消订单流程图

2.Spring Cloud Alibaba 在订单业务中的落地方案
SCA 包含了:Dubbo、Nacos、Sentinel、Seata、RocketMQ 等组件,SCA 技术栈在订单业务中的落地方案包括如下:
(1)基于 Dubbo + Nacos 实现全 RPC 调用链路
(2)基于 Seata 实现正向核心链路数据强一致性
针对生单 -> 优惠券锁定 -> 库存锁定等正向核心链路流程,使用 Seata 的 AT 模式确保涉及分布式事务的正向核心链路的数据强一致性。
(3)基于 RocketMQ 延迟消息取消超时未支付订单
通过 Redisson 分布式锁 + Elastic-Job 实现补偿。
(4)基于 Builder 和 Template 模式构建对象和发通知
基于 Builder 模式实现复杂订单对象的构建、复杂查询规则对象的构建,基于 Template 模式实现物流配送的通知。
(5)基于 Redisson 分布式锁解决并发预支付问题
(6)订单履约强一致解决方案
基于 RocketMQ 的柔性分布式事务解决方案。
(7)订单履约幂等性解决方案
基于 Redisson 分布式锁 + 前置状态检查实现幂等。
(8)基于 Seata 实现逆向核心链路数据强一致性
针对取消订单 -> 取消履约 -> 释放资产等逆向核心链路流程,使用 Seata 的 AT 模式确保涉及分布式事务的逆向核心链路的数据强一致性。
简单介绍完 SCA 在复杂订单业务中的基础技术方案,接下来简单介绍在分布式架构中面向分布式全链路故障而设计的高可靠架构方案。
3.面向分布式全链路故障设计的高可靠架构方案
分布式系统的技术难点,其实就是分布式系统链路长、故障多,如果任何一个环节出了故障就会导致系统出问题。所以要分析全链路里会有哪些问题,要用哪些方案来确保系统运行稳定。
分布式订单系统就采用了如下方案来保证系统稳定:
Dubbo 服务高并发压力生产优化、大促活动网关层限流解决方案、订单集群柔性限流解决方案、订单系统自适应流控解决方案、订单系统核心链路雪崩解决方案、防恶意刷单与黑名单解决方案、库存系统异构存储架构 TCC 分布式事务解决方案、仓储系统老旧代码 Saga 分布式事务解决方案、物流系统多数据库 XA 分布式事务解决方案、Nacos + ZooKeeper 双注册中心高可用方案、Dubbo + Nacos 多机房部署流量 Mesh 管控方案。
(1)订单系统 Dubbo 服务高并发压力优化
首先针对订单系统核心接口逐个进行高并发压测,然后逐步分析 Linux OS、Dubbo 线程池、数据库连接池、数据库索引和 SQL 语句、业务逻辑效率等各个环节存在的问题。并得出在机器负载可控情况下,订单系统可以接受的最大并发压力。
(2)订单系统引入 Spring Cloud Alibaba Sentinel
此时需要将 Sentinel 客户端引入订单系统工程,同时完成 Sentinel Dashboard 的搭建。
(3)大促活动网关层限流解决方案
首先演示在大促场景下,瞬时高并发是如何击垮订单系统的,同时评估出订单集群部署下的最大可抗压力,然后设计网关大促限流方案。可以基于 Spring Cloud Gateway 实现一个订单系统前置网关,对订单系统集群部署做负载均衡 + 部署网关集群。通过在网关引入 Sentinel 来实现限流,在流量入口处保护订单系统不被击垮。
(4)订单系统自适应流控解决方案
首先演示订单系统单实例流量超载的问题。然后根据订单系统部署机器的配置、高压下的机器负载、业务逻辑的复杂度,基于 Sentinel 设计订单系统的自适应流控方案。也就是根据机器负载、响应时间、请求速率,自适应调整机器的流量阈值,从而实现柔性流控效果。最后演示大流量下,流量被网关层限流后穿透到订单层,各个机器上的自适应流控效果。
(5)订单集群柔性限流解决方案
首先针对订单系统各核心接口,评估出集群模式下每个接口的最大负载压力。然后演示出集群模式下的接口,在访问超载时引发的问题。接着基于 Sentinel 设计各个核心接口的柔性限流方案。最后对订单接口进行超压力访问,演示接口级的柔性流控效果。
(6)订单核心链路雪崩场景保护方案
首先演示订单核心链路的服务雪崩场景,单服务崩溃是如何引发服务链路全面崩溃的。接着对订单核心链路的各个服务,基于 Sentinel 设计服务链路防雪崩方案,避免核心链路任何一个服务崩溃引发的服务链路雪崩问题。最后演示单服务崩溃时,整个订单服务的防雪崩效果。
订单核心链路的各个服务有:订单服务、库存服务、营销服务、仓储服务、物流服务、风控服务。
(7)防恶意刷单自动发现与黑名单方案
首先演示单用户恶意刷单行为和效果,接着基于基于 Sentinel 设计自动识别用户恶意刷单的方案,将恶意刷单的用户 ID 自动加入访问控制黑名单。从而实现自动化识别 + 防止恶意刷单 + 黑名单控制的机制。
(8)库存系统异构存储的 TCC 分布式事务解决方案
常见的库存架构是 Redis + 数据库异构存储架构。由于订单系统又会强依赖库存系统,所以库存系统的异构存储架构的分布式事务解决方案,通常是基于 Seata 的 TCC 模式来实现的。
(9)仓储系统老旧代码的 Saga 分布式事务解决方案
由于仓储系统的逻辑通常会非常复杂,而且会包含多个服务协同工作,所以对这类系统做分布式事务改造的难度比较大。仓储系统的多服务链路老旧代码的分布式事务解决方案,通常是基于 Seata 的 Saga 模式来实现的。
(10)物流系统多数据库的 XA 分布式事务解决方案
(11)Nacos+ZooKeeper 双注册中心高可用方案
(12)Dubbo+Nacos 多机房部署流量 Mesh 管控方案
4.分布式订单系统的技术栈与代码规范
(1)订单系统的技术栈

(2)各层方法的命名规范
开发规范基于阿⾥巴巴的《Java 开发⼿册》:
一.总的原则是⽤动词做前缀,名词在后⾯
二.获取单个对象时使⽤get 做前缀
三.获取多个对象时使⽤list 做前缀如 listOrders
四.获取统计值时使⽤count 做前缀
五.插⼊数据时使⽤save/insert 做前缀
六.删除数据时使⽤remove/delete 做前缀
七.修改数据时使⽤update 做前缀
(3)领域模型 POJO 类命名规范
一.数据对象:xxxDO,xxx 即为数据表名
二.Controller 层返回结果,展示对象⽤xxxVO
请求⼊参的命名格式⽤xxxRequest,查询条件封装对象⽤xxxQuery。
三.Dubbo API 层返回结果,返回对象⽤xxxDTO
请求的命名格式为 xxxRequest,查询条件封装对象⽤xxxQuery。
四.业务层内部的数据传输对象⼀般⽤xxxDTO,不做强制规定。
每个 POJO 类都会继承 AbstractObject 类,方便不同 POJO 之间的属性克隆。
(4)统一异常处理规范
一.定义⼀个 GlobalExceptionHandler 组件
通过对该组件添加 @RestControllerAdvice 注解,让该组件成为默认的 Controller 全局异常处理增强组件。在这个组件中,会分别对系统级别未知系统、客户端异常、服务端异常都做了统⼀处理。
二.继承基础业务异常类 BaseBizException
在业务代码开发中,可以直接抛出这个异常类,也可以在具体的业务代码⼯程新建⼀个类继承 BaseBizException,然后抛出⾃定义的异常类。⽐如在订单中⼼,新建⼀个 OrderBizException⾃定义类,然后继承 BaseBizException,最后在业务代码中抛出 OrderBizException。
三.提供 BaseErrorCodeEnum 错误信息枚举接⼝
各个业务服务在⾃定义错误枚举信息时,会继承该接口。在抛出业务异常时,统⼀使⽤错误枚举信息,可以很好地集中管理错误信息并定义错误码。
(5)统一返回结果处理规范
规范一:Web 层各个 Controller 组件可统⼀使⽤JsonResult 组件作为返回值,JsonResult 主要是定义了统⼀返回给前端的 Json 格式。
其中,success 字段表示请求是否成功,data 字段表业务数据。请求成功时才会返回业务数据,请求失败时 data 是 null。当 success 字段为 false 时,表示请求失败,此时 errorCode 与 errorMessage 才会有值,errorCode 与 errorMessage 分别表示错误码与错误提示信息。
规范二:Controller 中的⽅法也可以不返回 JsonResult 组件,⽽返回原样的对象,最后会由框架中的 GlobalResponseBodyAdvice 组件来统⼀拦截处理。
这个组件通过实现 ResponseBodyAdvice 接口 + 添加 @RestControllerAdvice 注解,实现了全局 Controller⽅法的默认的返回结果格式的统⼀处理。其中,处理逻辑都在 beforeBodyWrite()⽅法中。
规范三:如果某接⼝就想返回原样的对象,不想让返回结果被 JsonResult 封装,那么可以让 Controller⽅法返回一个 JsonMap 对象。
GlobalResponseBodyAdvice.beforeBodyWrite()⽅法会对类型为 JsonMap 的 body 进行直接返回。
(6)Service 层开发规范
业务异常规范:
一.Service 层需要中断执行的逻辑时,统⼀抛 BaseBizException 或其⼦类业务异常
二.DAO 层不要显式地抛任何业务异常,统⼀由 Service 来捕捉并抛异常
三.Controller 层不需要显式通过 try catch 来捕捉 Service 层抛出的业务异常,因为会由 GlobalExceptionHandler 组件来进行统⼀处理
四.抛业务异常时,建议对异常信息定义⼀个枚举值,这个枚举类要继承 BaseErrorCodeEnum
事务处理规范:
对于⾮查询接⼝,必须在 Service 实现类的⽅法上添加如下的 @Transactional 注解。
(7)DAO 层开发规范
一.Mybatis Plus 的配置使⽤规范
二.订单中⼼的 MybatisPlusConfig 组件示例
三.application.yml 中 mybatis-plus 开头的配置项
四.单表操作规范
⼀般情况下单表操作⽆论单条记录还是批量记录的增删改查,全部使⽤Mybatis Plus 框架的 IService 接口或 BaseMapper 接口。
只有多表关联查询时才需要在 mapper.xml⽂件中编写 SQL 脚本,不要让⼀个 SQL 脚本⽤于多个功能多个场景,特别是对很多字段做<#if>判断。然后作为可能的查询条件,应该按不同功能需求定义多个⽅法。
五.DO 通用字段处理规范
每个表都必须有三个必选字段 id、gmt_create、gmt_modified,其中 gmt_create、gmt_modified 这两个字段值都是让 Mybatis Plus⾃动填充的,不需要在业务代码中显式对这两个字段进⾏操作。
不过除了前⾯的 MybatisPlusConfig 中的配置之外,还需要在 DO 类的这两个字段上添加相应的注解,⽐如 OrderInfoDO 类。
文章转载自:东阳马生架构
评论