天天看點

Redis分布式鎖應用(實作+原理)

作者:湘見程式員

在分布式系統中,當不同程序或線程一起通路共享資源時,會造成資源争搶,如果不加以控制的話,就會引發程式錯亂。此時使用分布式鎖能夠非常有效的解決這個問題,它采用了一種互斥機制來防止線程或程序間互相幹擾,進而保證了資料的一緻性。

Redis分布式鎖應用(實作+原理)

提示:如果對分布式系統這一概念不清楚,可參考百度百科《分布式系統》,簡而言之,它是一種架構、一種模式。

Redis分布式鎖介紹

分布式鎖并非是 Redis 獨有,比如 MySQL 關系型資料庫,以及 Zookeeper 分布式服務應用,它們都實作分布式鎖,隻不過 Redis 是基于緩存實作的。

Redis分布式鎖應用(實作+原理)

Redis 分布式鎖有很多應用場景,舉個簡單的例子,比如春運時,您需要在 12306 上搶購回家火車票,但 Redis 資料庫中隻剩一張票了,此時有多個使用者來預訂購買,那麼這張票會被誰搶走呢?Redis 伺服器又是如何處理這種情景的呢?在這個過程中就需要使用分布式鎖。

Redis 分布式鎖主要有以下特點:

  • 第一:互斥性是分布式鎖的重要特點,在任意時刻,隻有一個線程能夠持有鎖;
  • 第二:鎖的逾時時間,一個線程在持鎖期間挂掉了而沒主動釋放鎖,此時通過逾時時間來保證該線程在逾時後可以釋放鎖,這樣其他線程才可以繼續擷取鎖;
  • 第三:加鎖和解鎖必須是由同一個線程來設定;
  • 第四:Redis 是緩存型資料庫,擁有很高的性能,是以加鎖和釋放鎖開銷較小,并且能夠很輕易地實作分布式鎖。

Redis分布式鎖指令

分布式鎖的本質其實就是要在 Redis 裡面占一個“坑”,當别的程序也要來占時,發現已經有人蹲了,就隻好放棄或者稍做等待。這個“坑”同一時刻隻允許被一個用戶端占據,也就是本着“先來先占”的原則。

1) 常用指令

Redis 分布式鎖常用指令如下所示:

  • SETNX key val:僅當key不存在時,設定一個 key 為 value 的字元串,傳回1;若 key 存在,設定失敗,傳回 0;
  • Expire key timeout:為 key 設定一個逾時時間,以 second 秒為機關,超過這個時間鎖會自動釋放,避免死鎖;
  • DEL key:删除 key。
Redis分布式鎖應用(實作+原理)

上述 SETNX 指令相當于占“坑”操作,EXPIRE 是為避免出現意外用來設定鎖的過期時間,也就是說到了指定的過期時間,該用戶端必須讓出鎖,讓其他用戶端去持有。

Redis分布式鎖應用(實作+原理)

但還有一種情況,如果在 SETNX 和 EXPIRE 之間伺服器程序突然挂掉,也就是還未設定過期時間,這樣就會導緻 EXPIRE 執行不了,是以還是會造成“死鎖”的問題。為了避免這個問題,Redis 作者在 2.6.12 版本後,對 SET 指令參數做了擴充,使它可以同時執行 SETNX 和 EXPIRE 指令,進而解決了死鎖的問題。

直接使用 SET 指令實作,文法格式如下:

SET key value [expiration EX seconds|PX milliseconds] [NX|XX]             
  • EX second:設定鍵的過期時間為 second 秒。 SET key value EX second 效果等同于 SETEX key second value 。
  • PX millisecond:設定鍵的過期時間為毫秒。SET key value PX millisecond 效果等同于 PSETEX key millisecondvalue 。
  • NX:隻在鍵不存在時,才對鍵進行設定操作。 SET key value NX 效果等同于 SETNX key value 。
  • XX:隻在鍵已經存在時,才對鍵進行設定操作。

2) 指令應用

下面進行簡單的指令示範:

127.0.0.1:6379> SETNX WEBNAME www.baidu.net
(integer) 1
127.0.0.1:6379> EXPIRE WEBNAME 60
(integer) 1
127.0.0.1:6379> GET WEBNAME
"www.baidu.net"
127.0.0.1:6379> TTL WEBNAME
(integer) 33
127.0.0.1:6379> SET name www.baidu.net EX 60 NX
OK           

繼續閱讀