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

背景介绍




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



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

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

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

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



// 名词解释:

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

架构原则




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



系统设计




设计思路

1.当前库存系统瓶颈在哪里?

1.抗写流量,数据库成为瓶颈点。

2.如何解决系统瓶颈?

1.由高并发组件Redis替代数据库。

3.利用Redis需要解决哪些问题?

1.防超卖,异步写数据库保证最终一致性。









总体设计




扛量部分:库存性能瓶颈在预占,传统架构主要依靠数据库事务保持数据一致以及数据读写;新版架构设计将数据扛量部分移植到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&属性保存工具

待续。。。。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/121495.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

rviz添加qt插件

一、增加rviz plugin插件 资料:http://admin.guyuehome.com/42336 https://blog.51cto.com/u_13625033/6126970 这部分代码只是将上面两个链接中的代码整合在了一起,整合在一起后可以更好的理解其中的关系 1、创建软件包 catkin_create_pkg rviz_tel…

css呼吸效果实现

实现一个图片有规律的大小变化,呈现呼吸效果,怎么用CSS实现这个呼吸效果呢 一.实现 CSS实现动态效果可以使用动画( animation)来属性实现,放大缩小效果可以用transform: scale来实现,在这基础上有了动画,就可以设置一个…

每日汇评:黄金将测试1935美元的200日移动均线

金价在美联储主席鲍威尔发表讲话之前仍然脆弱; 在市场情绪喜忧参半的情况下,美元与美债收益率走势艰难; 在上升的三角形破裂和看跌的相对强弱指数中,黄金价格看向200日移动均线; 黄金周四早时在略低于1950美元的三周…

访问者模式

详情可参考:https://zhuanlan.zhihu.com/p/380161731 意图:主要将数据结构与数据操作分离。 适用于:系统中有稳定的数据结构,且数据结构的功能经常发生变化。 双分派:我的理解是两次多态操作,动态获取对象…

mysql的备份和恢复

备份:完全备份 增量备份 完全备份:将整个数据库完整的进行备份 增量备份:在完全备份的基础之上,对后续新增的内容进行备份 备份的需求 1、在生产环境中,数据的安全至关重要,任何数据的都可能产生非常严重…

PHP保存时自动删除末尾的空格,phpstorm自动删除空白字符串

最近有个活儿,修改一个财务软件。 修改后给客户验收的过程中,客户反应有一个txt表格导出功能不能用了。之前是好的。 这次是新增,老的这个功能碰都没碰过,怎么能有问题呢?我心里OS 下班后我立马用系统导出TXT&#…

如何实现Debian工控电脑USB接口安全管控

Debian 作为工控电脑操作系统具有稳定性、安全性、自定义性和丰富的软件包等优势,适用于要求高度可靠性和安全性的工控应用。 Debian 作为工控电脑操作系统在工业控制领域有很大优势,包括: 稳定性:Debian 的发布版以其稳定性而闻…

ThinkPHP框架 开源 虚拟资源分享付费下载PHP网站源码

源码测评:非常不错的资源分享网站,仿的是之前的码农网,这个网站也是在码农网的源码基础上修改而来,这个是用ThinkPHP仿的,还不错,测试的时候发现后台上传图片报错,其他暂时没有发现。 转载自…

Leetcode刷题【hot100】盛最多水的容器

给定一个长度为 n 的整数数组 height 。有 n 条垂线,第 i 条线的两个端点是 (i, 0) 和 (i, height[i]) 。 找出其中的两条线,使得它们与 x 轴共同构成的容器可以容纳最多的水。 返回容器可以储存的最大水量。 说明:你不能倾斜容器。 示例…

OpenAI 工程师平均薪酬 92.5 万美元;SpaceX 明年将每两天发射一次丨 RTE 开发者日报 Vol.81

开发者朋友们大家好: 这里是 「RTE 开发者日报」 ,每天和大家一起看新闻、聊八卦。我们的社区编辑团队会整理分享 RTE (Real Time Engagement) 领域内「有话题的 新闻 」、「有态度的 观点 」、「有意思的 数据 」、「有思考的 文…

