Redis紅鎖

在算法的分布式版本中,我們假設(shè)我們有N個Redis主節(jié)點(diǎn)。這些節(jié)點(diǎn)是完全獨(dú)立的足删,因此我們不使用復(fù)制或任何其他隱式協(xié)調(diào)系統(tǒng)。我們已經(jīng)描述了如何在單個實(shí)例中安全地獲取和釋放鎖匣距。我們理所當(dāng)然地認(rèn)為,算法將使用此方法在單個實(shí)例中獲取和釋放鎖哎壳。在我們的示例中毅待,我們設(shè)置了 N=5,這是一個合理的值归榕,因此我們需要在不同的計(jì)算機(jī)或虛擬機(jī)上運(yùn)行 5 個 Redis 主節(jié)點(diǎn)尸红,以確保它們以一種基本獨(dú)立的方式失敗。

為了獲取鎖,客戶端執(zhí)行以下操作:

  1. 它獲取當(dāng)前時(shí)間(以毫秒為單位)外里。
  2. 它嘗試按順序獲取所有 N 個實(shí)例中的鎖怎爵,在所有實(shí)例中使用相同的鍵名和隨機(jī)值。在步驟 2 中盅蝗,在每個實(shí)例中設(shè)置鎖定時(shí)鳖链,客戶端使用與總鎖定自動釋放時(shí)間相比較小的超時(shí)來獲取它。例如墩莫,如果自動釋放時(shí)間為 10 秒芙委,則超時(shí)可能在 ~ 5-50 毫秒范圍內(nèi)。這可以防止客戶端長時(shí)間試圖與已關(guān)閉的Redis節(jié)點(diǎn)通信:如果實(shí)例不可用狂秦,我們應(yīng)該盡快嘗試與下一個實(shí)例通信题山。
  3. 客戶端通過從當(dāng)前時(shí)間中減去步驟 1 中獲得的時(shí)間戳來計(jì)算獲取鎖所經(jīng)過的時(shí)間。當(dāng)且僅當(dāng)客戶端能夠在大多數(shù)實(shí)例(至少 3 個)中獲取鎖故痊,并且獲取鎖所經(jīng)過的總時(shí)間小于鎖的有效時(shí)間,則該鎖被視為已獲取玖姑。
  4. 如果已獲取鎖愕秫,則其有效性時(shí)間被視為初始有效時(shí)間減去經(jīng)過的時(shí)間,如步驟 3 中計(jì)算的那樣焰络。
  5. 如果客戶端由于某種原因未能獲取鎖定(它無法鎖定 N/2+1 個實(shí)例或有效期為負(fù)數(shù))戴甩,它將嘗試解鎖所有實(shí)例(甚至是它認(rèn)為無法鎖定的實(shí)例)。

算法是異步的嗎闪彼?

該算法依賴于以下假設(shè):雖然進(jìn)程之間沒有同步時(shí)鐘甜孤,但每個進(jìn)程中的本地時(shí)間以大致相同的速率更新,與鎖的自動釋放時(shí)間相比畏腕,誤差幅度很小缴川。這個假設(shè)與現(xiàn)實(shí)世界的計(jì)算機(jī)非常相似:每臺計(jì)算機(jī)都有一個本地時(shí)鐘,我們通趁柘冢可以依靠不同的計(jì)算機(jī)來具有很小的時(shí)鐘漂移把夸。

在這一點(diǎn)上,我們需要更好地指定我們的互斥規(guī)則:只要持有鎖的客戶端在鎖有效時(shí)間內(nèi)(如步驟3中獲得的那樣)終止其工作铭污,減去一些時(shí)間(只需幾毫秒恋日,以補(bǔ)償進(jìn)程之間的時(shí)鐘漂移),它才能得到保證嘹狞。

本文包含有關(guān)需要綁定時(shí)鐘漂移的類似系統(tǒng)的更多信息:Leases:分布式文件緩存一致性的高效容錯機(jī)制岂膳。

失敗時(shí)重試

