Redis分布式锁在高并发环境下的超卖问题

news2024/9/25 9:40:29

先看这样一段代码,购买商品,扣减库存的逻辑代码

当用户下单,并且调用扣减库存的接口时,先判断商品库存是否还有,因为是秒杀场景下,太多请求都打到数据库,可能会导致数据库崩溃,所以会使用redis缓存,保存商品库存数。

由于是微服务架构,为了实现高并发,我们的商品业务代码(包含库存这部分的代码)不可能只部署在一台服务器上,肯定会在多台服务器上都运行。

场景:

假设:当多个请求同时执行到从redis缓存中取库存值的时候,stock=100,判断库存>0成立,然后进行下面的逻辑,当扣减1个库存时,都会把stock=99写回redis缓存的时候,这时,明明卖了2个,但是redis缓存中的数据stock却等于99,就超卖了。

改进:

我们使用同步代码块,使用Java的synchronized锁,只能解决商品业务代码部署在一台部署上的场景,因为synchronized锁是JVM进程级别的锁,对于多台服务器部署的场景,每台服务器都可以获得它的进程的synchronized锁,还是不能解决微服务架构下的超卖问题。

继续改进:

我们使用redis提供的原生命令setnx实现分布式锁(Java客户端jedis提供的方法setIfAbsent和原生命令setnx是一样的),这个锁加在了redis服务器上,一次只有一个请求能获得,当代码执行完成后,释放锁。好像解决了超卖问题,但是如果代码执行到中间时,代码抛出异常了,锁就一直存在在redis中,其他服务永远无法进入redis,就死锁了。

继续改进:

使用try...finally,就算代码中间抛了异常,也能将锁释放掉。

但是当服务器执行到中间,服务器挂掉了,锁还是不会释放,怎么办?

继续改进:

一般会给锁设置一个超时时间,就算服务器挂掉了,redis服务器中的锁还是会自动释放。

但是,当服务器获取了锁之后,正准备设置超时呢,由于是两条命令分开执行,还是可能会突然服务器挂了,是有可能没设置成功超时时间的,这把锁还是永远在redis中

所以一般使用一条命令,设置锁的同时设置超时时间,发送到redis服务器。

继续改进:

这样好像就没啥问题了,但是在高并发场景下,接口的响应可能会变慢。

当一个请求获取到锁时,处理业务时间由于超过了10s,还没有完成扣减库存,锁过了10s,自动释放了,由于高并发场景下,同时有源源不断的请求过来,其他请求就获得了锁,这时,又会导致超卖问题。这时,可能不只是超卖一个两个的问题,第二个请求加锁成功后,如果第一个请求完成了,执行 解锁 操作,会把第二个请求加的锁给释放掉了,其实这时第二个请求还没执行完成,然后请求三又会获得锁,造成一系列的超卖问题。

造成这个问题的原因,就是线程1把线程2的锁给释放掉了,线程2把线程3的锁给释放掉了,锁一直失效。

继续改进:

中小公司,当并发量不是特别大的时候,是没问题的。

但是这段代码仍然存在线程1加的锁,当线程1没执行完成,锁自动超时释放的情况。在高并发场景下,其他请求又可以获得锁,进入扣减库存操作了,一旦重复扣减同一个数字,又造成超卖问题了。

解决方案:

当线程1获得锁之后(假设设置超时时间t = 30s),在当前线程1的代码内部会开辟一个异步线程2,每过10s (1/3*t) 就会检查线程1是否执行完毕,当线程1还没执行完毕,异步线程2就会重新把这个锁的超时时间设置成30s,这个机制叫watchDog。

异步线程2为什么能获得这个锁的使用权?因为redis的分布式锁是可重入锁,线程2在线程1内部,能直接获得redis中的这个锁。



这个watchDog的机制自己实现起来比较复杂,所以推荐使用Redisson分布式锁。

Redisson分布式锁的实现机制就是基于以上这些逻辑。

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

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

相关文章

[leetcode] largest-divisible-subset 最大整除子集