【爬虫与反爬虫】从技术手段与原理深度分析

文章目录 1. 爬虫的基本概念1.1. 什么是爬虫1.2. 爬虫的价值1.3. 爬虫的分类 3. 爬虫技术原理与实现4. 反爬虫基本概念4.1. 什么是反爬虫4.2. 反爬虫的目的4.3. 反什么样的爬虫 5. 由浅到深的反爬虫技术手段5.1. 主动常见型反爬虫5.1.1. 基于爬虫行为5.1.2. 基于身份识别 6. 被…

Banana Pi BPI-M6(Raspberry Pi 5 替代品)初始设置及固件烧录

Banana Pi BPI-M6:初始设置和镜像烧录 Banana Pi BPI-M6 的首次测试 在上一篇文章中,我比较了Banana Pi BPI-M6和Raspberry Pi 5的硬件特性。两者都拥有出色的硬件技术,在性能方面应该不会有太大的问题。 今天我想测试一下 Banana Pi。作为…

Zabbix“专家坐诊”第210期问答汇总

问题一 Q:zabbix触发器条件基于历史趋势的函数有示例吗?还有这些基于历史趋势的函数,具体是读取历史表还是趋势表? A:读历史表,示例可以看看官网的。 https://www.bookstack.cn/read/zabbix-5.0-zh/37cf0…

Qt实现自定义多选下拉列表

目录 前言1、 功能描述2、代码实现总结 前言 本文记录了一种通过继承 QComboBox 实现下拉列表多选功能的方法。效果如下图所示: 1、 功能描述 普通的下拉列表只支持选择一个选项,在软件开发过程中,经常会遇到下拉列表支持选择多个选项的需…

网络原理---拿捏网络层:IP协议

文章目录 IP协议4位版本4位首部长度、选项8位服务类型(TOS)16位总长度16位标识、3位标志、13位片偏移8位生存时间(TTL)8位协议16位首部校验和32位源IP地址、32位目的IP地址解决IP地址不够用的问题动态分配IP地址NAT机制&#xff0…

RPA处理重复工作,助力高效资金管理

在瞬息万变的市场竞争中,众多企业开展多元化经营以获取最大的经济效益。然而,企业的多元化经营程度越高,协调活动可能造成的决策延误也越多,其资金管理往往将面临更大的考验。随着新技术的发展,更多具备多元产业的企业…

关于卷积神经网络的填充(padding)

认识填充 (padding) 随着卷积层数的加深,输出进一步缩小,那么最终会导致输出很快就只剩下1∗1的数组,这也就没办法继续计算了,所以提出了填充的方法来方便网络的进一步加深。 其实填充的原因有两点&#xf…

亚马逊云科技Zero ETL集成全面可用,可运行近乎实时的分析和机器学习

亚马逊云科技数据库、数据分析和机器学习全球副总裁Swami Sivasubramanian曾指出:“数据是应用、流程和商业决策的核心。”如今,客户常用的数据传输模式是建立从Amazon Aurora到Amazon Redshift的数据管道。这些解决方案能够帮助客户获得新的见解&#x…

“2024杭州国际物联网展览会”定于4月份在杭州国际博览中心召开

随着科技的飞速发展,物联网已经成为当今社会的一个重要组成部分。物联网技术正在逐渐渗透到各个领域,为人们的生活带来更多的便利和智慧。物联网的发展趋势将受到技术、应用、安全等多方面的影响和推动。未来,物联网将更加智能化、自主化和安…

使用Docker部署开源分布式任务调度系统DolphinScheduler

🔥博客主页: 小羊失眠啦. 🎥系列专栏:《C语言》 《数据结构》 《Linux》《Cpolar》 ❤️感谢大家点赞👍收藏⭐评论✍️ 使用Docker部署开源分布式任务调度系统DolphinScheduler 文章目录 使用Docker部署开源分布式任务…