當(dāng)客戶端無法獲取鎖時(shí),它應(yīng)該在隨機(jī)延遲后重試磅网,以便嘗試取消同步多個客戶端谈截,嘗試同時(shí)獲取同一資源的鎖(這可能會導(dǎo)致沒有人獲勝的裂腦情況)。此外,客戶端在大多數(shù) Redis 實(shí)例中嘗試獲取鎖的速度越快傻盟,裂腦情況的窗口就越兴偃铩(并且需要重試),因此理想情況下娘赴,客戶端應(yīng)嘗試使用多路復(fù)用同時(shí)將 SET 命令發(fā)送到 N 個實(shí)例规哲。

值得強(qiáng)調(diào)的是,對于未能獲取大多數(shù)鎖的客戶端來說诽表,盡快釋放(部分)獲取的鎖是多么重要唉锌,這樣就不需要等待密鑰到期才能再次獲取鎖(但是,如果發(fā)生網(wǎng)絡(luò)分區(qū)并且客戶端不再能夠與 Redis 實(shí)例通信竿奏, 在等待密鑰過期時(shí)需要支付可用性罰款)袄简。

釋放鎖

釋放鎖很簡單,無論客戶端是否認(rèn)為它能夠成功鎖定給定實(shí)例泛啸,都可以執(zhí)行绿语。

安全論據(jù)

算法安全嗎?讓我們來看看在不同場景中會發(fā)生什么候址。

首先吕粹,我們假設(shè)客戶端能夠在大多數(shù)實(shí)例中獲取鎖。所有實(shí)例都將包含一個具有相同生存時(shí)間的密鑰岗仑。但是匹耕,密鑰是在不同的時(shí)間設(shè)置的,因此密鑰也會在不同的時(shí)間過期荠雕。但是稳其,如果在時(shí)間 T1(我們在聯(lián)系第一臺服務(wù)器之前采樣之前采樣的時(shí)間)將第一個鍵設(shè)置為最差,而在時(shí)間 T2(我們從最后一個服務(wù)器獲得回復(fù)的時(shí)間)將最后一個鍵設(shè)置為最差炸卑,則我們確信集中第一個過期的密鑰將至少存在 既鞠。所有其他密鑰稍后將過期,因此我們確信至少這次將同時(shí)設(shè)置這些密鑰矾兜。MIN_VALIDITY=TTL-(T2-T1)-CLOCK_DRIFT

在設(shè)置大多數(shù)密鑰期間损趋,另一個客戶端將無法獲取鎖,因?yàn)槿绻?N/2+1 密鑰已存在椅寺,則 N/2+1 SET NX 操作無法成功浑槽。因此,如果獲得了鎖返帕,則不可能同時(shí)重新獲得它(違反互斥屬性)桐玻。

但是,我們還希望確保嘗試同時(shí)獲取鎖的多個客戶端無法同時(shí)成功荆萤。

如果客戶端鎖定大多數(shù)實(shí)例的時(shí)間接近或大于鎖定最大有效時(shí)間(我們基本上用于 SET 的 TTL)镊靴,它將認(rèn)為鎖定無效并將解鎖實(shí)例铣卡,因此我們只需要考慮客戶端能夠在小于有效時(shí)間的時(shí)間內(nèi)鎖定大多數(shù)實(shí)例的情況。在這種情況下偏竟,對于上面已經(jīng)表達(dá)的參數(shù)煮落,因?yàn)槿魏慰蛻舳硕疾粦?yīng)該能夠重新獲取鎖。因此踊谋,僅當(dāng)鎖定大多數(shù)實(shí)例的時(shí)間大于 TTL 時(shí)間時(shí)蝉仇,多個客戶端才能同時(shí)鎖定 N/2+1 個實(shí)例(“時(shí)間”是步驟 2 的結(jié)束),從而使鎖定無效殖蚕。MIN_VALIDITY

活潑性參數(shù)

系統(tǒng)活動性基于三個主要功能:

  1. 自動釋放鎖(因?yàn)殍€匙過期):最終鑰匙再次可供鎖定轿衔。
  2. 事實(shí)上,通常睦疫,當(dāng)未獲取鎖或獲取鎖并終止工作時(shí)害驹,客戶端將合作移除鎖,因此我們可能不必等待密鑰過期即可重新獲取鎖蛤育。
  3. 事實(shí)上宛官,當(dāng)客戶端需要重試鎖時(shí),它等待的時(shí)間比獲取大多數(shù)鎖所需的時(shí)間要長得多瓦糕,以便從概率上使資源爭用期間的裂腦條件變得不太可能摘刑。