. - 力扣&#xff08;LeetCode&#xff09; class Solution { public:vector<int> largestDivisibleSubset(vector<int>& nums) {int len nums.size();sort(nums.begin(), nums.end());// 第 1 步&#xff1a;动态规划找出最大子集的个数、最大子集中的最大整…

Djngo项目创建的准备工作【5】

【 一 】搭建纯净模式 核心就是 在安装完drf之后记得在app里面注册rest_framework, # django 默认很多app--》很多表auth 6个表session 表content-type表 # django很多中间件 ​ # 以后我们的项目&#xff0c;可能不用这些东西---》由于带了内置app&#xff0c;这些表就会创建…

MaxViT : 多轴Vision Transformer

本文提出了一种高效、可扩展的多轴注意力模型,该模型包括两个方面:局部注意力被阻塞和全局注意力被扩张。这些设计选择允许在任意输入分辨率下的全局-局部空间交互,只有线性复杂度。还通过有效地将注意力模型与卷积混合在一起,提出了一个新的架构元素,并相应地提出了一个简…

IAR全面支持芯驰科技E3系列车规MCU产品E3119/E3118

中国上海&#xff0c;2024年7月11日 — 全球领先的嵌入式系统开发软件解决方案供应商IAR与全场景智能车芯引领者芯驰科技宣布进一步扩大合作&#xff0c;最新版IAR Embedded Workbench for Arm已全面支持芯驰科技的E3119/E3118车规级MCU产品。IAR与芯驰科技有着悠久的合作历史&…

强化学习实战3:Sarsa 与 Q-Learning 算法求解迷宫问题

前置知识 首先实验环境依然是我们之前说的迷宫环境&#xff0c;然后是一些基本术语&#xff0c;应该都是比较熟悉的&#xff1a; 强化学习的算法大概有两类&#xff0c;一类是策略迭代&#xff08;讲究的是策略 Π &#xff09;&#xff0c;还有一类是价值迭代&#xff0c;也就…

电脑 DNS 缓存是什么?如何清除?

DNS&#xff08;Domain Name System&#xff0c;域名系统&#xff09;是互联网的重要组成部分&#xff0c;负责将人类易记的域名转换为机器可读的 IP 地址&#xff0c;从而实现网络通信。DNS 缓存是 DNS 系统中的一个关键机制&#xff0c;通过临时存储已解析的域名信息&#xf…

lnmp+DISCUZ+WORDPRESS

lnmpDISCUZWORDPRESS lnmpDISCUZ&#xff08;论坛的一个服务&#xff09; l&#xff1a;linux操作系统 n&#xff1a;nginx前端页面的web服务 php&#xff1a;动态请求转发的中间件 mysql&#xff1a;数据库 保存用户和密码以及论坛的相关内容 mysql8.0.30安装&#xff1a…

微信综合购物商城小程序ui模板源码

微信电商小程序前端页面&#xff0c;综合购物商城ui界面模板。主要功能包含&#xff1a;电商主页、商品分类、购物车、购物车结算、我的个人中心管理、礼券、签到、新人专享、专栏、商品详情页、我的订单、我的余额、我的积分、我的收藏、我的地址、我的礼券等。这是一款非常齐…

单相整流-TI视频课笔记

目录 1、单相半波整流 1.1、单相半波----电容滤波---超轻负载 1.2、单相半波----电容滤波---轻负载 1.3、单相半波----电容滤波---重负载 2、全波整流 2.1、全波整流的仿真 2.2、半波与全波滤波的对比 3、全桥整流电路 3.1、全波和全桥整流对比 3.2、半波全波和全桥…

【Linux杂货铺】2.进程优先级

1.进程优先级基本概念 进程优先级是操作系统中用于确定进程调度顺序的一个指标。每个进程都会被分配一个优先级&#xff0c;优先级较高的进程会在调度时优先被执行。进程优先级的设定通常根据进程的重要性、紧急程度、资源需求等因素来确定。操作系统会根据进程的优先级来决定进…

