iT邦幫忙

2022 iThome 鐵人賽

DAY 25
1
Software Development

軟體架構師的自我修養系列 第 25

[Day 25] 用Redis當鎖?你確定?

  • 分享至 

  • xImage
  •  

Redis是一個將資料存放在記憶體的存儲,而且我們都知道記憶體有多不可靠。更有甚者,在昨天,Redis的持久化中有提到Redis的儲存比我們想的更不可靠。因此,使用Redis當鎖來保證同步是很危險的。

但是,這篇文章,不是專注在告訴你有多危險,而是要更進一步分析,我們使用的「鎖」真的有用對嗎?

事實上,我們通常說的鎖有兩種截然不同的概念。

  • 排他鎖(Exclusive lock):這用來控制臨界區段(critical section)的存取權限,只能允許一次一個人進入。另外有個很類似的概念:號誌(Semaphore),這是設定臨界區段的容留上限。
  • 屏障(Barrier):這機制是用來減少特定操作的頻率。

儘管,這兩個概念有截然不同的目的且有完全相異的實作方式,但我們通常沒有仔細定義我們的需求,並且選擇錯誤的實作,導致最後做出一個畸形。

排他鎖

排他鎖的目的是我們所熟知的互斥(mutex)鎖,用來控制臨界區段的同時使用者僅能有一個。

進入臨界區段的時候上鎖,而離開時解鎖。這機制也很常在使用資料庫時搭配使用以避免競爭條件,例如,MySQL無法避免更新遺失,因此會用一個排他鎖FOR UPDATE作為兩個同時更新的同步機制。

根據上面描述,我們可以寫出偽代碼。

while not tryLock(forLongTime):
    sleep(veryShortTime)
    
doSomeThing()

releaseLock()

有幾個重點必須解釋一下。

  1. tryLock這個函式包含兩個動作:取得鎖以及上鎖。如果可以取得鎖,那麼就應該當下立刻上鎖,不然鎖有可能也會被別人取得,那麼臨界區段就破功了。
  2. 等待鎖的時間應該要非常短,等待的目的是為了儘早取得鎖以開始實際做事,所以要避免花很長時間等待。
  3. 但是,鎖的時間要夠長,以避免事情還沒做完鎖就消失了,那也等同臨界區段失效。
  4. 當所有事情做完,要馬上把鎖釋放掉,以便讓其餘操作可以盡快進入臨界區段。

再一次聲明,排他鎖的目的是為了控制臨界區段的存取。如果兩個同時發起的操作,那麼兩個操作都會執行,但是一前一後。

屏障

屏障的目的是為了減少特定操作的頻率。

舉例來說,如果連續呼叫一個API兩次,那麼第二個API可能會拿到「請稍後再試」,這就是典型的屏障。

既然目的是為了減少頻率,那麼鎖定的時間就很重要,要根據功能需求來決定。例如:如果產品規格是兩個API必須間隔5秒,那麼鎖的時間就是5秒。這通常比排他鎖的鎖定時間短。

我們也試著寫出偽代碼。

if not tryLock(featureSpecTime):
    return False

return doSomeThing()

相較於排他鎖,屏障並沒有解鎖和等待,但同樣會使用tryLock,只是鎖的時間來自於產品規格。

屏障是為了減少頻率,因此如果兩個操作同時發生,那麼一個會成功而另一個會失敗。

那關Redis什麼事?

好,我們都已經了解兩種鎖的概念了,因此我們來看看與Redis的關係。

Redis是最常被用來實作排他鎖和屏障的工具,因為利用Redis來實作tryLock非常容易,只需要一行指令:

SET someKey 1 EX someTime NX

根據指令的結果是OKnil就可以知道有沒有成功取得鎖,以實作來說實在非常單純。

但是,就像文章一開始說的,Redis並不可靠,因此使用Redis作為排他鎖會背負風險。

Redis作為屏障還不錯,就算真的資料消失,也頂多是原本只能執行一次的操作變成執行兩次而已,但不會影響系統穩定。反之,若是排他鎖,我們就得要仔細權衡風險了。

對我來說,如果要避免MySQL的更新遺失,我總是會使用MySQL內建的FOR UPDATE而不是Redis,不僅更容易使用也比Redis更安全。關於MySQL使用鎖的細節在前幾天我們已經有介紹過了。

結論

這篇文章解釋了兩種我們常稱的鎖和其意義,儘管他們有著類似的名稱,但無論目的還是實作都截然不同。

總結一下。

  • 排他鎖:兩個同時的操作都會成功,但一前一後。
  • 屏障:兩個同時的操作只有一個會成功。

當我們提到鎖,請確定到底要解決的是什麼使用情境,並且將鎖用對。

對我來說,即使在系統中有Redis且我也會用他,但我在設計系統時我總是當Redis內的資料不存在,如此一來才會正確的對待各種「不幸」。

請記得墨菲定律:當事情有機會出錯時,就總是會出錯。


上一篇
[Day 24] Redis的資料持久化
下一篇
[Day 26] 深入解釋Redlock
系列文
軟體架構師的自我修養31
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言