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,數據還沒來得及同步,這樣其他客戶端就有可能完成加鎖。就會導致多個客戶端同時持有了鎖。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章