Redis实战---分布式锁

1. 什么是Redis分布式锁?

        分布式锁,顾名思义,就是分布式系统中使用的锁,在单体应用中我们使用synchronized、ReentrantLock来解决线程时间的共享资源的访问问题,而在分布式系统中,资源贡献问题已经由线程之间的竞争演变到了进程之间的竞争,分布式锁就是接近分布式系统中多进程之间的共享资源的访问问题。

2. Redis分布式锁的作用

  • 互斥性:在同一时间只允许一个进程或线程获取锁。
  • 防死锁:锁具有超时机制,避免因为进程或线程意外中断导致锁一直被占用而无法释放。
  • 高可用性:Redis 分布式锁可以使用 Redis 集群或者 Redis Sentinel 进行部署,保证了高可用性和可扩展性。
  • 高性能:使用 Redis 自带的原子操作实现锁的获取和释放,具有高性能和高并发性。

3. 场景案例

秒杀场景是一个非常经典且需要使用分布式锁的应用场景。在秒杀过程中,多个用户会在同一时间尝试购买有限数量的商品,确保商品库存的正确更新和避免超卖至关重要。通过 Redis 的分布式锁,可以实现对商品库存的安全访问。

秒杀场景的实现

假设有一个商品限时秒杀活动,商品数量有限,多个用户同时尝试购买该商品。我们需要确保在同一时刻只有一个用户能够访问和修改商品的库存信息,以防止超卖。

4. 代码实现

4.1 未加任何锁

4.1.1 数据准备

这里使用的MySql数据库模拟我们要秒杀的商品数量为200。

4.1.2 未加锁的业务逻辑代码

@Service
public class StockService {@Autowiredprivate StockDao stockDao;public String decrement(Integer productid) {// 根据id查询商品的库存int num = stockDao.findById(productid);if (num > 0) {// 修改库存stockDao.update(productid);System.out.println("商品编号为:" + productid + "的商品库存剩余:" + (num - 1) + "个");return "商品编号为:" + productid + "的商品库存剩余:" + (num - 1) + "个";} else {System.out.println("商品编号为:" + productid + "的商品库存不足。");return "商品编号为:" + productid + "的商品库存不足。";}}
}

上述是根据我们的业务进行的一个简单的实现,在这个实现里,未对代码进行加锁。如果在并发请求的时候,这段代码将会出现很经典的超卖问题

4.1.3 接口压测,模拟并发情况

让我们来压测一下接口,看一下对应的效果

我们发送了100个请求在1s的时间里,让我们来一起看看结果

4.1.4 压测结果

4.1.5 压测问题