但是,我們支付的可用性損失等于網(wǎng)絡(luò)分區(qū)上的TTL時(shí)間刻坊,因此,如果有連續(xù)分區(qū)党晋,我們可以無限期地支付此罰款谭胚。每次客戶端獲取鎖并在能夠刪除鎖之前進(jìn)行分區(qū)時(shí),都會發(fā)生這種情況未玻。

基本上灾而,如果存在無限連續(xù)的網(wǎng)絡(luò)分區(qū),則系統(tǒng)可能會在無限長的時(shí)間內(nèi)變得不可用扳剿。

性能旁趟、崩潰恢復(fù)和同步

許多使用 Redis 作為鎖服務(wù)器的用戶在獲取和釋放鎖的延遲以及每秒可以執(zhí)行的獲取/釋放操作數(shù)方面都需要高性能。為了滿足這一要求庇绽,與N Redis服務(wù)器對話以減少延遲的策略肯定是多路復(fù)用(將套接字置于非阻塞模式锡搜,發(fā)送所有命令,稍后讀取所有命令瞧掺,假設(shè)客戶端和每個實(shí)例之間的RTT相似)耕餐。

但是,如果我們想以崩潰恢復(fù)系統(tǒng)模型為目標(biāo)辟狈,則關(guān)于持久性還有另一個考慮因素肠缔。

基本上夏跷,為了看到這里的問題,讓我們假設(shè)我們配置Redis時(shí)根本沒有持久性明未〔刍客戶端在 5 個實(shí)例中的 3 個實(shí)例中獲取鎖√送祝客戶端能夠獲取鎖的其中一個實(shí)例重新啟動猫态,此時(shí)我們可以為同一資源鎖定3個實(shí)例,而另一個客戶端可以再次鎖定它煮纵,這違反了鎖的獨(dú)占性的安全屬性懂鸵。

如果我們啟用AOF持久性,事情將會有所改善行疏。例如匆光,我們可以通過向服務(wù)器發(fā)送 SHUTDOWN 命令并重新啟動它來升級服務(wù)器。由于 Redis 過期在語義上是實(shí)現(xiàn)的酿联,因此當(dāng)服務(wù)器關(guān)閉時(shí)终息,時(shí)間仍然會過去,因此我們所有的要求都很好贞让。但是周崭,只要它是干凈關(guān)閉,一切都很好喳张。停電怎么辦续镇?如果 Redis 配置為(默認(rèn)情況下)每秒在磁盤上同步一次,則重新啟動后销部,我們的密鑰可能會丟失摸航。從理論上講,如果我們想在面對任何類型的實(shí)例重啟時(shí)保證鎖定安全舅桩,我們需要在持久性設(shè)置中啟用酱虎。由于額外的同步開銷,這將影響性能擂涛。fsync=always

然而读串,事情比乍一看要好∪雎瑁基本上恢暖,只要實(shí)例在崩潰后重新啟動,它就不再參與任何當(dāng)前活動的鎖定狰右,算法安全性就會保留胀茵。這意味著實(shí)例重新啟動時(shí)的當(dāng)前活動鎖定集都是通過鎖定重新加入系統(tǒng)的實(shí)例以外的實(shí)例而獲得的。

為了保證這一點(diǎn)挟阻,我們只需要在崩潰后使一個實(shí)例不可用琼娘,至少比我們使用的最大TTL多一點(diǎn)峭弟。這是實(shí)例崩潰時(shí)存在的有關(guān)鎖的所有密鑰變得無效并自動釋放所需的時(shí)間。

使用延遲重啟脱拼,即使沒有任何可用的Redis持久性瞒瘸,基本上也可以實(shí)現(xiàn)安全,但請注意熄浓,這可能會轉(zhuǎn)化為可用性損失情臭。例如,如果大多數(shù)實(shí)例崩潰赌蔑,系統(tǒng)將全局不可用 TTL(此處全局意味著在此期間根本沒有資源可鎖定)俯在。

