库存预占架构升级方案设计 - 交易库存中心

本文涉及的产品
Redis 开源版,标准版 2GB
推荐场景:
搭建游戏排行榜
云数据库 Tair(兼容Redis),内存型 2GB
简介: 伴随物流行业的迅猛发展,一体化供应链模式的落地,对系统吞吐、系统稳定发出巨大挑战,库存作为供应链的重中之重表现更为明显。近三年数据可以看出:

背景介绍
伴随物流行业的迅猛发展,一体化供应链模式的落地,对系统吞吐、系统稳定发出巨大挑战,库存作为供应链的重中之重表现更为明显。近三年数据可以看出:

接入商家同比增长 37.64%、货品种类同比增长 53.66%

货品数量同比增长 46.43%、仓库数量同比增长 18.87%

通过分析过往大促流量,分钟级流量增长率为 75%,大促仓内反馈三方订单下传不及时,库存预占吞吐量和性能是导致订单积压因素之一。目前库存使用 mysql 数据库作为接单预占的扛量手段,随着一体化供应链建设以及重点 KA 商家不断接入,现有库存架构在业务支撑上存在风险和缺陷。

此外未来 3 到 5 年业务增长、流量增长预计增长 5-10 倍。为避免系统性能和技术架构缺陷导致业务损失,轻量级库存架构势在必行。

// 名词解释:

库存预占:是指消费者拍下商品订单后,库存先为该订单短暂预留,预留的库存即为预占库存。

架构原则
架构:是⾯向问题,解决问题的手段。 库存系统的问题:非功能性:1. 高并发 2. 系统稳定性 (容灾) 3. 数据一致性 功能性: 1. 业务复杂 2. 数据一致性

系统设计
设计思路
当前库存系统瓶颈在哪里?:抗写流量,数据库成为瓶颈点。
如何解决系统瓶颈?:由高并发组件 Redis 替代数据库。
利用 Redis 需要解决哪些问题?:防超卖,异步写数据库保证最终一致性。

总体设计
扛量部分:库存性能瓶颈在预占,传统架构主要依靠数据库事务保持数据一致以及数据读写;新版架构设计将数据扛量部分移植到 Redis,利用 Redis 高性能吞吐解决高并发场景下数据读写。
数据回写:Redis 进行扛量削峰,后续数据仅用于记账,最终牺牲数据的短暂一致性达到削峰的目的。
差异部分:老版本库存预占设计仅依靠数据进行数据处理,新版设计依靠切量配置建数据切换到 Redis,利用 Redis 高读写进行削峰操作。

详细设计
主流程:

库存初始化:竞态条件利用 Redis watch 命令来实现锁等待,解决并发场景数据不一致问题。
LUA 执行器:将原子操作指令 / 复用指令封装到 LUA 脚本中以减少网络开销。
补偿机制:i> 执行流程中所有业务异常发生时会同步发起反向操作请求;ii> 反向操作执行异常后会提交异步反向操作任务;iii> 异步任务执行异常后,依赖监 q 控系统扫描异常单据或异常库存并修改异常库存量

回溯回写:任务落库后发出 mq 组装参数调用数据回写服务,数据回写服务操作库存数量;同时回写 redis 数据,释放预占量库存数据;更新任务库数据状态

数据结构
库存记录索引:{deptNo|goodsNo|warehouseNo}|stockStatus|stockType|goodsLevel
hashTag:{deptNo|goodsNo|warehouseNo}|stockStatus|stockType|goodsLevel
可售库存数量:usableKey:{库存记录索引}
扣减库存量:usableSubtractKey:{库存记录索引} ,记录 Redis 到 DB 执行期间减库存量
预占防重 key:operateKey:{库存记录索引:单号} 防重 key 防并发重复请求
回滚防重:rollbackOperateKey:{库存记录索引}
缺量预占库存量:ullageOperateKey:{库存记录索引}
扣减库存单据记录:hSetrecord: {库存记录索引}
key 预占 缺量预占 回滚 回写
可售库存数量 - - + 不变
扣减库存量 + + - -
预占防重 key + + - 不变
回滚防重 不变 不变 + 不变
缺量预占库存量 不变 + 反向 不变
扣减库存单据记录 + + - -
Redis&DB
首先进行 redis & 从库数据比对,若存在差异则对主库进行校验
比对过程中,DB 中 sku 明细行进行锁定 (for update),比对逻辑为 DB 可用库存量 ==(Redis 可用库存量 + Redis 预占量)
有差异,报警且触发 SDK 可用量过期,同时矫正预占量

