Redis ①⑦-分布式鎖

在這里插入圖片描述

分布式鎖

分布式鎖是鎖的一種,都是為了解決多線程/多進程環境下,對共享資源的訪問沖突問題。

不過,像 Java 的 synchronized 或者 C++ 的 mutex 這種鎖,都是進程內的鎖,而分布式鎖則是跨越進程/機器的鎖。也就是可以針對多個進程、多臺服務器的的共享資源進行加鎖

考慮買票的場景,現在車站提供了若干個車次,每個車次的票數都是固定的。

現在存在多個服務器節點,都可能需要處理這個買票的邏輯:先查詢指定車次的余票,如果余票 > 0,則設置余票值 -= 1在這里插入圖片描述

上述場景如果任何處理,就會存在 “線程安全問題”。

當多個客戶端同時購買一個車次的票時,此時余票數量還未作出相應的更新。
假設此時只剩一張余票,當多個客戶端都判斷 余票 > 0 成功后,導致余票 “被賣出去了多張”,但實際只剩一張了,這就是是出現 “超賣” 的情況。

為了解決這個問題,引入分布式鎖。

實現分布式鎖

引入 SETNX

既然普通的鎖無法跨越多個進程/機器,那就只能單獨找一臺服務器作為鎖的管理者,該服務器可以使用 Redis 來實現分布式鎖。

某個客戶端執行買票請求前,先訪問 Redis,在 Redis 上設置一個鍵值對。比如 key 就是車次,value 隨便設置個值 (比如 1)。

當另一個客戶端也想要訪問買票請求時,也先訪問 Redis,在 Redis 上設置一個 key 為該車次的鍵值對,如果發現 key 已經設置過了,說明有其他客戶端正在處理該車次的票,則該客戶端要么直接放棄,要么等待。

而當該客戶端處理完買票請求后,直接刪除該 key 即可。就相當于是解鎖操作。

如何實現?可以使用 Redis 的 setnx 命令,該命令的作用是設置一個鍵值對,當且僅當鍵不存在時才設置成功。

引入過期時間

但是上述方案存在問題,如果某個客戶端設置完鎖 key 后,突然掛掉了,此時鎖一直存在,其他客戶端就無法獲取到鎖,導致其他客戶端無法正常處理買票請求。

所以,我們可以給鎖引入一個過期時間,比如 1 秒,即這個鎖的最長持有時間,如果鎖的過期時間到了,則自動釋放鎖。

如何實現?可以使用 Redis 的 set ex nx 命令,在設置鎖的同時把過期時間加上。

能否先設置鎖,然后通過 expire 的方式設置過期時間?答案不行的,因為這是兩條命令了,就不是原子的了,就有概率發生 “線程安全問題”。

引入校驗ID

上述依然存在問題,是否可能會出現 服務器1 設置鎖,服務器2 誤刪鎖。答案是可能的,保不齊代碼哪里會出現 bug,導致鎖被誤刪。

正常的解鎖操作是必須由加鎖的這一方執行的。

所以,我們可以給每個服務器設置一個唯一的 ID,在設置鎖,將這個鎖的 value 設置為這個 ID。

在解鎖時,先獲取到該鎖,校驗其 value 是否與當前服務器的 ID 相同,如果相同,則執行解鎖操作。如果不相同,則忽略該操作。

引入 Lua 腳本

上述解鎖的判斷依然可能存在問題,根本原因還是可能造成 “線程安全問題”。

校驗和刪除這兩個操作,不是原子的,則可能會出現下圖的情況:在這里插入圖片描述

如果發生上述情況,命令按照上圖的順序執行,會導致 服務器1 刪除鎖之后,服務器3 來加鎖了,但是馬上又被 服務器2 給刪了。

我們可以使用事務將這兩個操作打包成一個原子的操作,但是,Redis 的事務比較雞肋,形同虛設。

Redis 官方文檔明確說,Lua 腳本可以作為事務的替代方案。Redis 在執行 Lua 腳本時,就相當于是執行一條命令,只有全部命令都執行完了,才會服務其他客戶端。

