redis的常见部署方式:
1.单机 单点问题
2.mster-slave 读写分离,不能切换
3.哨兵 哨兵模式 通过哨兵监控节点,主节点宕机自动切换slave为master
4.cluster 基于槽点16348个槽点 多主多从,组合形成
Redis分布式锁要保证的几个方面:
1.互斥性
2.不能死锁
3.大多数节点正常,锁不能丢失。
分布式锁的实现方案:
1.可以直接通过 set key value px milliseconds nx
命令实现加锁, 通过Lua脚本实现解锁
存在的风险,锁所在的节点发生宕机,导致锁会丢失的。
2.Redission 实现
Redission在Redis的基础上实现Java驻内存数据网格。提供了一系列的分布式的Java常用对象,重入锁,读写锁,公平锁,红锁,还提供了很多的分布式服务。Redission提供了使用Redis的最简单和便捷的方式。
/ 1.构造redisson实现分布式锁必要的Config Config config = new Config(); config.useSingleServer().setAddress("redis://127.0.0.1:5379").setPassword("123456").setDatabase(0); // 2.构造RedissonClient RedissonClient redissonClient = Redisson.create(config); // 3.获取锁对象实例(无法保证是按线程的顺序获取到) RLock rLock = redissonClient.getLock(lockKey); try { /** * 4.尝试获取锁 * waitTimeout 尝试获取锁的最大等待时间,超过这个值,则认为获取锁失败 * leaseTime 锁的持有时间。
*/ boolean res = rLock.tryLock((long)waitTimeout, (long)leaseTime, TimeUnit.SECONDS); if (res) { //成功获得锁,在这里处理业务 } } catch (Exception e) { throw new RuntimeException("aquire lock fail"); }finally{ //无论如何, 最后都要解锁 rLock.unlock(); }
获取锁成功就会开启一个定时任务,也就是watchdog
,定时任务会定期检查去续期renewExpirationAsync(threadId),避免业务执行时间大于锁的超时时间,业务没有执行完成锁已经释放。
RedissionLock同样没有解决节点挂掉的问题,存在丢失锁的问题。RedissonRedLock 真正解决了单点失败的问题,代价是需要额外的为 RedissonRedLock 搭建Redis环境。
3.RedissonRedLock 算法
假设一个redis cluster有5个master节点。
1.获取当前时间戳,单位是毫秒
2.和上面set的方式相似,在每个master节点创建锁,过期时间较短,一般几十毫秒。
3.尝试在大多数节点上获取锁,比如总共五个节点就要三个。
4.客户端计算好获取锁的时间,如果客户端获取锁的时间小于超时时间,就算获取成功了。
5.如果锁获取失败,则要依次把之前的锁删掉。
6.主要别人建立一把分布式锁,那你就得不断轮询去获取锁。
来源:oschina
链接:https://my.oschina.net/u/3126880/blog/4713138