问:你对Redis使用熟悉吗?Redis中是如何实现分布式锁的?
要点Redis要实现分布式锁,以下条件应该得到满足
互斥性
不能死锁
容错性
可以直接通过 set key value px milliseconds nx 命令实现加锁, 通过Lua脚本实现解锁。
//获取锁(unique_value可以是UUID等)
SETresource_nameunique_valueNXPX30000
//释放锁(lua脚本中,一定要比较value,防止误解锁)
ifredis.call("get",KEYS[1])==ARGV[1]then
returnredis.call("del",KEYS[1])
else
return0
end
代码解释
加锁代码分析
首先,set()加入了NX参数,可以保证如果已有key存在,则函数不会调用成功,也就是只有一个客户端能持有锁,满足互斥性。其次,由于我们对锁设置了过期时间,即使锁的持有者后续发生崩溃而没有解锁,锁也会因为到了过期时间而自动解锁(即key被删除),不会发生死锁。最后,因为我们将value赋值为requestId,用来标识这把锁是属于哪个请求加的,那么在客户端在解锁的时候就可以进行校验是否是同一个客户端。
解锁代码分析
将Lua代码传到jedis.eval()方法里,并使参数KEYS[1]赋值为lockKey,ARGV[1]赋值为requestId。在执行的时候,首先会获取锁对应的value值,检查是否与requestId相等,如果相等则解锁(删除key)。
存在的风险
如果存储锁对应key的那个节点挂了的话,就可能存在丢失锁的风险,导致出现多个客户端持有锁的情况,这样就不能实现资源的独享了。
这个场景是假设有一个 redis cluster,有 5 个 redis master 实例。然后执行如下步骤获取一把锁:
Redis 官方给出了以上两种基于 Redis 实现分布式锁的方法,详细说明可以查看:
Redissonhttps://redis.io/topics/distlock 。
Redisson是一个在Redis的基础上实现的Java驻内存数据网格(In-Memory Data Grid)。它不仅提供了一系列的分布式的Java常用对象,还实现了可重入锁(Reentrant Lock)、公平锁(Fair Lock、联锁(MultiLock)、 红锁(RedLock)、 读写锁(ReadWriteLock)等,还提供了许多分布式服务。
Redisson提供了使用Redis的最简单和最便捷的方法。Redisson的宗旨是促进使用者对Redis的关注分离(Separation of Concern),从而让使用者能够将精力更集中地放在处理业务逻辑上。
Redisson 分布式重入锁用法
Redisson 支持单点模式、主从模式、哨兵模式、集群模式,这里以单点模式为例:
//1.构造redisson实现分布式锁必要的Config
Configconfig=newConfig();
config.useSingleServer().setAddress("redis://127.0.0.1:5379").setPassword("123456").setDatabase(0);
//2.构造RedissonClient
RedissonClientredissonClient=Redisson.create(config);
//3.获取锁对象实例(无法保证是按线程的顺序获取到)
RLockrLock=redissonClient.getLock(lockKey);
try{
/**
*4.尝试获取锁
*waitTimeout尝试获取锁的最大等待时间,超过这个值,则认为获取锁失败
*leaseTime锁的持有时间,超过这个时间锁会自动失效(值应设置为大于业务处理的时间,确保在锁有效期内业务能处理完)
*/
booleanres=rLock.tryLock((long)waitTimeout,(long)leaseTime,TimeUnit.SECONDS);
if(res){
//成功获得锁,在这里处理业务
}
}catch(Exceptione){
thrownewRuntimeException("aquirelockfail");
}finally{
//无论如何,最后都要解锁
rLock.unlock();
}
加锁流程图
解锁流程图
我们可以看到,RedissonLock是可重入的,并且考虑了失败重试,可以设置锁的最大等待时间, 在实现上也做了一些优化,减少了无效的锁申请,提升了资源的利用率。
需要特别注意的是,RedissonLock 同样没有解决 节点挂掉的时候,存在丢失锁的风险的问题。而现实情况是有一些场景无法容忍的,所以 Redisson 提供了实现了redlock算法的 RedissonRedLock,RedissonRedLock 真正解决了单点失败的问题,代价是需要额外的为 RedissonRedLock 搭建Redis环境。
所以,如果业务场景可以容忍这种小概率的错误,则推荐使用 RedissonLock, 如果无法容忍,则推荐使用 RedissonRedLock。
最后需要大厂精选面试题及答案、Java架构师的学习资料及学习视频的程序员朋友可以 【关注 转发 】 之后私信回复【资料】即可免费领取得到,记得要转发关注后再私信哈!!!
(文末福利:马士兵大佬网约车项目实战白皮书)
高级开发架构学习资料源码实战书籍
中高级架构视频全套视频文中提及内容获取方式:转发 关注后,私信【资料】免费获取!
大厂面试宝典转发 关注后,私信我【资料】免费获取架构视频,大厂面试攻略,高清架构学习视频以及马大佬的网约车项目实战文档~
网约车项目Copyright © 2024 妖气游戏网 www.17u1u.com All Rights Reserved