Redis分布式锁解决超卖问题

本文涉及的产品
Redis 开源版,标准版 2GB
推荐场景:
搭建游戏排行榜
云数据库 Tair(兼容Redis),内存型 2GB
简介: Redis分布式锁解决超卖问题

1、三种分布式锁实现方式对比:

1、数据库分布式锁实现缺点:

1)db操作性能较差,且有锁表的风险;

2)非阻塞操作失败后,需要轮询,占用cpu资源;

3)长时间不commit或者长时间轮询,可能会占用较多连接资源。

2、ZK分布式锁实现缺点:

性能不如redis,因为其写操作(获取锁释放锁)都需要在Leader上执行,然后同步到follower。

3、Redis(缓存)分布式锁实现缺点:

1)过期时间不好控制;

2)非阻塞,操作失败后,需要轮询,占用cpu资源;

2、使用原生redis实现

使用原生Redis的SetNX+Expire实现的分布式锁。

//方案1 setnx
String lockKey = "zhyRedis";
   //通过val,给锁设置唯一id,防止其他线程删除锁
String clientId = UUID.randomUUID().toString();  //或者雪花生成位置ID
boolean result = redisTemplate.opsForValue().setIfAbsent(lockKey, clientId, 10, TimeUnit.SECONDS); 
  // redisTemplate.expire(lockKey,10,TimeUnit.SECONDS) //旧版本redis(新版直接设置在后面,如上)
  //如果获取不到锁,则返回失败
if(!result){
    result "failed";
}
try {
 //如果能获取到锁,则返回成功
 Integer count = Integer.parseInt(redisTemplate.opsForValue.get("count").toString());
 if (count > 0) {
  Integer realCount = count - 1;
  System.out.Println("购买成功,剩余库存:" + realCount.toString());
  redisTemplate.opsForValue().set("count",realCount.toString());
 }else{
  System.out.Println("购买失败,库存不足");
 }
} catch(Exception e){
 e.printStackTrace();
  return "failed";
} finally{
  //解锁
  //判断当前客户端id与redis分布式中持有的客户端id一致,才能删除锁
 if(clientId.equals(redisTemplate.opsForValue().get(lockKey))){
   redisTemplate.delete(lockKey)
 }
}

3、使用redisson实现

相较于原生Redis的SetNX+Expire实现的分布式锁而言,Redisson的分布式锁组件可以解决原生Redis组合命令带来的一些缺陷,即redis的超时时间值不知道设置为多少才合适。如果此时Redis的服务器节点恰好出现宕机或者服务不能用的情况,那将会导致相应的Key永远存于缓存中,即处于所谓的“永久被锁死”的状态!

底层的实现机制在于:Redisson内部提供了一个监控锁的看门狗WatchDog,其作用在于Redis实例被关闭之前,不断延长锁的有效期。

除此之外,Redisson还通过加锁的方法提供了leaseTime等参数来指定加锁的有效时间,即超过这个时间后“锁”便自动解开了。