  • 我们发现,100个请求进来之后,如果是正常的情况下,是应该减少20个库存,剩下的应该是没有抢到
  • 可以根据结果看,我们的100个请求获得了43个商品。同一个商品卖给了多个用户。列如 195号商品同时卖给了多个人。
  • 那么我们该如何去解决这个问题呢?

5. 单机情况下JVM级别加锁

首先我们来看一下,如果是单机(项目只部署在一台机器上),使用 synchronized 进行jvm级别加锁,解决上述问题。

5.1 代码加锁

@Service
public class StockService {@Autowiredprivate StockDao stockDao;private final Object lock = new Object();public String decrement(Integer productid) {synchronized (lock) {// 根据id查询商品的库存int num = stockDao.findById(productid);if (num > 0) {// 修改库存stockDao.update(productid);System.out.println("商品编号为:" + productid + "的商品库存剩余:" + (num - 1) + "个");return "商品编号为:" + productid + "的商品库存剩余:" + (num - 1) + "个";} else {System.out.println("商品编号为:" + productid + "的商品库存不足。");return "商品编号为:" + productid + "的商品库存不足。";}}}
}

使用 synchronized 关键字,将我们的业务逻辑进行包裹即可。

5.2 查看结果

从结果上来看,通过synchronized 可以在jvm级别上进行上锁。但是我们实际的生产环境中,很少有部署单机服务的。如果我们部署了多个服务,那么通过synchronized 是肯定无法影响另一条机器上的请求的。

6. 集群模式

上面使用syn和lock虽然解决了并发问题,但是我们未来项目部署时可能要部署集群模式。

开启多服务

nginx代理集群

通过压测发现本地锁 无效了。使用redis解决分布式锁文件

代码

@Service
public class StockService {@Autowiredprivate StockDao stockDao;@Autowiredprivate StringRedisTemplate redisTemplate;//public String decrement(Integer productid) {ValueOperations<String, String> opsForValue = redisTemplate.opsForValue();//1.获取共享锁资源Boolean flag = opsForValue.setIfAbsent("product::" + productid, "1111", 30, TimeUnit.SECONDS);//表示获取锁成功if(flag) {try {//根据id查询商品的库存int num = stockDao.findById(productid);if (num > 0) {//修改库存stockDao.update(productid);System.out.println("商品编号为:" + productid + "的商品库存剩余:" + (num - 1) + "个");return "商品编号为:" + productid + "的商品库存剩余:" + (num - 1) + "个";} else {System.out.println("商品编号为:" + productid + "的商品库存不足。");return "商品编号为:" + productid + "的商品库存不足。";}}finally {//释放锁资源redisTemplate.delete("product::"+productid);}}else{//休眠100毫秒 在继续抢锁try {Thread.sleep(100);} catch (InterruptedException e) {throw new RuntimeException(e);}return decrement(productid);}}
}

redis超时问题[业务代码执行时间超过了上锁时间]. 第三方redisson

引入redisson依赖<!--①依赖--><dependency><groupId>org.redisson</groupId><artifactId>redisson</artifactId><version>3.24.3</version></dependency>
@Configuration
public class RedissonConfig {@Beanpublic RedissonClient redisson(){Config config = new Config();
//        //连接的为redis集群
//        config.useClusterServers()
//                // use "rediss://" for SSL connection
//                .addNodeAddress("redis://127.0.0.1:7181","","","")
//        ;//连接单机config.useSingleServer().setAddress("redis://192.168.111.188:6379");RedissonClient redisson = Redisson.create(config);return redisson;}
}
@Service
public class StockService {@Autowiredprivate StockDao stockDao;@Autowiredprivate RedissonClient redisson;//public String decrement(Integer productid) {RLock lock = redisson.getLock("product::" + productid);lock.lock();try {//根据id查询商品的库存: 提前预热到redis缓存中int num = stockDao.findById(productid);if (num > 0) {//修改库存---incr---定时器[redis  数据库同步]stockDao.update(productid);System.out.println("商品编号为:" + productid + "的商品库存剩余:" + (num - 1) + "个");return "商品编号为:" + productid + "的商品库存剩余:" + (num - 1) + "个";} else {System.out.println("商品编号为:" + productid + "的商品库存不足。");return "商品编号为:" + productid + "的商品库存不足。";}}finally {lock.unlock();}}
}

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

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

相关文章

【Ubuntu】安装 Snipaste 截图软件

Snipaste 下载安装并使用 Snipastefor more information报错解决方案每次启动软件需要输入的命令如下添加开机自启动 下载 下载地址 安装并使用 Snipaste 进入终端输入命令 # 1、进入到 Snipaste-2.8.9-Beta-x86_64.AppImage 所在目录&#xff08;根据自己的下载目录而定&…

Corsearch 用 ClickHouse 替换 MySQL 进行内容和品牌保护

本文字数&#xff1a;3357&#xff1b;估计阅读时间&#xff1a;9 分钟 作者&#xff1a;ClickHouse Team 本文在公众号【ClickHouseInc】首发 Chase Richards 自 2011 年在初创公司 Marketly 担任工程负责人&#xff0c;直到 2020 年公司被收购。他现在是品牌保护公司 Corsear…

JAVA笔记十六

十六、异常Exception 1.概念 异常&#xff1a;非正常情况&#xff0c;包括空的引用、数组下标越界、内存溢出等 Java提供了异常对象描述这类异常情况。 Java提供了异常机制来进行处理&#xff0c;通过异常机制来处理程序运行期间出现的错误&#xff0c;可以更好地提升程序的…

波特率和比特率的区别联系【理解】

波特率&#xff08;Baud rate&#xff09;&#xff1a;表示单位时间内载波调制状态变化的次数 &#xff0c;单位为波特(Baud)&#xff1b; 【值得注意的是】单位“波特”本身就已经是代表每秒的调制数&#xff0c;不能用“波特每秒”&#xff08;Baud per second&#xff09;为…

MySQL练手 --- 1141. 查询近30天活跃用户数

题目链接&#xff1a;1141. 查询近30天活跃用户数 思路&#xff1a; 题目要求&#xff1a;统计截至 2019-07-27&#xff08;包含2019-07-27&#xff09;&#xff0c;近 30 天的每日活跃用户数&#xff08;当天只要有一条活动记录&#xff0c;即为活跃用户&#xff09; 要计算…

react中简单的配置路由

1.安装react-router-dom npm install react-router-dom 2.新建文件 src下新建page文件夹&#xff0c;该文件夹下新建login和index文件夹用于存放登录页面和首页&#xff0c;再在对应文件夹下分别新建入口文件index.js&#xff1b; src下新建router文件用于存放路由配置文件…

「Ant Design」Antd 中卡片如何完全不展示内容区域、按需展示内容区域、不展示标题

前言 下面是默认的 Antd 卡片&#xff0c;由以下区域组成 处理 Antd 的 Card 展示形式大致有下面三种 卡片完全不展示内容区域 const App () > (<Card title"Default size card" extra{<a href"#">More</a>} style{{ width: 300 }}b…

nginx的学习(二):负载均衡和动静分离

简介 nginx的负载均衡和动静分离的简单使用 负载均衡配置 外部访问linux的ip地址:80/edu/a.html地址&#xff0c;会轮询访问Tomcat8080和Tomcat8081服务。 Tomcat的准备 准备两个Tomcat&#xff0c;具体准备步骤在nginx的学习一的反向代理例子2中&#xff0c;在Tomcat8080…

崖山异构数据库迁移利器YMP初体验-Oracle迁移YashanDB

前言 首届YashanDB「迁移体验官」开放后&#xff0c;陆续收到「体验官」们的投稿&#xff0c;小崖在此把优秀的投稿文章分享给大家~今天分享的用户文章是《崖山异构数据库迁移利器YMP初体验-Oracle迁移YashanDB》&#xff08;作者&#xff1a;小草&#xff09;&#xff0c;满满…

让你的程序有记忆功能。

目录 环境 代码 环境 大语言模型&#xff1a; gpt-40-mini Mem0: Empower your AI applications with long-term memory and personalization OpenAPI-Key: Mem0-Key&#xff1a; 代码 import osfrom dotenv import load_dotenv from openai import OpenAI from m…

网络安全领域五大注入攻击类型介绍

在网络安全领域&#xff0c;注入攻击是一种常见的攻击方式&#xff0c;攻击者通过向应用程序发送恶意数据来操控应用程序的行为。以下跟随博主通过具体样例一起来掌握以下五种知名的注入攻击类型。 1. SQL注入&#xff08;SQL Injection&#xff09; 1.1. 概述 SQL注入是最常见…

OAuth2 + Gateway统一认证一步步实现(公司项目能直接使用),密码模式授权码模式

文章目录 认证的具体实现环境的搭建基础版授权服务搭建引入依赖创建数据表yml配置配置SpringSecurity定义认证授权的配置类授权服务器存储客户端信息修改授权服务配置&#xff0c;支持密码模式 基础版授权服务测试授权码模式测试密码模式测试**测试校验token接口** 整合JWT使用…

内网对抗-隧道技术篇防火墙组策略FRPNPSChiselSocks代理端口映射C2上线

知识点&#xff1a; 1、隧道技术篇-传输层-工具项目-Frp&Nps&Chisel 2、隧道技术篇-传输层-端口转发&Socks建立&C2上线Frp Frp是专注于内网穿透的高性能的反向代理应用&#xff0c;支持TCP、UDP、HTTP、HTTPS等多种协议。可以将内网服务以安全、便捷的方式通过…

探索算法系列 - 滑动窗口

目录 长度最小的子数组&#xff08;原题链接&#xff09; 无重复字符的最长子串&#xff08;原题链接&#xff09; 最大连续1的个数 III&#xff08;原题链接&#xff09; 将 x 减到 0 的最小操作数&#xff08;原题链接&#xff09; 水果成篮&#xff08;原题链接&#x…

首个卫星影像全球一张图发布

数据是GIS的血液&#xff01; 我们在《如何加载卫星影像全国一张图》一文中&#xff0c;为你分享过加载卫星影像全国一张图的方法。 现在用该方法&#xff0c;你已经可以加载卫星影像全球一张图了&#xff01; 如何查看全球卫星影像 为了一睹为快&#xff0c;你可以打开以下…

14 集合运算符和矩阵乘法运算符@

集合的交集、并集、对称差集等运算借助于位运算符来实现&#xff0c;而差集则使用减号运算符实现。 print({1, 2, 3} | {3, 4, 5}) # 并集&#xff0c;自动去除重复元素 print({1, 2, 3} & {3, 4, 5}) # 交集 print({1, 2, 3} - {3, 4, 5}) # 差集 print({1, 2, 4, 6, …

Pandas Series对象的创建和基本使用(Pandas Series Object)

pandas是Python的一个第三方数据分析库&#xff0c;其集成了大量的数据模型和分析工具&#xff0c;可以方便的处理和分析各类数据。Pandas中主要对象类型有Series&#xff0c;DataFrame和Index。本文介绍Series对象的创建和基本用法。 文章目录 一、Series对象的创建1.1 通过序…

使用netty编写syslog日志接收服务端

使用netty编写syslog日志接收服务端 1.添加netty依赖 <dependency><groupId>io.netty</groupId><artifactId>netty-all</artifactId><version>4.1.72.Final</version> <!-- 版本号可能需要根据实际情况更新 --></dependenc…

Docker Desktop安装(通俗易懂)

1、官网 https://www.docker.com/products/docker-desktop/ 2、阿里云镜像 docker-toolbox-windows-docker-for-windows安装包下载_开源镜像站-阿里云 1. 双击安装文件勾选选项 意思就是&#xff1a; Use WSL 2 instead of Hyper-V (recommended) : 启用虚拟化&#xff0c;…