高并发下的库存扣减技术

news2024/10/24 11:23:51

背景

针对库存操作,宗旨:绝不超卖(存在资损、造成客诉、用户体验差)、尽量避免少卖(相对资损)。

在明星直播、大促、秒杀等高并发场景下,数据库的性能会变得非常差,传统的分库分表变得很鸡肋,因为大流量冲击的都是少量商品,最后还是会针对一条Sku库存数据做update操作,行锁会使得这些命令排序执行,导致慢SQL。(数据库用的MySQL架构,数据隔离级别为RC,提升并发度,降低死锁概率,另外表增加Version乐观锁,做并发情况的补偿操作)

为了解决这种场景,域内解决方案通常有三种:

  1. 库存数据水平拆分,打散热点。
  2. 限流排队扣减,增加扣减异步回调能力。
  3. 读写分离,同步缓存读,异步数据写,域内维护数据一致性。(采用)

新旧方案

旧方案

以前的方案,简单粗暴:

  1. 加分布式锁,防止重复扣减库存。
  2. 拆单后排序,防止高并发下数据库死锁。
  3. 同步扣减库存

在这里插入图片描述

以前方案的可行性在于自研的数据库引擎通过Inventory Hint技术实现热点数据更新的并发,改造后的MySQL在相同的配置下,相比传统的MySQL,读写性能提升了 2~4 倍。

UPDATE SKU_INVENTORY_TABLE
SET inventory = inventory - 1
WHERE sku_id = 1 and inventory > 0;
UPDATE /*+ COMMIT_ON_SUCCESS ROLLBACK_ON_FAIL TARGET_AFFECT_ROW(1)*/ SKU_INVENTORY_TABLE
SET inventory = inventory - 1
WHERE sku_id = 1 and inventory > 0;

Tip:

  1. COMMIT_ON_SUCCESS:语句成功即提交事务。
  2. ROLLBACK_ON_FAIL:语句失败则回滚事务。
  3. TARGET_AFFECT_ROW(NUMBER):语句影响指定行数才成功,否则失败。

当使用COMMIT_ON_SUCCESS等hint标记了一条SQL之后,就相当于告诉MySQL内核,这行可能是热点更新。于是,MySQL的内核层就会自动识别带此类标记的更新操作,在一定的时间间隔内,将收集到的更新操作按照主键或者唯一键进行分组,这样更新相同行的操作就会被分到同一组中。

在这里插入图片描述

为了进一步提升性能,又做了主备执行引擎,在主执行引擎收集完毕准备提交时,备执行引擎立即开始收集更新操作,主备无缝切换,提升处理效率。

热点数据在存储引擎内核分组之后,针对三个维度做了性能优化:

  1. 申请行锁等待的时间
  2. 减少B+数据索引遍历
  3. 减少事务提交次数

踩坑:在组合商品的场景,会涉及到拆单,此时可能会出现死锁问题,为了避免产生死锁,在进行DB扣减之前,可在SkuID维度做排序操作,打破锁的循环依赖。

流程图

在这里插入图片描述

新方案

虽然针对数据库引擎做了性能优化,但是在高并发的场景下,性能还是有所欠缺,所以在自研数据库引擎的基础上,做了一版新的方案。

库存扣减总共有三点:

  1. 防重(分布式锁|防重表)
  2. 防超卖(inventory > 0)
  3. 扣减库存(inventory = inventory -1)

设计思想:

  1. 用redis去做防重和防超卖的操作
  2. 库存操作异步落库
  3. 通过库存一致性引擎保证Redis和MySQL数据一致性

在这里插入图片描述

超卖校验

数据库:insert 主键;缓存:setnx key。

超卖校验包括两个操作:防重 + 扣减,防重将分布式锁方案调整为防重码方案,通过Pipeline命令将防重和Redis库存扣减操作合并为一个操作执行,这样可以大大降低Redis的RTT,提升性能。

超卖校验过程中,要注意防重操作和扣减操作的时序,如果防重在扣减操作之前,在极端情况下(机器宕机)可能会出现超卖现象。除此之外,还要注意Redis集群的可用性,针对热点防刷做本地限流即可。

