分布式锁实现

2020-09-25  本文已影响0人  飞翃荷兰人

1 基本的实现方式

分布式锁的主要实现方式主要有以下几种:mysql,zookeeper和redis。下面依次介绍这三种组件实现分布式锁的方式。

2 分布式锁的几个问题

在使用分布式锁的时候,需要考虑如下几个问题:假如我们在多线程下拿锁(多线程和多进程是一样的):

3 mysql实现分布式锁

先select,如果没有则,insert一个key,insert成功则拿到锁,insert不成功则拿不到锁。如果第一次select到了,那么用select for update操作施加一个x锁,for update拿到数据则拿锁成功。
锁的有效期就是线程的有效期,线程如果中断了或者异常退出了,一般都会捕获异常,回滚事务,释放锁。

4 zookeeper实现分布式锁

zookeeper实现分布式锁是利用的zookeeper可以创建临时节点的机制,同时利用了zk的watcher机制,如果不太熟悉zk的可以看我的zk文章,一个常见的使用zk作为分布式锁的方法为:

细心的读者可能发现了问题,所有的线程都去拿锁,这就是惊群效应,那么如何避免呢?zk还提供了一种创建模式,可以创建顺序节点,那么该怎么做呢?

zk的实现机制很完美,有什么问题呢?
zk的事务提交流程比较长,在集群下需要非leader转发到leader,leader发起投票,过半提交后leadercommit事务,follower 提交事务。整个流程比较长,有些高并发场景下可能不太适用,而且新增了一个zk组件,不便维护。

3 redis实现分布式锁

redis的分布式锁实现,要依赖于原子操作和setnx命令。setnx拿到锁并同时设置超时时间的原子操作命令为:

SET key value [EX seconds] [PX milliseconds] [NX|XX]
实例:SET resource-name any-string NX EX max-lock-time

这个命令解决了

假如不设置锁的有效期,线程异常挂掉,所有线程都拿不到锁了怎么办。

的问题。但是续期怎么做呢。
有两种做法:
第一种:

"if (redis.call('hexists', KEYS[1], ARGV[3]) == 0) then " +
                "return nil;" +
            "end; " +
            // 将该客户端对应的锁的 hash 结构的 value 值递减为 0 后再进行删除
            // 然后再向通道名为 redisson_lock__channel publish 一条 UNLOCK_MESSAGE 信息
            "local counter = redis.call('hincrby', KEYS[1], ARGV[3], -1); " +
            "if (counter > 0) then " +
                "redis.call('pexpire', KEYS[1], ARGV[2]); " +
                "return 0; " +
            "else " +
                "redis.call('del', KEYS[1]); " +
                "redis.call('publish', KEYS[2], ARGV[1]); " +
                "return 1; "+
            "end; " +
            "return nil;",

第二种,使用看门狗:

上一篇下一篇

猜你喜欢

热点阅读