首頁  >  文章  >  Java  >  如何使用Redis實現分散式鎖

如何使用Redis實現分散式鎖

PHPz
PHPz原創
2024-08-31 18:31:04736瀏覽

我是啞巴

嗯,每當我們在本地系統中工作時,一切都像黃油一樣工作。這就是為什麼我們稱「沒有比 127.0.0.1 更好的地方了」,但醒來面對現實

How to implement a Distributed Lock using Redis

生產中的事情並不總是按預期進行。大多數情況下,當您執行應用程式的多個實例時。

How to implement a Distributed Lock using Redis

?正如您所看到的,如果我們的應用程式的多個執行個體正在運行,並且假設我們的客戶端發出請求,將使用者標記為資料庫中的付費使用者。

  • 客戶端將請求我們的伺服器
  • 請求將到達我們的負載平衡器
  • 其中一個實例將收到請求並向我們的資料庫發出寫入查詢

看起來還不錯吧?到目前為止沒問題吧。

嗯,是的,到目前為止沒有問題。但是如果我們想寫這樣的業務邏輯怎麼辦:-

  • 從資料庫取得使用者
  • 檢查使用者是否為免費使用者或已付費
  • 如果免費,則將其標記為付費並保存在資料庫中
  • 如果已付款,請在回覆中發送「已付款」。

⚡️ 眾所周知(假設我們在這裡使用 MySQL)MySQL 資料庫符合 ACID,這意味著任何查詢都將是原子的和隔離的。這意味著 MySQL 查詢將以原子方式運行,要么通過,要么失敗。但中間不會退出。

?但這裡有一個問題。想想,想想…

  • 第 1 步:我們正在取得使用者(原子交易)
  • 第 2 步:在程式碼中執行一些業務邏輯
  • 第3步:如果使用者未付款則更新MySQL記錄(原子交易)

如果在第 2 步,又一個取消付款的請求,然後該查詢首先運行並將用戶標記為免費,然後運行第 3 步並將用戶標記為已付費,會發生什麼情況。

??萬歲,使用者甚至無需付費即可存取我們的產品。

鎖定

✅救星Locks來了
How to implement a Distributed Lock using Redis

?鎖是一種結構,一次只允許一個執行緒進入臨界區(不應被多個工作執行緒存取的程式碼區塊)

因此,我們將在操作完成之前取得鎖定並在操作完成後釋放:-

  • 第0步:嘗試取得()鎖定
  • 第 1 步:如果獲取,我們將獲取使用者(原子事務)
  • 第 2 步:在程式碼中執行一些業務邏輯
  • 第3步:如果使用者未付款則更新MySQL記錄(原子事務)
  • 第四步:release() 鎖

?問題

現在,問題來了,如果我們使用一些記憶體鎖資料結構或任何基於記憶體的鎖,它將有資格獲得我們應用程式的一個實例。其他運行相同程式碼並在資料庫中更新的實例怎麼樣?

分散式鎖的概念來了

?分散式鎖

How to implement a Distributed Lock using Redis

這裡的鎖充當一種集中式服務,如果我們服務的一個實例取得了鎖,那麼其他實例就無法使用同一個金鑰。

支付服務中可以使用什麼鍵?

?對於進行付款的用戶,金鑰可以是=“PAYMENT_”+ user_id + amount

的組合

這對每個使用者來說都是唯一的。並且當用戶付款或取消付款時,該密鑰將保持不變。因此,當一個操作發生時,其他操作無法繼續,因為這兩個操作將嘗試取得相同鍵。

? Key、取得鎖、釋放鎖到底是什麼?最重要的是,redis 是如何使用的?


?使用Redis實現分散式鎖

使用 Redis 的單一實例:-

How to implement a Distributed Lock using Redis

但是單一 Redis 實例存在以下幾個問題:-

  • 單一實例可能會失敗且取得的鎖定可能無法釋放
  • 如果使用兩個實例(主副本),則一個客戶端將取得一個實例上的鎖定
  • 主伺服器必須與副本進行相同的通訊才能同步。這種通訊本身就是非同步通訊

?因此,如果在主伺服器上取得了鎖,並且在與副本通訊時,如果主伺服器在與副本同步之前發生故障。副本將成為主伺服器,其中相同金鑰上的鎖將可用於取得先前在主伺服器上取得的鎖。

即使有兩個實例(主副本),我們服務的兩個實例也將能夠取得 Redis 上的鎖。

使用 Redlock 演算法:-

取得鎖定:- 我們將嘗試在具有鎖定過期時間的多個 Redis 實例上取得鎖定
鎖定驗證:- 如果主要 Redis 實例為客戶端取得了鎖,則將被視為已取得鎖定
釋放鎖定:- 釋放鎖定時,所有實例都釋放鎖定

How to implement a Distributed Lock using Redis

是的,就是這樣。

❤️ 感謝您的閱讀,並訂閱我們的時事通訊以獲取更多此類文章:- https://www.serversidedigest.com/

欲了解更多:-

  • Java 中的 Jedis:- https://redis.io/docs/latest/develop/connect/clients/java/jedis/
  • Golang 中的 Redis 用戶端:- https://github.com/redis/go-redis

以上是如何使用Redis實現分散式鎖的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述:
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn