深入理解高并发超卖一系列问题与解决方案(近7万字详解,跳槽涨薪必备宝藏珍藏级分享)

破除困境带你飞

能遇上高并发的,基本都是有点规模的公司,小公司基本都是CRUD。
想去一线城市跳槽,想去有高并发的公司,但是没有高并发经验,没有高并发的经验,就去不了高并发的公司,去不了这样的公司,就没有高并发经验,前狼后虎两头堵的困境,干就完了。

一语道破

超卖问题是属于并发安全问题,在并发情况下出现数据一致性的问题的表现,据有代表性。
这是个概率问题,不是一定发生或一定不发生。
核心问题就两个:

  • 并发引起的资源竞争却没有加锁,导致运行时序不可控(MySQL超卖)。
  • 多个读写操作存在间隙,导致并发请求通过间隙插队引发的时序不可控问题(Redis超卖)。

解决方案也很简单,上锁或者保证无间隙执行就行了。

并发问题仅仅只是一种,至于并发带来的,大数据存储、检索、以及安全问题都是需要考虑进去的。

MySQL超卖原理分析

假设无并发情况下代码逻辑没问题。这个问题主要出现在获取库存数据的方式上,并发过来时,多个请求获取到的库存一致,然后都在这个一致的库存基础上扣库存,自然要出错。

MySQL的解决方案

并发存在资源争夺问题,时序是不可控的,所以要上锁,强制在短时间内让数据串行更改。

  • 乐观锁:MySQL乐观锁与悲观锁
  • 悲观锁:MySQL锁(读锁、共享锁、写锁、S锁、排它锁、独占锁、X锁、表锁、意向锁、自增锁、MDL锁、RL锁、GL锁、NKL锁、插入意向锁、间隙锁、页锁、悲观锁、乐观锁、隐式锁、显示锁、全局锁、死锁)
  • 分布式锁:深入理解PHP+Redis实现分布式锁的相关问题

Redis超卖原理分析

Redis超卖,主要是开发者没有考虑到并发下资源争夺的间隙问题。
redis get(‘stock’)是5,然后decr(‘stock’),想让库存减到4,看起来没毛病。
但是get和decr是两条语句,因此存在间隙,get(‘stock’)是5只能代表执行的那个时刻是5,decr在执行时不能保证redis是以5的基础上自减的,可能已经被秒成0了。

Redis的解决方案

  • 笨方法:
    由于Redis是单线程的,利用Redis双向链表的特性可以完成,利用左推右拉的单向队列完成对库存的扣减。笨方法,笨就笨在要是有1000个商品,一共50000个库存,难道要存50000条数据吗。
    伪代码如下:
    实现通过缓存预热,将商品id缓存进redis队列中,例如:lPush('goods_ids' , 商品id)	
    然后抢购时:在逐个取出来,利用这些数据,做其它逻辑操作rPush('goods_ids', 商品id),知道这个动作返回false,证明库存全部扣完。
    
  • Redis+lua:
    利用Redis+Lua脚本的方式,让扣库存的动作无间隙执行,超卖问题,用redis操作string,或者hash类型都行。
    //用字符串类型操作,单商品库存
    $lua = <<<EOFlocal stock_key   = KEYS[1]                                -- Redis中存储库存数量的键名local input_stock = tonumber(ARGV[1])                      -- 要扣除的库存数量local redis_stock = tonumber(redis.call('GET', stock_key)) -- 获取当前库存数量if redis_stock >= input_stock thenredis.call('DECRBY', stock_key, input_stock)           -- 如果库存充足,则扣除库存数量return redis_stock - input_stock                       -- 返回扣除后的库存数量elsereturn -1                                              -- 库存不足,返回标记值,别返回0,有歧义end
    EOF;$redis = new Redis();
    $redis->connect('127.0.0.1', 6379);
    //stock为string名,2为要扣库存的数量
    $res = $redis->eval($lua, ['stock' , 2], 1);
    if($res == -1) {//库存不足
    }//库存充足,其它下游流程...
    
    用hash类型操作多商品库存
    $script = <<<EOFlocal hash_key    = KEYS[1]local goods_id    = KEYS[2]local input_stock = - tonumber(ARGV[1])if input_stock >= 0 thenreturn -1 -- 表单验证endlocal redis_stock = tonumber(redis.call('HGET', hash_key, goods_id))if redis_stock == nil thenreturn -2 -- 商品不存在endlocal stock_res = redis_stock + input_stockif stock_res < 0 thenreturn -3 -- 库存不足endredis.call('HSET', hash_key, goods_id, stock_res)return stock_res
    EOF;
    //扣减商品id为50的3个库存。
    $res = $redis->eval($script, ['stock', 50, 3], 2);
    if($res == -1) {echo '库存数据不合法';return;
    }
    if($res == -2) {echo '商品不存在';return;
    }
    if($res == -3) {echo '库存不足';return;
    }echo "库存扣减成功,当前库存为:{$res}";
    

关于Redis+Lua是否是原子性执行的争议问题