扣减库存的流水信息也可以在一个管道进行记录,方便后续支持库存数据一致的“对账”功能,流水信息数据结构:skuId+订单ID、库存操作类型(+/-)、时间。

商品下架时可以清除商品的流水记录,也可以设置指定的缓存有效期。

在这里插入图片描述

库存变更

在发品时,需要将产品的库存同步双写至Redis和MySQL中,但是如果运营变更正在售卖的产品/商品的库存时,会存在数据混乱的问题(并发),针对这个问题,可通过MySQL行锁和Redis事务来保证数据一致性。

在这里插入图片描述

任务调度引擎

在超高并发下,优先消息队列存在瓶颈,可将扣减主任务通过MQ异步写入MySQL中,热卖品和库存高优品对任务增加优先级,降低热卖品对库存一致性引擎的影响。

库存一致性引擎

库存每天变动千万次,为了性能考虑,做了以下方案:

  1. 只针对低于一定水位线的商品,启动库存一致性引擎进行库存一致性对比,考虑到消息队列/任务调度的影响,在一定时间内两个数据源的流水信息经过多次对比,只要有一次判断为缓存-DB相等,就认定当前库存数据是一致的。
  2. 如果库存充足,在一定时间内进行一次对比,可以根据实际情况在配置中心,做动态调整。

在这里插入图片描述

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【C++进阶专栏】:priority_queue(优先级队列)?仿函数?

文章目录 前言1、优先级队列的使用?2、仿函数?3、优先级队列用仿函数实现大/小堆变换? 前言 priority_queue:优先级队列,别看有一个队列的名字,但结构个队列完全不一样。队列是一种先进先出的结构特征&…

AttributeError: ‘str‘ Object Has No Attribute ‘x‘:字符串对象没有属性x的完美解决方法

AttributeError: str Object Has No Attribute x:字符串对象没有属性x的完美解决方法 🔍💡 AttributeError: str Object Has No Attribute x:字符串对象没有属性x的完美解决方法 🔍💡摘要 📖引言…

四、音频播放

一、相关逻辑 在登录代码中调用,资源加载代码,然后再资源加载代码中调用。 1、登陆方法中: 单例类音频调用自己的方法,然后传入配置代码中的常量 2、音频播放代码中: 首先设置为一个单例类,然后初始化一…

精益与数字化的融合:制造业的创新之路

回望过去,精益管理作为制造业的瑰宝,以其“消除浪费、持续改进、顾客至上”的核心理念,引领了无数企业走向成功。从丰田生产方式到全球范围内的广泛实践,精益管理不仅提升了生产效率,更重塑了企业的文化和价值观。它教…

【Python大语言模型系列】一文教你使用dify云版本开发一个简单的Agent(完整教程)

这是我的第365篇原创文章。 一、引言 智能助手(Agent),利用大语言模型的推理能力,能够自主对复杂的人类任务进行目标规划、任务拆解、工具调用、过程迭代,并在没有人类干预的情况下完成任务。 本文我们将搭建一个旅行…

vt虚拟化怎么开启_各品牌主板及品牌机开启VT虚拟化教程

VT指的是CPU的虚拟化技术可以单CPU模拟多CPU并行,允许一个平台同时运行多个操作系统,并且应用程序都可以在相互独立的空间内运行而互不影响,从而显著提高计算机的工作效率。下面,小编给大家介绍电脑开启vt的操作步骤。 VT虚…

[LeetCode] 155. 最小栈

设计一个支持 push ,pop ,top 操作,并能在常数时间内检索到最小元素的栈。 实现 MinStack 类: MinStack() 初始化堆栈对象。void push(int val) 将元素val推入堆栈。void pop() 删除堆栈顶部的元素。int top() 获取堆栈顶部的元素。int get…

TiDB 监控组件之 Blackbox_exporter 运行原理

作者: TiDBerHailang 原文来源: https://tidb.net/blog/b269e96f 1. 介绍 本文介绍了 TiDB 集群监控组件Blackbox Exporter监控运行机制和配置方式。Blackbox Exporter是Prometheus官方提供的 Exporter,它能够通过多种协议对网络服务进行…