容灾方案

// 对系统容错 / 降级、监控机制 (空间换稳定性,两份 redis,故障 3 次丢数),流量分布材料,618 流量大、峰值数据切量。数据不一致,多个商家,不能超过 5 分。

预占任务持久化:mysql 需要将核心属性字段数据持久化:事业部,商品编码,仓编码,等级,库存类型,库存状态,预占库存量,任务状态;调度执行完成后需要更新 stockTask 状态为完成

初始化:

(1) lock db

(2) sum stockTask

(3) 使用 DB 可用库存初始化 Redis 可用库存,stockTask 预占量初始化 Redis 预占量

(4) Redis 库存回滚,如果预占量 key 不存在,该 key 不需要回滚

性能结果

23 年 618 大促

切量细则
切量细则

冷热数据
OMS 库存冷热装置

预占架构升级切量重点 key 监控

库存预占架构升级切量商家

架构升级切量商家明细 2

已切量商家

反向切量
原有设计中存在以下名单

禁止切量商家:优先级较高,一旦在名单中,禁止切量

批次库存商家:批次库存管理商家,目前该部分能力尚未建设

动态质押商家:物流金融业务,目前该部分能力尚未建设 切量名单商家:该部分为切量商家

原有切量流程:!禁止切量 ->!批次库存 ->!动态质押 -> 切量名单中,通过以上校验为切量商家。

原有流程在增量商家中需要手动将商家配置到切量名单中才可进行切量操作,对于新增商家场景操作不变,且原有流程中逻辑库存名单为痛点:逻辑库存的启用配置在事业部主数据中,不在库存侧。

新版切量流程中对切量名单进行优化,将原来切量名单商家拆分成非逻辑库存名单、逻辑库存两个名单,其中:

非逻辑库存名单:包含可切量商家

逻辑库存名单:逻辑库存商家,该部分不可切量

原流程新流程对切量商家名单进行优化,拆分成非逻辑库存名单、逻辑库存两个名单

构建模型 (批次库存 & 内存模型待续)

Redis 存储数据结构
MD 生成规则工具集
◦逻辑库存 MD5 工具

 StringBuffer md5Key = new StringBuffer();
 md5Key.append(logicWarehouseStock.getGoodsNo()+"_"+logicWarehouseStock.getWarehouseNo()+"_"+logicWarehouseStock.getOwnerNo()+
         "_"+logicWarehouseStock.getDeptNo()+"_"+logicWarehouseStock.getStockType()+"_"+logicWarehouseStock.getGoodsLevel());
 if(StringUtils.isBlank(logicWarehouseStock.getFactor1())){
     md5Key.append("_0");
 }else {
     md5Key.append("_"+logicWarehouseStock.getFactor1());
 }
 if(StringUtils.isBlank(logicWarehouseStock.getFactor2())){
     md5Key.append("_0");
 }else {
     md5Key.append("_"+logicWarehouseStock.getFactor2());
 }
 if(StringUtils.isBlank(logicWarehouseStock.getFactor3())){
     md5Key.append("_0");
 }else {
     md5Key.append("_"+logicWarehouseStock.getFactor3());
 }
 if(StringUtils.isBlank(logicWarehouseStock.getFactor4())){
     md5Key.append("_0");
 }else {
     md5Key.append("_"+logicWarehouseStock.getFactor4());
 }
 if(logicWarehouseStock.getYn()== null){
  md5Key.append("_1");
 }else {
     md5Key.append("_"+logicWarehouseStock.getYn());
 }
 md5Key.toString().hashCode()