https://redis.io/docs/latest/develop/interact/programmability/eval-intro/
对Redis官网进行搜索,出现了原子性的字眼。
原话是:
Blocking semantics that ensure the script’s atomic execution.
Lua lets you run part of your application logic inside Redis. Such scripts can perform conditional updates across multiple keys, possibly combining several different data types atomically.

但是我想了想有矛盾的地方:
MySQL使用了undo log来保证原子性,要么成功全部执行,要么失败全部回滚。
众所周知,Redis不支持回滚的,那么ACID的A就没办法全部保证,最多是没有执行期间没有间隙,不被其它过来的请求影响,引起并发问题。

然后我又看了看阿里某架构师对此的剖析,跟我设想的一样:
Redis会把Lua脚本当做一个整体去执行,中间不会被其它的命令插入,但是如果执行过程中出现了错误,事务是不会回滚的。
也就意味着执行Lua脚本的过程不可被拆分,不可被中断,但是遇到错误不会回滚。

并发情况下MySQL与Redis缓存一致性问题详解

并发情况单个MySQL或单个Redis本身都有读写不一致的问题,更何况MySQL与Redis两个组件间通信又没有事务的约束,或者锁的加持,同样会出现一致性问题。
深入理解高并发下的MySQL与Redis缓存一致性问题(增删改查数据缓存的一致性、Canal、分布式系统CAP定理、BASE理论、强、弱一致性、顺序、线性、因果、最终一致性)

高并发带来的数据幂等性问题

库存一致性是一方面,库存保证好了,不代表,其它地方就一定不会出现库存一致性问题:
高并发下数据幂等问题的9种解决方案

高并发带来海量数据MySQL查询问题

MySQL索引底层原理相关问题自总结(难度对标18K-25K薪资,已总结80+,持续更新中)

MySQL查询优化方案汇总(索引相关)

高并发带来的亿级大数据检索问题

万字详解PHP+Sphinx中文亿级数据全文检索实战(实测亿级数据0.1秒搜索耗时)

高并发从侧面带来的安全问题

深入理解PHP+Redis实现布隆过滤器(亿级大数据处理和黑客攻防必备)

其它文章持续更新中……

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

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

相关文章

什么是bs架构和cs架构

bs架构是在浏览器就能访问到的系统&#xff0c;不需要用户去更新和安装app cs架构是需要下载一个app客户端&#xff0c;每次升级都需要更新app

mysql面试题五(事务)

目录 1.mysql有哪些锁及作用 1. 行锁&#xff08;Row Locks&#xff09; 2. 间隙锁&#xff08;Gap Locks&#xff09; 3. Next-Key Locks 4. 意向锁&#xff08;Intention Locks&#xff09; 5. 表锁&#xff08;Table Locks&#xff09; 6. 元数据锁&#xff08;Metad…

【Java基础】19.继承(面向对象的三大特征:封装、继承、多态)

文章目录 前言一、继承的概念二、继承的步骤1.类的继承格式2.继承的实例3.继承类型 三、继承的特性四、继承的关键字1.extends关键字2.implements关键字3.super 与 this 关键字4.final 关键字 五、构造器 前言 一、继承的概念 继承是java面向对象编程技术的一块基石&#xff…

python 3种算法 回溯法、字典序生成、递归交换 实现全排列【力扣46题】

作者介绍&#xff1a;10年大厂数据\经营分析经验&#xff0c;现任大厂数据部门负责人。 会一些的技术&#xff1a;数据分析、算法、SQL、大数据相关、python 欢迎加入社区&#xff1a;码上找工作 作者专栏每日更新&#xff1a; LeetCode解锁1000题: 打怪升级之旅 python数据分析…

webpack 打包优化 - splitChunks

打包时会遇到的问题&#xff1a; 打包文件过大&#xff0c;首屏加载时间过长&#xff0c;js阻塞页面渲染导致白屏改动业务代码后&#xff0c;对于第三方库也会一并重新打包到一个出口文件&#xff0c;浏览器无法利用缓存来减少请求和加载的时间 针对以上两个问题&#xff0c;…

适合生产制造企业用的ERP系统有哪些?

适合生产制造企业用的ERP系统有哪些&#xff1f; 想选择适合生产制造企业的ERP&#xff0c;首先了解市面上有哪些ERP系统 市面上的ERP系统主要分为三大类&#xff1a; 1、垂直领域的ERP系统&#xff1a;这些系统是针对特定行业或垂直市场定制的ERP解决方案&#xff0c;通常具…

功能测试前景揭秘:会被淘汰吗?

在当今快速发展的信息时代&#xff0c;软件已经成为我们工作、学习乃至生活中不可或缺的一部分。随着技术的不断进步和应用的广泛普及&#xff0c;软件测试作为保障软件质量和功能实现的关键步骤&#xff0c;其职业发展路径也受到了广泛的关注。特别是针对功能测试这一细分领域…

我与C++的爱恋:隐式类型转换

