Redis分布式锁在项目中的实现方法——小布

122 阅读2分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第26天,点击查看活动详情

轮回.jpg

什么是分布式锁

分布式锁可以理解为:控制分布式系统有序的去对共享资源进行操作,通过互斥来保持一致性。

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^)~~~