出现 failed to remove xxxx: Invalid argument 解决方法

目录 前言1. 问题所示2. 原理分析3. 解决方法 前言 这好像是一个Git的一个Bug&#xff0c;对应有个下下策的解决方式 1. 问题所示 Git提交的时候出现如下问题 Git warning:failed to remove debug.log:invalid argumentgit clean -f -1 --F&#xff1a;\xxx failed to rem…

准备工作+1、请求和响应+2、模型和管理站点

Django快速入门——创建一个基本的投票应用程序 准备工作1、创建虚拟环境2、安装django 1、请求和响应&#xff08;1&#xff09;创建项目&#xff08;2&#xff09;用于开发的简易服务器&#xff08;3&#xff09;创建投票应用&#xff08;4&#xff09;编写第一个视图1、编写…

Python(四)---序列

文章目录 前言1.列表1.1.列表简介1.2.列表的创建1.2.1.基本方式[]1.2.2.list()方法1.2.3.range()创建整数列表1.2.4.推导式生成列表 1.3. 列表各种函数的使用1.3.1.增加元素1.3.2.删除元素1.3.3.元素的访问和计数1.3.4.切片1.3.5.列表的排序 1.4.二维列表 2.元组2.1.元组的简介…

mybatis基础语法

Mybatis快速入门 1.需求 使用MyBatis查询所有的用户, 封装到List集合 2.分析 创建maven工程&#xff08;jar&#xff09;&#xff0c;添加坐标创建pojo创建UserDao接口创建UserDao映射文件创建Mybatis核心配置文件SqlMapConfig.xml编写java代码测试 3.实现 准备工作&…

《梦醒蝶飞:释放Excel函数与公式的力量》11.3 ISTEXT函数

第11章&#xff1a;信息函数 第三节 11.3 ISTEXT函数 11.3.1 简介 ISTEXT函数是Excel中的一个信息函数&#xff0c;用于检查指定单元格中的内容是否为文本。如果单元格内容是文本&#xff0c;则返回TRUE&#xff1b;否则返回FALSE。ISTEXT函数在数据验证、条件格式化和逻辑判…

【排序算法】插入排序(希尔排序)

目录 一.直接插入排序 1.基本思想 2.实现 3.特性 1.效率 2.时间复杂度&#xff1a;O(N^2) 3.空间复杂度&#xff1a;O(1) 4.稳定性&#xff1a;稳定 二.希尔排序 1.基本思想 2.实现 3.特性 1.效率 2.时间复杂度&#xff1a;O(N^1.3) ​编辑 3.空间复杂度&#xff…

AI在软件开发中的角色:辅助创新还是自动化取代?

文章目录 每日一句正能量前言&#xff1a;人工智能与软件开发的未来交汇点AI工具现状AI对开发者的影响工作方式的改变需要掌握的新技能保持竞争力的策略结论 AI开发的未来AI在软件开发领域的未来发展方向AI是否可能完全取代开发者如何在AI时代规划开发者的职业发展结论 后记&am…

【通过pnpm创建vite项目】

vue3最新项目技术构建后台管理系统 一、技术要求二、安装pnpm2.1 构建vite三、项目配置3.1 eslint 配置3.2 prettier配置3.3 stylelint配置3.4 配置husky3.5 配置commitlint3.6 pnpm 强制安装四、Element-plus 引入4.1 完整引入4.2 国际化配置4.3 配置别名4.4 Env环境配置4.5 s…

教育与社会的发展

生产力与教育的关系 政治经济制度与教育的关系 文化和人口与教育的关系

《梦醒蝶飞:释放Excel函数与公式的力量》11.4 ISERROR函数

第11章&#xff1a;信息函数 第四节 11.4 ISERROR函数 11.4.1 简介 ISERROR函数是Excel中的一个信息函数&#xff0c;用于检查指定单元格或表达式是否产生错误。如果单元格或表达式产生任何类型的错误&#xff08;如N/A、VALUE!、REF!等&#xff09;&#xff0c;则返回TRUE&…