//方案2 redisson
String lockKey = "zhyRedis";
RLock rLock = redisson.getLock(lockKey);
try {
 rLock.lock(10, TimeUnit.SECONDS)
 //如果能获取到锁,则返回成功
 Integer count = Integer.parseInt(redisTemplate.opsForValue.get("count").toString());
 if (count > 0) {
  Integer realCount = count - 1;
  System.out.Println("购买成功,剩余库存:" + realCount.toString());
  redisTemplate.opsForValue().set("count",realCount.toString());
 }else{
  System.out.Println("购买失败,库存不足");
 }
} catch(Exception e){
 e.printStackTrace();
 return "failed";
} finally{
 //解锁
 rLock.unlock();
}
相关实践学习
基于Redis实现在线游戏积分排行榜
本场景将介绍如何基于Redis数据库实现在线游戏中的游戏玩家积分排行榜功能。
云数据库 Redis 版使用教程
云数据库Redis版是兼容Redis协议标准的、提供持久化的内存数据库服务,基于高可靠双机热备架构及可无缝扩展的集群架构,满足高读写性能场景及容量需弹性变配的业务需求。 产品详情:https://www.aliyun.com/product/kvstore     ------------------------------------------------------------------------- 阿里云数据库体验:数据库上云实战 开发者云会免费提供一台带自建MySQL的源数据库 ECS 实例和一台目标数据库 RDS实例。跟着指引,您可以一步步实现将ECS自建数据库迁移到目标数据库RDS。 点击下方链接,领取免费ECS&RDS资源,30分钟完成数据库上云实战!https://developer.aliyun.com/adc/scenario/51eefbd1894e42f6bb9acacadd3f9121?spm=a2c6h.13788135.J_3257954370.9.4ba85f24utseFl
相关文章
|
1月前
|
NoSQL Java 中间件
【📕分布式锁通关指南 02】基于Redis实现的分布式锁
本文介绍了从单机锁到分布式锁的演变,重点探讨了使用Redis实现分布式锁的方法。分布式锁用于控制分布式系统中多个实例对共享资源的同步访问,需满足互斥性、可重入性、锁超时防死锁和锁释放正确防误删等特性。文章通过具体示例展示了如何利用Redis的`setnx`命令实现加锁,并分析了简化版分布式锁存在的问题,如锁超时和误删。为了解决这些问题,文中提出了设置锁过期时间和在解锁前验证持有锁的线程身份的优化方案。最后指出,尽管当前设计已解决部分问题,但仍存在进一步优化的空间,将在后续章节继续探讨。
478 131
【📕分布式锁通关指南 02】基于Redis实现的分布式锁
|
1月前
|
NoSQL Java Redis
Springboot使用Redis实现分布式锁
通过这些步骤和示例,您可以系统地了解如何在Spring Boot中使用Redis实现分布式锁,并在实际项目中应用。希望这些内容对您的学习和工作有所帮助。
173 83
|
27天前
|
缓存 NoSQL 搜索推荐
【📕分布式锁通关指南 03】通过Lua脚本保证redis操作的原子性
本文介绍了如何通过Lua脚本在Redis中实现分布式锁的原子性操作,避免并发问题。首先讲解了Lua脚本的基本概念及其在Redis中的使用方法,包括通过`eval`指令执行Lua脚本和通过`script load`指令缓存脚本。接着详细展示了如何用Lua脚本实现加锁、解锁及可重入锁的功能,确保同一线程可以多次获取锁而不发生死锁。最后,通过代码示例演示了如何在实际业务中调用这些Lua脚本,确保锁操作的原子性和安全性。
60 6
【📕分布式锁通关指南 03】通过Lua脚本保证redis操作的原子性
|
1月前
|
缓存 NoSQL 中间件
Redis,分布式缓存演化之路
本文介绍了基于Redis的分布式缓存演化,探讨了分布式锁和缓存一致性问题及其解决方案。首先分析了本地缓存和分布式缓存的区别与优劣,接着深入讲解了分布式远程缓存带来的并发、缓存失效(穿透、雪崩、击穿)等问题及应对策略。文章还详细描述了如何使用Redis实现分布式锁,确保高并发场景下的数据一致性和系统稳定性。最后,通过双写模式和失效模式讨论了缓存一致性问题,并提出了多种解决方案,如引入Canal中间件等。希望这些内容能为读者在设计分布式缓存系统时提供有价值的参考。感谢您的阅读!
131 6
Redis,分布式缓存演化之路
|
2月前
|
SQL Java 关系型数据库
【📕分布式锁通关指南 01】从解决库存超卖开始加锁的初体验
本文通过电商场景中的库存超卖问题,深入探讨了JVM锁、MySQL悲观锁和乐观锁的实现及其局限性。首先介绍了单次访问下库存扣减逻辑的正常运行,但在高并发场景下出现了超卖问题。接着分析了JVM锁在多例模式、事务模式和集群模式下的失效情况,并提出了使用数据库锁机制(如悲观锁和乐观锁)来解决并发问题。 悲观锁通过`update`语句或`select for update`实现,能有效防止超卖,但存在锁范围过大、性能差等问题。乐观锁则通过版本号或时间戳实现,适合读多写少的场景,但也面临高并发写操作性能低和ABA问题。 最终,文章强调没有完美的方案,只有根据具体业务场景选择合适的锁机制。
73 12
【📕分布式锁通关指南 01】从解决库存超卖开始加锁的初体验
|
3月前
|
存储 NoSQL Java
使用lock4j-redis-template-spring-boot-starter实现redis分布式锁
通过使用 `lock4j-redis-template-spring-boot-starter`,我们可以轻松实现 Redis 分布式锁,从而解决分布式系统中多个实例并发访问共享资源的问题。合理配置和使用分布式锁,可以有效提高系统的稳定性和数据的一致性。希望本文对你在实际项目中使用 Redis 分布式锁有所帮助。
279 5
|
4月前
|
NoSQL Java 数据处理
基于Redis海量数据场景分布式ID架构实践
【11月更文挑战第30天】在现代分布式系统中,生成全局唯一的ID是一个常见且重要的需求。在微服务架构中,各个服务可能需要生成唯一标识符,如用户ID、订单ID等。传统的自增ID已经无法满足在集群环境下保持唯一性的要求,而分布式ID解决方案能够确保即使在多个实例间也能生成全局唯一的标识符。本文将深入探讨如何利用Redis实现分布式ID生成,并通过Java语言展示多个示例,同时分析每个实践方案的优缺点。
137 8
|
NoSQL Redis 数据库
用redis实现分布式锁时容易踩的5个坑
云栖号资讯:【点击查看更多行业资讯】在这里您可以找到不同行业的第一手的上云资讯,还在等什么,快来! 近有不少小伙伴投入短视频赛道,也出现不少第三方数据商,为大家提供抖音爬虫数据。 小伙伴们有没有好奇过,这些数据是如何获取的,普通技术小白能否也拥有自己的抖音爬虫呢? 本文会全面解密抖音爬虫的幕后原理,不需要任何编程知识,还请耐心阅读。
用redis实现分布式锁时容易踩的5个坑
|
NoSQL Java 关系型数据库
浅谈Redis实现分布式锁
浅谈Redis实现分布式锁
|
存储 canal 缓存

热门文章

最新文章