批次库存 MD5 工具
public void fillMd5Value(){
StringBuffer md5Key = new StringBuffer();
md5Key.append(warehouseNo);
md5Key.append("");
md5Key.append(goodsNo);
md5Key.append("
");
md5Key.append(goodsLevel);
md5Key.append("_");
md5Key.append(stockType);
//遍历类字段不遍历map是为了控制MD5的组成顺序
Class clazz = BatchAttrStock.class;
Field[] fields = clazz.getDeclaredFields();
try {
int batchFieldCount = 0 ;
for (Field field : fields){
BatchAttrEnum attrEnum = BatchAttrEnum.batchFieldEnumMap.get(field.getName());
//不是批属性的字段不进入MD5的组成
if (attrEnum == null){
continue;
}
batchFieldCount ++;
field.setAccessible(true);
Object value = field.get(this);
if (value == null ){
md5Key.append("0");
continue;
}
if(field.getType().toString().contains("String")){
md5Key.append(value);
continue;
}
if(field.getType().toString().contains("Date")){
Date timeField = (Date) value;
md5Key.append(timeField.getTime());
continue;
}
throw new RuntimeException(attrEnum.getField()+"填充MD5异常");
}
//默认50个批属性长度,长度不够0补齐
int remainLength = 50 - batchFieldCount;
String str = String.format("%0"+remainLength+"d", 0);
md5Key.append(str);

    }catch (Exception e){
        throw new RuntimeException("填充MD5异常.");
    }

    md5Key.append(yn);
    String md5Value =  MD5Util.md5(md5Key.toString());
    setMd5Value(md5Value);
}

MD&ID & 属性保存工具
本文篇幅有限,余下二期进行分享。

相关实践学习
基于Redis实现在线游戏积分排行榜
本场景将介绍如何基于Redis数据库实现在线游戏中的游戏玩家积分排行榜功能。
云数据库 Redis 版使用教程
云数据库Redis版是兼容Redis协议标准的、提供持久化的内存数据库服务,基于高可靠双机热备架构及可无缝扩展的集群架构,满足高读写性能场景及容量需弹性变配的业务需求。 产品详情:https://www.aliyun.com/product/kvstore     ------------------------------------------------------------------------- 阿里云数据库体验:数据库上云实战 开发者云会免费提供一台带自建MySQL的源数据库 ECS 实例和一台目标数据库 RDS实例。跟着指引,您可以一步步实现将ECS自建数据库迁移到目标数据库RDS。 点击下方链接,领取免费ECS&RDS资源,30分钟完成数据库上云实战!https://developer.aliyun.com/adc/scenario/51eefbd1894e42f6bb9acacadd3f9121?spm=a2c6h.13788135.J_3257954370.9.4ba85f24utseFl
相关文章
|
1月前
|
存储 SQL 关系型数据库
Mysql高可用架构方案
本文阐述了Mysql高可用架构方案,介绍了 主从模式,MHA模式,MMM模式,MGR模式 方案的实现方式,没有哪个方案是完美的,开发人员在选择何种方案应用到项目中也没有标准答案,合适的才是最好的。
164 3
Mysql高可用架构方案
|
17天前
|
机器学习/深度学习 编解码 人工智能
超越Transformer,全面升级!MIT等华人团队发布通用时序TimeMixer++架构,8项任务全面领先
一支由麻省理工学院、香港科技大学(广州)、浙江大学和格里菲斯大学的华人研究团队,开发了名为TimeMixer++的时间序列分析模型。该模型在8项任务中超越现有技术,通过多尺度时间图像转换、双轴注意力机制和多尺度多分辨率混合等技术,实现了性能的显著提升。论文已发布于arXiv。
139 83
|
3天前
|
决策智能 数据库 开发者
使用Qwen2.5+SpringBoot+SpringAI+SpringWebFlux的基于意图识别的多智能体架构方案
本项目旨在解决智能体的“超级入口”问题,通过开发基于意图识别的多智能体框架,实现用户通过单一交互入口使用所有智能体。项目依托阿里开源的Qwen2.5大模型,利用其强大的FunctionCall能力,精准识别用户意图并调用相应智能体。 核心功能包括: - 意图识别:基于Qwen2.5的大模型方法调用能力,准确识别用户意图。 - 业务调用中心:解耦框架与业务逻辑,集中处理业务方法调用,提升系统灵活性。 - 会话管理:支持连续对话,保存用户会话历史,确保上下文连贯性。 - 流式返回:支持打字机效果的流式返回,增强用户体验。 感谢Qwen2.5系列大模型的支持,使项目得以顺利实施。
123 5
使用Qwen2.5+SpringBoot+SpringAI+SpringWebFlux的基于意图识别的多智能体架构方案
|
23天前
|
消息中间件 架构师 数据库
本地消息表事务:10Wqps 高并发分布式事务的 终极方案,大厂架构师的 必备方案
45岁资深架构师尼恩分享了一篇关于分布式事务的文章,详细解析了如何在10Wqps高并发场景下实现分布式事务。文章从传统单体架构到微服务架构下分布式事务的需求背景出发,介绍了Seata这一开源分布式事务解决方案及其AT和TCC两种模式。随后,文章深入探讨了经典ebay本地消息表方案,以及如何使用RocketMQ消息队列替代数据库表来提高性能和可靠性。尼恩还分享了如何结合延迟消息进行事务数据的定时对账,确保最终一致性。最后,尼恩强调了高端面试中需要准备“高大上”的答案,并提供了多个技术领域的深度学习资料,帮助读者提升技术水平,顺利通过面试。
本地消息表事务:10Wqps 高并发分布式事务的 终极方案,大厂架构师的 必备方案
|
1月前
|
缓存 关系型数据库 MySQL
高并发架构系列:数据库主从同步的 3 种方案
本文详解高并发场景下数据库主从同步的三种解决方案:数据主从同步、数据库半同步复制、数据库中间件同步和缓存记录写key同步,旨在帮助解决数据一致性问题。关注【mikechen的互联网架构】,10年+BAT架构经验倾囊相授。
高并发架构系列:数据库主从同步的 3 种方案
|
9天前
|
弹性计算 负载均衡 安全
云端问道-Web应用上云经典架构方案教学
本文介绍了企业业务上云的经典架构设计,涵盖用户业务现状及挑战、阿里云业务托管架构设计、方案选型配置及业务初期低门槛使用等内容。通过详细分析现有架构的问题,提出了高可用、安全、可扩展的解决方案,并提供了按量付费的低成本选项,帮助企业在业务初期顺利上云。
|
9天前
|
弹性计算 负载均衡 安全
企业业务上云经典架构方案整体介绍
本次课程由阿里云产品经理晋侨分享,主题为企业业务上云经典架构。内容涵盖用户业务架构现状及挑战、阿里云业务托管经典架构设计、方案涉及的产品选型配置,以及业务初期如何低门槛使用。课程详细介绍了企业业务上云的全流程,帮助用户实现高可用、稳定、可扩展的云架构。
|
1月前
|
人工智能 Cloud Native 算法
|
1月前
|
网络协议 数据挖掘 5G
适用于金融和交易应用的低延迟网络:技术、架构与应用
适用于金融和交易应用的低延迟网络:技术、架构与应用
72 5
|
2月前
|
存储 消息中间件 人工智能
ApsaraMQ Serverless 能力再升级,事件驱动架构赋能 AI 应用
本文整理自2024年云栖大会阿里云智能集团高级技术专家金吉祥的演讲《ApsaraMQ Serverless 能力再升级,事件驱动架构赋能 AI 应用》。
153 10

热门文章

最新文章