|NO.Z.00052|——————————|BigDataEnd|——|Hadoop&Redis.V05|——|Redis.v05|乐观锁|分布式锁|Redisson.v02|
一、setnx
### --- 实现原理
~~~ 共享资源互斥
~~~ 共享资源串行化
~~~ # 单应用中使用锁:(单进程多线程)
~~~ synchronized、ReentrantLock
~~~ # 分布式应用中使用锁:(多进程多线程)
~~~ 分布式锁是控制分布式系统之间同步访问共享资源的一种方式。
~~~ 利用Redis的单线程特性对共享资源进行串行化处理
二、实现方式
### --- 获取锁
~~~ # 方式1(使用set命令实现)--推荐
/**
* 使用redis的set命令实现获取分布式锁
* @param lockKey 可以就是锁
* @param requestId 请求ID,保证同一性 uuid+threadID
* @param expireTime 过期时间,避免死锁
* @return
*/
public boolean getLock(String lockKey,String requestId,int expireTime) {
//NX:保证互斥性
// hset 原子性操作 只要lockKey有效 则说明有进程在使用分布式锁
String result = jedis.set(lockKey, requestId, "NX", "EX", expireTime);
if("OK".equals(result)) {
return true;
}
return false;
}
~~~ # 方式2(使用setnx命令实现) -- 并发会产生问题
public boolean getLock(String lockKey,String requestId,int expireTime) {
Long result = jedis.setnx(lockKey, requestId);
if(result == 1) {
//成功设置 进程down 永久有效 别的进程就无法获得锁
jedis.expire(lockKey, expireTime);
return true;
}
return false;
}
### --- 释放锁
~~~ # 方式1(del命令实现) -- 并发
/**
* 释放分布式锁
* @param lockKey
* @param requestId
*/
public static void releaseLock(String lockKey,String requestId) {
if (requestId.equals(jedis.get(lockKey))) {
jedis.del(lockKey);
}
}
~~~ # 问题在于如果调用jedis.del()方法的时候,
~~~ 这把锁已经不属于当前客户端的时候会解除他人加的锁。
~~~ # 那么是否真的有这种场景?答案是肯定的,
~~~ 比如客户端A加锁,一段时间之后客户端A解锁,在执行jedis.del()之前,
~~~ 锁突然过期了,此时客户端B尝试加锁成功,然后客户端A再执行del()方法,
~~~ 则将客户端B的锁给解除了。
~~~ # 方式2(redis+lua脚本实现)--推荐
public static boolean releaseLock(String lockKey, String requestId) {
String script = "if redis.call('get', KEYS[1]) == ARGV[1] then return redis.call('del', KEYS[1]) else return 0 end";
Object result = jedis.eval(script, Collections.singletonList(lockKey),Collections.singletonList(requestId));
if (result.equals(1L)) {
return true;
}
return false;
}
三、存在问题
### --- 存在问题
~~~ 单机:无法保证高可用
~~~ 主--从:无法保证数据的强一致性,在主机宕机时会造成锁的重复获得。

四、无法续租
### --- 无法续租
~~~ 超过expireTime后,不能继续使用
五、本质分析
### --- CAP模型分析
~~~ 在分布式环境下不可能满足三者共存,只能满足其中的两者共存,
~~~ 在分布式下P不能舍弃(舍弃P就是单机了)。
~~~ 所以只能是CP(强一致性模型)和AP(高可用模型)。
~~~ 分布式锁是CP模型,Redis集群是AP模型。 (base)
~~~ Redis集群不能保证数据的随时一致性,只能保证数据的最终一致性。
### --- 为什么还可以用Redis实现分布式锁?
~~~ 与业务有关
~~~ 当业务不需要数据强一致性时,比如:社交场景,就可以使用Redis实现分布式锁
~~~ 当业务必须要数据的强一致性,即不允许重复获得锁,
~~~ 比如金融场景(重复下单,重复转账)就不要使用可以使用CP模型实现,比如:zookeeper和etcd。
Walter Savage Landor:strove with none,for none was worth my strife.Nature I loved and, next to Nature, Art:I warm'd both hands before the fire of life.It sinks, and I am ready to depart
——W.S.Landor
分类:
bdv012-redis
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 记一次.NET内存居高不下排查解决与启示
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了
· DeepSeek 开源周回顾「GitHub 热点速览」