使用HTML、CSS和JavaScript创建滚动弹幕效果

使用HTML、CSS和JavaScript创建滚动弹幕效果 在现代网页设计中,滚动文本是一种常见的动态效果,可以吸引用户的注意力并增强交互体验。在这篇博客文章中,我们将详细介绍如何使用HTML、CSS和JavaScript实现滚动文本效果。 效果 步骤1&#xf…

【电商购物管理系统】Python+Django网页界面平台+商品管理+数据库

一、介绍 电商购物管理系统,本系统前端使用HTML、CSS、BootStrap等技术搭建前端界面,后端使用Django框架处理用户的逻辑请求。主要功能有: 管理员登录与管理:管理员可以登录后台,对用户和商品进行增删改查的操作。用…

使用mybatis查询数据库时,表有数据但是为空值null

前言 数据库有数据但是查出来都是空的 解决方法 这里写错了, resultType只能用在数据库字段和实体类字段一致的情况下,而数据库多单词通常用下划线隔开,不能映射到驼峰命名的实体类属性上,因此得使用一个ResultMap 1.定义映射映…

【C++】set/map(重点解析)

目录 一、关联式容器和序列式容器 二、C中的键值对——pair 1.概念 2.定义 3.构造pair 三.set 1.construct构造 2.iterator迭代器 3.insert插入 4.erase删除 5.find查找 6.lower_bound和upper_bound 7.count 四.multiset 五.map 1.insert 2.operator[] 一、…

Pygame实现音乐可视化

pip install pydub pip install ffmpeg pip install pyaudio 完整代码如下: import pygame,sys import random import numpy as np from random import randint import colorsys from pydub import AudioSegment import mathdef rnd_color(): #随机颜色h,s,l…

Python的reshape的用法和reshape(1,-1)、reshape(-1,1)

在创建DataFrame的时候常常使用reshape来更改数据的列数和行数。 reshape可以用于numpy库里的ndarray和array结构以及pandas库里面的DataFrame和Series结构。 reshape(行,列)可以根据指定的数值将数据转换为特定的行数和列数,这个…

用SAM2和Cutie模型目标追踪

一、数据集 视频:每个视频文件夹以图片帧的形式存储 box:给出每个视频第一帧要追踪的物体的box 二、将数据格式转换成SAM2所需要的格式 主要是将box转换成mask的格式,下面这个代码就是将box转换成mask的代码,具体转换原理如下…

深圳易图讯科技有限公司承建的厦门应急处突大队三维电子沙盘顺利通过专家验收

近日,深圳易图讯科技有限公司承建的厦门应急处突大队三维电子沙盘系统项目成功通过专家组的严格验收,标志着该系统在应急管理和处置突发事件方面的应用取得了重要突破。 验收过程中,专家组对三维电子沙盘系统的各项功能进行了全面而细致的测试…

第十六周:机器学习笔记

第十六周周报 摘要Abstratc一、机器学习1. Pointer Network(指针网络)2. 生成式对抗网络(Generative Adversarial Networks | GAN)——(上)2.1 Generator(生成器)2.2 Discriminator&…

Cef加载自定义本地资源

在Cef auto build下载cefCEF Automated Builds 我下载的是104,使用cefsimple工程。 例如:前端资源如下 通过http协议把前端资源加载出来。所有的资源都通过http://local.test.cn/xxx加载。 前端资源包括index.html、test.css、test.js index.html&am…

麒麟系统离线安装英伟达驱动

麒麟系统离线安装英伟达驱动 驱动相关程序下载下载显卡驱动下载CUDA-Toolkit下载cudnn 安装关闭自带图形界面禁用 Nouveau 驱动安装驱动安装CUDA-Toolkit安装cudnn 驱动相关程序下载 下载显卡驱动 进入显卡驱动查询页面,下载对应的显卡驱动,页面如下&a…

第十节:React路由:react-router认识与基本使用

1. React Router的理解 React的路由根据项目的不同使用不同的路由库,web应用主要使用react-router和react-router-dom react-router和react-router-dom的区别 react-rotuer 核心库,提供了一些核心的api,但是没有提供dom操作进行跳转的api react-router-dom扩展了核心库,提供了一…