持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第26天,点击查看活动详情
什么是分布式锁
分布式锁可以理解为:控制分布式系统有序的去对共享资源进行操作,通过互斥来保持一致性。
redis 分布式锁,其实需要自己不断去尝试获取锁,比较消耗性能。 zk 分布式锁,获取不到锁,注册个监听器即可,不需要不断主动尝试获取锁,性能开销较小。 另外一点就是,如果是 redis 获取锁的那个客户端 出现 bug 挂了,那么只能等待超时时间之后才能释放锁;而 zk 的话,因为创建的是临时 znode,只要客户端挂了,znode 就没了,此时就自动释放锁。
redis 分布式锁大家没发现好麻烦吗?遍历上锁,计算时间等等…zk 的分布式锁语义清晰实现简单。
所以先不分析太多的东西,就说这两点,我个人实践认为 zk 的分布式锁比 redis 的分布式锁牢靠、而且模型简单易用。
实现原理
-
互斥性
-
安全性
-
避免死锁
-
保证加锁和解锁操作是原子性操作
使用redis实现分布式锁
java代码如下:
public RedisLock(RedisTemplate redisTemplate) {
this.redisTemplate = redisTemplate;
lockOperation = redisTemplate.opsForValue();
unlockLuaScript = new DefaultRedisScript<>(UNLOCK_LUA_SCRIPT, Long.class);
}
public void lock(String value) {
for(; ;) {
if (lockOperation.setIfAbsent(KEY, value, TIMEOUT)) {
uniqueKey.set(value);
return;
}
}
}
/**
* 自旋锁
*/
@Override
public void lock() {
for(; ;) {
if (tryLock()) {
return;
}
}
}
@Override
public void lockInterruptibly() throws InterruptedException {
}
@Override
public boolean tryLock() {
// TODO 使用雪花算法生成分布式唯一id
String uuid = UUID.randomUUID().toString();
if (lockOperation.setIfAbsent(KEY, uuid, TIMEOUT)) {
uniqueKey.set(uuid);
return true;
}
return false;
}
@Override
public boolean tryLock(long time, TimeUnit unit) throws InterruptedException {
return false;
}
@Override
public void unlock() {
redisTemplate.execute(unlockLuaScript, Arrays.asList(KEY), uniqueKey.get());
uniqueKey.remove();
}
@Override
public Condition newCondition() {
return null;
}
会出现的问题 在redis server是单机的情况下,该代码不会出现问题;但是当redis是集群部署的时候,redis主从节点的数据同步是异步的,如果redis的master节点在锁未同步到slave节点的时候宕机了?会出现什么情况,举个例子。
1、进程A在master节点获得了锁。
2、在锁同步到slave之前,master宕机,数据还没有同步到slave。
3、slave变成了新的master节点。
4、进程B也得到了和进程A相同的锁
因此,如果业务上使用该锁,应该允许在master宕机期间,多个客户端同时持有锁。
以上就是本人对于Redis分布式锁使用的个人见解,今天的分享就到这,我们下期再见😀~~~///(^v^)~~~