使用 Lua 腳本完成上述功能:

if redis.call("setnx", KEYS[1]) == ARGV[1] thenreturn redis.call("expire", KEYS[1])
elsereturn 0
end

上述代碼可以編寫成一個 .lua 后綴的文件,由 redis-cli 或者 redis-plus-plus 或者 jedis 等客戶端加載,并發送給 Redis 服務器,由 Redis 服務器來執行這段邏輯。

一個 lua 腳本會被 Redis 服務器以原子的方式來執行。

引入看門狗

上述的方案依然存在問題,就是鎖的過期時間較為固定。

如果鎖的過期時間設置的過短,可能業務邏輯還沒處理完就釋放鎖了。
如果鎖的過期時間設置的過長,導致鎖的持有時間太長,導致其他客戶端無法正常處理請求。

所以我們采用動態續約的機制,引入一個 “看門狗” 線程,每隔一段時間,如果當前業務還沒執行完,就續上鎖的過期時間。

引入 Redlock 算法

實踐中的 Redis 一般是以集群的方式部署的(至少是主從的形式,而不是單機)。那么就可能出現以下比較極端的情況:

  • 服務器1master 節點進行加鎖操作。這個寫入 key 的過程剛剛完成,master 就掛了;slave 節點升級成了新的 master 節點。
  • 但是由于剛才寫入的這個 key 尚未來得及同步給 slave,此時就相當于 服務器1 的加鎖操作形同虛設了,服務器2 仍然可以進行加鎖(即給新的 master 寫入 key。因為新的 master 不包含剛才的 key)。

為了解決這個問題,Redis 官方提出了 Redlock 算法。

我們引入一組 Redis 節點。其中每一組 Redis 節點都包含一個主節點和若干從節點。并且組和組之間存儲的數據都是一致的,相互之間是 “備份” 關系(而并非是數據集合的一部分。這點有別于 Redis cluster)。

加鎖的時候,按照一定的順序,寫多個 master 節點。在寫鎖的時候需要設定操作的 “超時時間”。比如 50ms。即如果 setnx 操作超過了 50ms 還沒有成功,就視為加鎖失敗。

如果給某個節點加鎖失敗,就立即再嘗試下一個節點。

當加鎖成功的節點數超過總節點數的一半,才視為加鎖成功。

這樣的話,即使有某些節點掛了,也不影響鎖的正確性。

同理,釋放鎖的時候,也需要把所有節點都進行解鎖操作。(即使是之前超時的節點,也要嘗試解鎖,盡量保證邏輯嚴密)。

簡而言之,Redlock 算法的核心就是,加鎖操作不能只寫給一個 Redis 節點,而要寫給多個!!!

分布式系統中任何一個節點都是不可靠的。最終的加鎖成功結論是 “少數服從多數的”。

證邏輯嚴密)。

簡而言之,Redlock 算法的核心就是,加鎖操作不能只寫給一個 Redis 節點,而要寫給多個!!!

分布式系統中任何一個節點都是不可靠的。最終的加鎖成功結論是 “少數服從多數的”。

由于一個分布式系統不至于大部分節點都同時出現故障,因此這樣的可靠性要比單個節點來說靠譜不少。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/916184.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/916184.shtml
英文地址,請注明出處:http://en.pswp.cn/news/916184.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

OpenCV-圖像預處理?【圖像顏色空間轉換、灰度化實驗、二值化處理、鏡像翻轉 和 仿射變換】

文章目錄先言一、圖像顏色空間轉換1.RGB顏色空間2.顏色加法3.顏色加權加法4.HSV顏色空間5.圖像轉換(cvtColor())二、灰度實驗1.灰度圖2.圖像灰度化(最大值法)3.圖像灰度化(平均值法)4.圖像灰度化&#xff0…

APP逆向 day9 安卓開發基礎

