redis分布式锁原理

以redisson为例

        RLock lock = redissonClient.getLock(key);
        lock.lock(timeoutSecond, TimeUnit.SECONDS);

原则:1.自己加的锁自己释放,2.锁到期了业务没执行完还需续期

1. 加锁时执行lua脚本

				"if (redis.call('exists', KEYS[1]) == 0) then " +
                      "redis.call('hset', KEYS[1], ARGV[2], 1); " +
                      "redis.call('pexpire', KEYS[1], ARGV[1]); " +
                      "return nil; " +
                  "end; " +
                  "if (redis.call('hexists', KEYS[1], ARGV[2]) == 1) then " +
                      "redis.call('hincrby', KEYS[1], ARGV[2], 1); " +
                      "redis.call('pexpire', KEYS[1], ARGV[1]); " +
                      "return nil; " +
                  "end; " +
                  "return redis.call('pttl', KEYS[1]);"

KEYS[1]代表加锁的key,ARGV[2]代表的是加锁的客户端ID,ARGV[1]代表的锁的生存时间

2. 锁互斥实现

如果其它客户端来加锁,第一个if会失败,然后第二个if,然后再hash结构中判断是否存在客户端2的ID,因为不含有,所以会走最后return返回过期时间,然后客户端2会进入while循环,不停的尝试加锁。

3. watch dog自动延期机制

如果客户端超过生存时间还想持有锁,怎么办?

加锁成功同时会启动一个后台线程检查,如果客户端还持有锁就会不断延长生存时间,默认是10s一次

4. 可重入

进入第二个if,会把value + 1

5. 释放锁

			"if (redis.call('hexists', KEYS[1], ARGV[3]) == 0) then " +
                    "return nil;" +
                "end; " +
                "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;"	

先把锁里的计数减一,然后再删除

7. redis分布式锁的缺点

master节点宕机,salve变成master,数据还没来得及同步,这样其他客户端就有可能完成加锁。就会导致多个客户端同时持有了锁。

实时内容请关注微信公众号,公众号与博客同时更新:程序员星星
在这里插入图片描述

©️2020 CSDN 皮肤主题: 编程工作室 设计师:CSDN官方博客 返回首页