使算法更可靠:擴(kuò)展鎖

如果客戶端執(zhí)行的工作由小步驟組成,則默認(rèn)情況下可以使用較小的鎖定有效期娃惯,并擴(kuò)展實(shí)現(xiàn)鎖定擴(kuò)展機(jī)制的算法跷乐。基本上趾浅,如果客戶端在計(jì)算過程中鎖定有效性接近較低值愕提,則可以通過將Lua腳本發(fā)送到所有實(shí)例來擴(kuò)展鎖定,該實(shí)例擴(kuò)展密鑰的TTL(如果密鑰存在并且其值仍然是客戶端在獲取鎖定時(shí)分配的隨機(jī)值)皿哨。

只有當(dāng)客戶端能夠?qū)㈡i擴(kuò)展到大多數(shù)實(shí)例中浅侨,并且在有效時(shí)間內(nèi)(基本上要使用的算法與獲取鎖時(shí)使用的算法非常相似),才應(yīng)考慮重新獲取鎖证膨。

但是如输,這在技術(shù)上不會更改算法,因此應(yīng)限制鎖定重新獲取嘗試的最大次數(shù)央勒,否則會違反其中一個活動屬性挨决。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市订歪,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌肆捕,老刑警劉巖刷晋,帶你破解...
    沈念sama閱讀 212,816評論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異慎陵,居然都是意外死亡眼虱,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,729評論 3 385
  • 文/潘曉璐 我一進(jìn)店門席纽,熙熙樓的掌柜王于貴愁眉苦臉地迎上來捏悬,“玉大人,你說我怎么就攤上這事润梯」溃” “怎么了甥厦?”我有些...
    開封第一講書人閱讀 158,300評論 0 348
  • 文/不壞的土叔 我叫張陵,是天一觀的道長寇钉。 經(jīng)常有香客問我刀疙,道長,這世上最難降的妖魔是什么扫倡? 我笑而不...
    開封第一講書人閱讀 56,780評論 1 285
  • 正文 為了忘掉前任谦秧,我火速辦了婚禮,結(jié)果婚禮上撵溃,老公的妹妹穿的比我還像新娘疚鲤。我一直安慰自己,他們只是感情好缘挑,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,890評論 6 385
  • 文/花漫 我一把揭開白布集歇。 她就那樣靜靜地躺著,像睡著了一般卖哎。 火紅的嫁衣襯著肌膚如雪鬼悠。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 50,084評論 1 291
  • 那天亏娜,我揣著相機(jī)與錄音焕窝,去河邊找鬼。 笑死维贺,一個胖子當(dāng)著我的面吹牛它掂,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播溯泣,決...
    沈念sama閱讀 39,151評論 3 410
  • 文/蒼蘭香墨 我猛地睜開眼虐秋,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了垃沦?” 一聲冷哼從身側(cè)響起客给,我...
    開封第一講書人閱讀 37,912評論 0 268
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎肢簿,沒想到半個月后靶剑,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,355評論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡池充,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,666評論 2 327
  • 正文 我和宋清朗相戀三年桩引,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片收夸。...
    茶點(diǎn)故事閱讀 38,809評論 1 341
  • 序言:一個原本活蹦亂跳的男人離奇死亡坑匠,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出卧惜,到底是詐尸還是另有隱情厘灼,我是刑警寧澤夹纫,帶...
    沈念sama閱讀 34,504評論 4 334
  • 正文 年R本政府宣布,位于F島的核電站手幢,受9級特大地震影響捷凄,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜围来,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 40,150評論 3 317
  • 文/蒙蒙 一跺涤、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧监透,春花似錦桶错、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,882評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至粪狼,卻和暖如春退腥,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背再榄。 一陣腳步聲響...
    開封第一講書人閱讀 32,121評論 1 267
  • 我被黑心中介騙來泰國打工狡刘, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人困鸥。 一個月前我還...
    沈念sama閱讀 46,628評論 2 362
  • 正文 我出身青樓嗅蔬,卻偏偏與公主長得像,于是被迫代替她去往敵國和親疾就。 傳聞我的和親對象是個殘疾皇子澜术,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,724評論 2 351

推薦閱讀更多精彩內(nèi)容