一.前言 app逆向當然要學安卓基礎啦!今天我們來教安卓基礎當然,安卓基礎不會教的很多,比java還要少,還是那句話,了解就好。 二.安卓環境搭建 2.1 安卓介紹 如果做安卓開發 需要會java代碼安卓SDK(安卓提供的內置…

Jmeter的元件使用介紹:(三)配置元件詳解02

六、計數器 可以用來做一些變量自增操作。 1、Starting value:定義初始值 2、遞增:定義每次執行遞增多少 3、Maximum value:定義承受的最大值 4、數據格式:可以不填,也可以定義成000;001;002等等任意格式都行。(1)如…

JavaWeb學習打卡15(JSP標簽、JSTL標簽、EL表達式)

EL表達式&#xff1a;${ }獲取數據執行運算獲取web開發的常用對象在pom.xml 文件中導入JSP、JSTL相關依賴&#xff1a;<!--JSP依賴--><!-- https://mvnrepository.com/artifact/javax.servlet.jsp/javax.servlet.jsp-api --><dependency><groupId>java…

7.22數據結構——順序表

文章目錄一、思維導圖二、實現順序表的功能代碼head.htest.cmain.c一、思維導圖 二、實現順序表的功能代碼 head.h #ifndef __HEAD_H__ #define __HEAD_H__#include <stdio.h> #include <string.h> #include <stdlib.h> //數組的最大長度 #define MAXSIZE …

【如何無限制免費試用 IDEA || Pycharm(JB 全家桶)】

如何無限制免費試用 IDEA || Pycharm(JB 全家桶) 一、目標:解決 JB 全家桶試用時長痛點 如果你是程序員,大概率用過 JetBrains 家的 IDE——IDEA 寫 Java、Pycharm 寫 Python、WebStorm 做前端,體驗確實頂流,但官方 30 天試用到期后,動輒幾千的年費實在讓人肉痛。 咱…

Qt(資源庫和按鈕組)

這一節是對上一節的補充&#xff0c;上一節提到QLabel類和QAabstractButton類&#xff0c;這節內容&#xff1a;1.如設置資源庫&#xff0c;使用資源設置圖片2. 使用按鈕組管理多個按鈕。一、資源庫1. 資源庫作用Qt的資源庫&#xff08;Resource System&#xff0c;.qrc文件&am…

一道檢驗編碼能力的字符串的題目

#include<iostream> #include<vector> #include<string> using namespace std; int bNum0,gNum0; int findEnd(string& s,int si){int lens.size();//當前字母在哪個字符串中,存入comp中string comp;if(s[si]b||s[si]o||s[si]y){comp"boy";bNu…

UniApp X 網絡請求避坑指南:從 JS 到 UTS 的 JSON 數據處理全解析

在 UniApp 開發中&#xff0c;我們經常需要通過 uni.request 獲取服務器返回的 JSON 數據&#xff0c;并將其綁定到頁面或進行邏輯處理。但在 UniApp X&#xff08;基于 UTS&#xff09; 中&#xff0c;由于引入了 強類型語言特性&#xff0c;處理 JSON 數據的方式與 JS 有明顯…

iOS 網絡請求常用依賴庫與系統自帶 API 介紹與示例

iOS 網絡請求常用依賴庫與系統自帶 API 介紹與示例 在 iOS 開發中&#xff0c;進行網絡請求是幾乎所有應用都不可或缺的功能。開發者有多種選擇來處理網絡通信&#xff0c;從系統自帶的 URLSession 到各種流行的第三方庫。下面我將為您介紹 URLSession、AFNetworking、Alamofir…

JavaScript 中 let 在循環中的作用域機制解析

一、let在循環中的特殊性 let作為ES6引入的塊級作用域聲明&#xff0c;在循環結構中存在特殊行為&#xff0c;其核心區別于var的函數作用域特性。理解這一特性對于編寫正確的閉包邏輯至關重要。 在 ECMAScript 規范里&#xff0c;let聲明的變量具有塊級作用域特性&#xff0c;這…

@Subscribe@AllowConcurrentEvents解析這兩個注解

@Subscribe@AllowConcurrentEvents解析這兩個注解 @Subscribe 和 @AllowConcurrentEvents 是 Guava EventBus(Google 開源的事件總線框架)中用于處理事件訂閱的注解,主要用于實現組件間的解耦通信。下面分別解析: 1. @Subscribe 注解 作用:標記一個方法為事件訂閱者方法,…

好看的小程序推廣單頁HTML源碼 可用作導航頁

內容目錄一、詳細介紹二、效果展示1.部分代碼2.效果圖展示三、學習資料下載一、詳細介紹 響應式的小程序推廣單頁HTML源碼。這個設計采用了現代化的UI元素&#xff0c;包含吸引人的標題、特性展示、二維碼區域和行動號召按鈕。 二、效果展示 1.部分代碼 代碼如下&#xff0…

華為倉頡編程語言實踐體驗

華為倉頡編程語言實踐體驗 目前華為倉頡編程語言因為其推出時間較短&#xff0c;生態系統不完善。官網資料權威&#xff0c;但比較龐大難懂。快速實驗入門&#xff0c;是學習一門編程語言的法寶。網上靠譜的資料稀少&#xff0c;特此撰文介紹&#xff0c;幫助初學者減少挫折感&…

YOLOv11實戰,使用YOLOv11訓練自己的數據集和推理(附YOLOv11網絡結構圖)

2024年計算機視覺領域的顛覆性突破,YOLOv11以22%的參數量減少和0.3%的mAP提升重新定義實時目標檢測的邊界 本文將手把手帶你完成YOLOv11的全流程實戰,包含環境配置、數據準備、模型訓練、推理部署及創新優化方案,并深度解析其網絡架構設計思想。 一、YOLOv11核心創新解析 …

macOS xcode打包ios測試ipa應用包

可以參考&#xff1a; https://blog.csdn.net/sinat_34104446/article/details/133684756 過程中遇到很多稀奇古怪的報錯&#xff0c;基本重啟電腦即可解決。。。在我按照上面的步驟申請并導入新證書后&#xff0c;還遇到了一個問題&#xff1a;解決辦法&#xff1a; https://b…

STM32基礎知識學習筆記:ICODE、DCODE、DMA等常見名詞的解釋

基于AI生成內容。 ICODEICODE&#xff1a;指令總線&#xff08;Instruction Bus&#xff09; 主要用于處理 CPU 對程序指令的讀取操作。它是 STM32 存儲架構中重要的組成部分&#xff0c;與數據總線&#xff08;DCODE&#xff09;、系統總線&#xff08;System Bus&#xff09;…

誰將統治AI游戲時代?騰訊、網易、米哈游技術暗戰

游戲行業的“產能天花板”正被AI技術轟然擊穿。騰訊、網易、米哈游……所有的游戲廠商都在押注AI&#xff0c;騰訊混元發布混元游戲視覺生成平臺&#xff0c;分鐘級生成高精度游戲角色&#xff1b;網易《蛋仔派對》借AI實現UGC創作平民化&#xff1b;米哈游新作更以實時多模態對…

基于springboot的工商局商家管理系統

博主介紹&#xff1a;java高級開發&#xff0c;從事互聯網行業六年&#xff0c;熟悉各種主流語言&#xff0c;精通java、python、php、爬蟲、web開發&#xff0c;已經做了六年的畢業設計程序開發&#xff0c;開發過上千套畢業設計程序&#xff0c;沒有什么華麗的語言&#xff0…

ABP VNext + Razor 郵件模板:動態、多租戶隔離、可版本化的郵件與通知系統

&#x1f680; ABP VNext Razor 郵件模板&#xff1a;動態、多租戶隔離、可版本化的郵件與通知系統 &#x1f4da; 目錄&#x1f680; ABP VNext Razor 郵件模板&#xff1a;動態、多租戶隔離、可版本化的郵件與通知系統&#x1f31f; 一、TL;DR&#x1f4c8; 二、系統流程圖…