当前位置: 首页 > news >正文

4、Redis高并发分布式锁实战

引言

在分布式系统中,保证数据的一致性和避免竞争条件是至关重要的。分布式锁是一种常用的机制,而Redis作为一款高性能的内存数据库,提供了简单而强大的分布式锁方案。本文将深入探讨如何利用Redis高并发分布式锁来解决分布式系统中的并发控制问题,并提供实战案例。

正常库存扣减代码

public void deductStock(){int stock = Integer.parseInt(redisTemplate.opsForValue().get("stock"));if(stock>0){stock = stock -1 ;redisTemplate.opsForValue().set("stock",stock+"");System.out.println("扣减成功,剩余库存:"+stock);}else {System.out.println("扣减失败,库存不足");}
}
//弊端:两个线程同时执行读取stock为50,然后各自-1 修改为49,实际应该50-2=48

代码调整后

public void deductStock(){synchronized (this){int stock = Integer.parseInt(redisTemplate.opsForValue().get("stock"));if(stock>0){stock = stock -1 ;redisTemplate.opsForValue().set("stock",stock+"");System.out.println("扣减成功,剩余库存:"+stock);}else {System.out.println("扣减失败,库存不足");}}
}
//弊端:适用于单体项目,如果该项目被部署两台服务器,两台服务器同时访问获取stock为50,然后各自-1 修改为49,实际应该50-2=48 也会存在上述问题,因为synchronized只能在当前项目下生效

redis的一个简单的分布式锁

public void deductStock(){String lockKey = "lockKey";try {Boolean result = redisTemplate.opsForValue().setIfAbsent("lockKey", "nuoyi",10, TimeUnit.SECONDS);if(!result){System.out.println("....");return ;}int stock = Integer.parseInt(redisTemplate.opsForValue().get("stock"));if(stock>0){stock = stock -1 ;redisTemplate.opsForValue().set("stock",stock+"");System.out.println("扣减成功,剩余库存:"+stock);}else {System.out.println("扣减失败,库存不足");}}catch (Exception e){e.printStackTrace();}finally {redisTemplate.delete("lockKey");}
}
//弊端:适用于访问量不高的系统  如果访问量非常的大,第一个a请求获取到锁 ,设置过期10s,执行业务需要15s,a业务执行10s后锁自动过期被第二个请求b拿到并执行业务,当b业务执行到第5s时,b的锁被a的请求给释放了,如此高并发循环,导致锁失效

优化上述redis的分布式锁解决不是自己的锁不释放
 

public void deductStock(){String lockKey = "lockKey";String clientId = UUID.randomUUID().toString();try {Boolean result = redisTemplate.opsForValue().setIfAbsent("lockKey", clientId,10, TimeUnit.SECONDS);if(!result){System.out.println("....");return ;}int stock = Integer.parseInt(redisTemplate.opsForValue().get("stock"));if(stock>0){stock = stock -1 ;redisTemplate.opsForValue().set("stock",stock+"");System.out.println("扣减成功,剩余库存:"+stock);}else {System.out.println("扣减失败,库存不足");}}catch (Exception e){e.printStackTrace();}finally {//不是自己的锁不删除if(clientId.equals(redisTemplate.opsForValue().get(lockKey))){redisTemplate.delete("lockKey");}}
}
//不是自己的锁不删除,但是这个只是解决了a请求删除b请求的锁,如果a请求15秒锁第十秒过期了,b请求就进来了还是会有问题,解决方案:给锁续命

 Redisson代码
 

private final Redisson redisson;public void deductStock(){String lockKey = "lockKey";RLock redissonLock = redisson.getLock(lockKey);//获取锁try {redissonLock.lock();//加锁及锁续命   默认锁失效30s  守护线程每10s续命一次int stock = Integer.parseInt(redisTemplate.opsForValue().get("stock"));if(stock>0){stock = stock -1 ;redisTemplate.opsForValue().set("stock",stock+"");System.out.println("扣减成功,剩余库存:"+stock);}else {System.out.println("扣减失败,库存不足");}}catch (Exception e){e.printStackTrace();}finally {redissonLock.unlock();//释放锁}
}
//三行代码即可满足获取锁、锁续命、释放锁,完美解决上述redis的释放锁及锁续命问题  redisson的底层还是redis,使用了大量的lua脚本,lua脚本支持原子性

redisson配置
 

@Bean
public Redisson redisson(){Config config = new Config();//useSingleServer 单机版config.useSingleServer().setAddress("redis://"+instance.getRedisHost()+":"+instance.getRedisPort()).setDatabase(instance.getRedisDataBase());return (Redisson)Redisson.create(config);
}


 

lua脚本语言:

  • 减少网络开销(批量操作)

  • 原子性

  • 替代redis的事务
     

为什么redis不常使用lua?

因为Redis是个单线程,如果lua有耗时运算或循环,Redis则阻塞,不会管其他的操作

通过学习本文,读者将深入了解Redis分布式锁的原理和实践应用。分布式锁在构建高并发、分布式系统中发挥着关键作用,正确使用和理解分布式锁是确保系统稳定性和可靠性的重要一环。希望本文能为读者提供有益的指导和实战经验。

http://www.lryc.cn/news/281094.html

相关文章:

  • matlab subs 函数计算太慢
  • 如何确保网络传输的安全性和稳定性?
  • 鸿蒙应用开发学习:改进小鱼动画实现按键一直按下时控制小鱼移动和限制小鱼移出屏幕
  • 紫光展锐5G扬帆出海 | Blade系列勇当拉美5G先锋
  • 如何设计一个高并发系统?
  • 基于WebRTC技术的EasyRTC视频云服务系统在线视频客服解决方案
  • 黑马程序员——2022版软件测试——乞丐版——day04
  • uniapp微信小程序投票系统实战 (SpringBoot2+vue3.2+element plus ) -创建图文投票实现
  • Spring系列学习九、Spring MVC的使用
  • 开源内容管理系统Wagtail本地安装运行并结合内网穿透实现公网访问
  • 【蓝桥杯/DFS】路径之谜 (Java)
  • Go语言的内存分配器
  • Swift单元测试Quick+Nimble
  • 详解电源动态响应的测试方法及重要性 -纳米软件
  • 计算机网络系统结构-2020期末考试解析
  • 二叉树的遍历 Java
  • 数据结构之str类
  • Java电影购票小程序在线选座订票电影
  • 24-1-9 bilibilic++音视频
  • 备案(三)
  • Hotspot源码解析-第十九章-ClassLoaderData、符号表、字符串表的初始化
  • impala元数据自动刷新
  • 骑砍战团MOD开发(35)-射击精度系统
  • 树莓派非常实用的程序-3 vcdbg
  • jmeter分布式服务搭建
  • vue中el-radio无法默认选中
  • 分布式I/O应用于智慧停车场的方案介绍
  • node后端+vue前端实现接口请求时携带authorization验证
  • SourceTree管理git
  • 【数模百科】一篇文章讲清楚灰色预测模型GM(1,1)附python代码