​ ​ &#x1f525;个人主页&#xff1a;guoguoqiang. &#x1f525;专栏&#xff1a;我与C的爱恋 朋友们大家好&#xff0c;本篇内容我们来介绍初始化列表&#xff0c;隐式类型转换以及explicit的内容 一、初始化列表 1.1 构造函数体赋值 在创建对象时&#xff0c;编译器…

说说redis的数据类型

1.字符串&#xff08;String&#xff09;&#xff1a;其存储二进制的数据&#xff0c;对数据可以进行原子性的增加或者减少操作 2.List&#xff08;列表&#xff09;&#xff1a;按照插入顺序进行排序&#xff0c;可以进行元素的重复&#xff0c;可以对列表的两端进行插入或者删…

etcd campaign

1. 引言 本文主要讲解使用etcd进行选举的流程&#xff0c;以及对应的缺陷和使用场景 2. etcd选举流程 流程如以代码所示&#xff0c;流程为&#xff1a; clientv3.New 创建client与etcd server建立连接 concurrency.NewSession 创建选举的session&#xff0c;一般会配置ses…

java:Java中的接口

什么是接口 概念&#xff1a; 官方解释&#xff1a;Java接口是一系列方法的声明&#xff0c;是一些方法特征的集合&#xff0c;一个接口只有方法的特征没有方法的实现&#xff0c;因此这些方法可以在不同的地方被不同的类实现&#xff0c;而这些实现可以具有不同的行为&#x…

Java Maven项目推送到 Maven 中央仓库

准备阶段 namespace 域名认证 当需要在 sonatype 认证 com.xxx命名空间时&#xff0c;需要将 .xxx.com 配置域名解析。 记录类型&#xff1a;TXT 文本内容&#xff1a;验证的 key。 GPG 公私钥生成 GPG 下载地址&#xff1a;https://www.gnupg.org/download/index.html M…

零代码编程:用kimichat将mp4视频批量转为mp3音频

一个文件夹里面有多个子文件夹&#xff0c;里面的视频需要转成为mp3音频格式。可以在kimichat中键入提示词&#xff1a; 你是一个Python编程专家&#xff0c;要完成一个Python脚本的编写任务&#xff0c;具体步骤如下&#xff1a; 打开文件夹&#xff1a;D:\CHATGPT For TikT…

openAI介绍及相关概念

OpenAI 简介 成立背景: OpenAI 成立于 2015 年&#xff0c;由一群高科技界的重要人物创立&#xff0c;包括 Elon Musk 和 Sam Altman。其目标是推动人工智能&#xff08;AI&#xff09;的发展&#xff0c;同时确保 AI 的发展能够造福全人类。 研究方向: OpenAI 专注于深度学习…

新手必犯的十大错误 Python语言

Python 是一种广泛使用的编程语言&#xff0c;它以其简洁和易读性而闻名。然而&#xff0c;即使是经验丰富的程序员也可能会遇到一些常见的错误。以下是一些常见的 Python 错误案例&#xff1a; 语法错误&#xff08;SyntaxError&#xff09;&#xff1a; print("Hello Wo…

SpringBoot中异步执行事务REQUIRED和REQUIRED_NEW的区别

springboot中事务的使用方式 在spring的bean中&#xff0c;要开启数据库事务只需要在方法中标注注解 Transactional 注解常用的参数有 Class[] rollbackFor() default {} 指定回滚异常Propagation propagation() default Propagation.REQUIRED 事务的传播机制Isolation iso…

Hive:GROUP BY GROUPING SETS

分组聚合 group by x1, x2, x3 grouping sets((x1), (x1, x2), (x1, x3),(x1, x2, x3)) 将不同维度的GROUP BY结果进行UNION ALL操作 GROUPING SETS会把在单个GROUP BY逻辑中没有参与GROUP BY的那一列置为NULL值&#xff0c;这样聚合出来的结果&#xff0c;未被GROUP BY的列…

web server apache tomcat11-10-Class Loader

前言 整理这个官方翻译的系列&#xff0c;原因是网上大部分的 tomcat 版本比较旧&#xff0c;此版本为 v11 最新的版本。 开源项目 从零手写实现 tomcat minicat 别称【嗅虎】心有猛虎&#xff0c;轻嗅蔷薇。 系列文章 web server apache tomcat11-01-官方文档入门介绍 web…

AI推介-多模态视觉语言模型VLMs论文速览(arXiv方向):2024.04.10-2024.04.15

文章目录~ 1.Photo-Realistic Image Restoration in the Wild with Controlled Vision-Language Models2.Do LLMs Understand Visual Anomalies? Uncovering LLM Capabilities in Zero-shot Anomaly Detection3.UNIAA: A Unified Multi-modal Image Aesthetic Assessment Base…

大华相机C#学习之Enumerator类

构造函数 Enumerator() 创建一个Enumerator实例。 常用方法 EnumerateDevices() 枚举所有发现设备,返回List<IDeviceInfo>对象。 List<IDeviceInfo> devices new List<IDeviceInfo>();private void test_Click(object sender, EventArgs e) {devicesEnum…