【Redis】Redis 分布式锁误删问题
本文主要介绍 Redis 分布式锁误删问题的解决
场景一
1. 问题的产生情况一
因为业务阻塞,导致别人的锁被误删
2. 解决思路
获取锁的时候存入标识,释放锁的时候判断标识是否一致,一致可以释放锁,不一致不释放锁。
3. 解决代码
总体思路:
- 获取锁的时候存入线程标识 , 用 UUID 表示 ()
- 释放锁的时候,判断标识是否一致
public class SimpleRedisLock implements ILock{// 锁的 key 前缀private static final String KEY_PREFIX = "lock:";// 线程 id 的前缀private static final String ID_PREFIX = UUID.randomUUID().toString() + "-";// 锁的名字private String lockName;// 传入的 StringRedisTemplateprivate StringRedisTemplate stringRedisTemplate;public SimpleRedisLock(String lockName, StringRedisTemplate stringRedisTemplate) {this.lockName = lockName;this.stringRedisTemplate = stringRedisTemplate;}@Overridepublic boolean tryLock(long timeoutSec) {// 获取当前线程标识String threadId = ID_PREFIX + Thread.currentThread().getId();// 获取锁Boolean success = stringRedisTemplate.opsForValue().setIfAbsent(KEY_PREFIX+lockName, threadId, timeoutSec, TimeUnit.SECONDS);return Boolean.TRUE.equals(success); // 防止自动拆箱时候出现空指针问题}@Overridepublic void unlock() {// 获取当前锁的线程 idString id = stringRedisTemplate.opsForValue().get(KEY_PREFIX + lockName);// 获取当前请求释放锁的线程 idString threadId = ID_PREFIX + Thread.currentThread().getId();// 判断两者是否一致,一致给释放锁if(threadId.equals(id)){stringRedisTemplate.delete(KEY_PREFIX + lockName);}}
}
场景二
1. 问题的产生情况二
获取锁标识并判断一致后被阻塞导致误删问题
2. 解决思路
保证判断锁标识一致和删除锁这一操作的原子性
- Redis 事务:
- 支持原子性,不支持一致性
- 批处理操作,最终一致性 (基于乐观锁)
- Lua 脚本
Redis 提供了 Lua 脚本功能,在一个脚本中编写多条 Reids 命令,保证多条命令执行的原子性
https://www.runoob.com/lua/lua-tutorial.html
Redis 调用函数:
redis.call('命令名称', 'key', '其他参数')
Redis 执行脚本的命令:
eval "脚本语句"
eval 支持带参数脚本:
eval "return redis.call('set', KEYS[1], ARGV[1])" 1 name Rose
等价于 set name Rose
3. 解决代码
SpringBoot 整合 Lua 脚本实现锁的释放
释放锁的 Lua 脚本:
-- 获取锁中的线程标识
local id = redis.call('get, KEYS[1])
-- Redis中存入的线程标识和传入的参数一致可以删除
if(id == ARGV[1]) thenreturn redis.call('del', KEYS[1])
end
return 0
Java 执行 Lua 脚本:
public class SimpleRedisLock implements ILock{// 锁的 key 前缀private static final String KEY_PREFIX = "lock:";// 线程 id 的前缀private static final String ID_PREFIX = UUID.randomUUID().toString() + "-";// 锁的名字private String lockName;// 传入的 StringRedisTemplateprivate StringRedisTemplate stringRedisTemplate;private static final DefaultRedisScript<Long> UNLOCK_SCRIPT;static {UNLOCK_SCRIPT = new DefaultRedisScript<>();// 设置脚本位置UNLOCK_SCRIPT.setLocation(new ClassPathResource("unlock.lua"));UNLOCK_SCRIPT.setResultType(Long.class);}public SimpleRedisLock(String lockName, StringRedisTemplate stringRedisTemplate) {this.lockName = lockName;this.stringRedisTemplate = stringRedisTemplate;}@Overridepublic boolean tryLock(long timeoutSec) {// 获取当前线程标识String threadId = ID_PREFIX + Thread.currentThread().getId();// 获取锁Boolean success = stringRedisTemplate.opsForValue().setIfAbsent(KEY_PREFIX+lockName, threadId, timeoutSec, TimeUnit.SECONDS);return Boolean.TRUE.equals(success); // 防止自动拆箱时候出现空指针问题}@Overridepublic void unlock() {stringRedisTemplate.execute(UNLOCK_SCRIPT, Collections.singletonList(KEY_PREFIX + lockName), ID_PREFIX + Thread.currentThread().getId());}
}
总结:
Redis 分布式锁实现思路:
- 利用 setnx 获取锁,设置过期时间,保存 value 为线程标识
- 释放锁时先判断线程标识是否一致,一致则删除锁
特性:
- setnx 保证互斥性
- 通过设置过期时间的方式,保证出现故障时锁仍然能释放,避免了死锁
- 利用 Redis 集群保证高可用性和并发现
【Redis】Redis 分布式锁误删问题相关推荐
- Redis:基于SETNX解决分布式锁误删问题
Redis:SETNX解决分布式锁误删问题 一.概述 二. 分布式锁(初级) (1)锁接口 (2)锁实现类+上锁 (3)释放锁 (4)存在的问题 三. 改进释放锁 (1)准备unlock.lua脚本 ...
- 《Redis官方文档》用Redis构建分布式锁
<Redis官方文档>用Redis构建分布式锁 用Redis构建分布式锁 在不同进程需要互斥地访问共享资源时,分布式锁是一种非常有用的技术手段. 有很多三方库和文章描述如何用Redis实现 ...
- 《Redis官方文档》用Redis构建分布式锁(悲观锁)
2019独角兽企业重金招聘Python工程师标准>>> **用Redis构建分布式锁 ** 在不同进程需要互斥地访问共享资源时,分布式锁是一种非常有用的技术手段. 有很多三方库和文章 ...
- Redis的分布式锁详解
一.什么是分布式锁: 1.什么是分布式锁: 分布式锁,即分布式系统中的锁.在单体应用中我们通过锁解决的是控制共享资源访问的问题,而分布式锁,就是解决了分布式系统中控制共享资源访问的问题.与单体应用不同 ...
- Redis构建分布式锁——Redlock
本文来自:http://ifeve.com/redis-lock/ 简介 在不同进程需要互斥地访问共享资源时,分布式锁是一种非常有用的技术手段. 有很多三方库和文章描述如何用Redis实现一个分布式锁 ...
- Redis 作者 Antirez 讲如何实现分布式锁?Redis 实现分布式锁天然的缺陷分析Redis分布式锁的正确使用姿势!...
Redis分布式锁基本原理 采用 redis 实现分布式锁,主要是利用其单线程命令执行的特性,一般是 setnx, 只会有一个线程会执行成功,也就是只有一个线程能成功获取锁:看着很完美. 然而-- 看 ...
- Redis实现分布式锁的7种方案
https://www.cnblogs.com/wangyingshuo/p/14510524.html 七种方案前言 日常开发中,秒杀下单.抢红包等等业务场景,都需要用到分布式锁.而Redis非常适 ...
- Redis实现分布式锁(SETNX)
目录 1.什么是分布式锁 2.分布式锁应具备的条件 3.为什么使用分布式锁 4.SETNX介绍 5.分布式锁实现 6.效果演示 7.Redisson分布式锁详解 8.Lua脚本实现可重入分布式锁 1. ...
- 基于 Redis 实现分布式锁思考
以下文章来源方志朋的博客,回复"666"获面试宝典 来源:blog.csdn.net/xuan_lu/article/details/111600302 分布式锁 基于redis实 ...
最新文章
- 用jackson封装的JSON工具类
- xml语法规则(一)
- SD-WAN的四个价值—Vecloud微云
- 网工协议基础(1) OSI七层模型
- iOS开发点击UIButton实现UIView的旋转
- 2021牛客多校6 - Defend Your Country(点双缩点求割点)
- 注入双括号报错注入_SQL手动注入:sqlilabs(less110)
- 从挂科学渣到史上学历最低诺奖得主,他用17年时间重新证明自己
- 1Password 7:Mac的密码管理工具
- 解决升级PHP7后 微信公众号收不到消息
- 百度地图 城市中心点坐标
- Android 知识点 250 —— screencap截屏指令
- 集美福利!陈睿当时加入B站的故事分享
- 阿里云安全组规则授权对象设置为固定IP段访问
- Auto.js Pro安卓免ROOT引流脚本开发系列教程23网易公开课(1)-前言
- 基于飞凌i.MX6Q-C核心板搭建3D相机
- Spark GraphX下强连通子图和社团发现算法在1T TPC-DS数据集下执行方法、优化和性能估算
- 使用windows引导的ubuntu双操作系统
- 20201022-成信大-C语言程序设计-20201学期《C语言程序设计B》C-trainingExercises26
- git提示please tell me who you are