以前咱們使用的定時任務都是隻部署在了單臺機器上,爲了解決單點的問題,爲了保證一個任務,只被一臺機器執行,就須要考慮鎖的問題,因而就花時間研究了這個問題。到底怎樣實現一個分佈式鎖呢?redis
鎖的本質就是互斥,保證任什麼時候候能有一個客戶端持有同一個鎖,若是考慮使用redis來實現一個分佈式鎖,最簡單的方案就是在實例裏面建立一個鍵值,釋放鎖的時候,將鍵值刪除。可是一個可靠完善的分佈式鎖須要考慮的細節比較多,咱們就來看看如何寫一個正確的分佈式鎖。算法
因此咱們直接基於 redis 的 setNX (SET if Not eXists)命令,實現一個簡單的鎖。直接上僞碼安全
鎖的獲取:網絡
SET resource_name my_random_value NX PX 30000複製代碼
鎖的釋放:架構
if redis.call("get",KEYS[1]) == ARGV[1] then
return redis.call("del",KEYS[1])
else
return 0
end複製代碼
幾個細節須要注意:併發
在鎖釋放的時候咱們判斷了KEYS[1]) == ARGV[1]
,在這裏 KEYS[1]
是從redis裏面取出來的value,ARGV[1]
是上文生成的my_random_value
。之因此進行以上的判斷,是爲了保證鎖被鎖的持有者釋放。咱們假設不進行這一步校驗:dom
客戶端C獲取鎖。這個時候一個系統中同時兩個客戶端持有鎖。異步
形成這個問題的關鍵,在於客戶端B持有的鎖,被客戶端A釋放了。分佈式
鎖的釋放必須使用lua腳本,保證操做的原子性。鎖的釋放包含了get
,判斷,del
三個步驟。若是不能保證三個步驟的原子性,分佈式鎖就會有併發問題。性能
注意了以上細節,一個單redis節點的分佈式鎖就達成了。
在這個分佈式鎖中仍是存在一個單點的redis。也許你會說,Redis是 master-slave的架構,發生故障的時候切換到slave就好,可是Redis的複製是異步的。
這樣因爲Master的宕機,形成了同時多人持有鎖。若是你的系統可用接受短時時間內,有多人持有鎖。這個簡單的方案就能解決問題。
可是若是解決這個問題。Redis的官方提供了一個Redlock的解決方案。
爲了解決,Redis單點的問題。Redis的做者提出了RedLock的解決方案。方案很是的巧妙和簡潔。
RedLock的核心思想就是,同時使用多個Redis Master來冗餘,且這些節點都是徹底的獨立的,也不須要對這些節點之間的數據進行同步。
假設咱們有N個Redis節點,N應該是一個大於2的奇數。RedLock的實現步驟:
對於釋放鎖的實現就很簡單了。想全部的Redis節點發起釋放的操做,不管以前是否獲取鎖成功。
同時須要注意幾個細節:
若是某master節點故障以後,回覆的時間間隔應當大於鎖的有效時間。
此時又有兩個客戶端獲取到鎖了。
因此若是恢復的時間將大於鎖的有效時間,就能夠避免以上狀況發生。同時若是性能要求不高,甚至能夠開啓Redis的持久化選項。
瞭解了Redis分佈式的實現之後,其實以爲大多數的分佈式系統其實原理很簡單,可是爲了保證分佈式系統的可靠性須要注意不少的細節,瑣碎異常。
RedLock算法實現的分佈式鎖就是簡單高效,思路至關巧妙。
可是RedLock就必定安全麼?我還會寫一篇文章來討論這個問題。敬請你們期待,文章地址。