日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 运维知识 > 数据库 >内容正文

数据库

Redis分布式锁如何提高可用性

發(fā)布時(shí)間:2025/3/17 数据库 30 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Redis分布式锁如何提高可用性 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

在編程中我們時(shí)常考慮高并發(fā)帶來的數(shù)據(jù)訪問不安全問題,那么我們?cè)趓edis中是否也要考慮呢?答案是肯定的,有人會(huì)問:redis不是單線程的嗎?對(duì)它是單線程,但是在某些情況他會(huì)出現(xiàn)信息更新,用戶沒有拿到最新數(shù)據(jù),然后導(dǎo)致操作有誤,看下圖

我們可以看到張三和李四同時(shí)請(qǐng)求這個(gè)number,但是李四執(zhí)行set后張三拿到的數(shù)據(jù)是沒有更新的,而后執(zhí)行了set命令,這樣這個(gè)number應(yīng)該是30才對(duì)。

Redis分布式鎖簡(jiǎn)介

redis給我們提供了分布式鎖,開啟鎖的指令是setnx(set if not exists),釋放鎖指令del,下面我們來嘗試

> setnx lookname mango(integer)?1> get lookname"mango"> del lookname(integer) 1> get mango(nil)

死鎖

這里我們思考一個(gè)問題,如果我們?cè)趫?zhí)行邏輯的時(shí)候出現(xiàn)異常了,那么這個(gè)鎖就會(huì)一直得不到釋放,導(dǎo)致死鎖,所以我們想辦法讓它自己釋放,添加一個(gè)過期時(shí)間這個(gè)指令是expire key seconds,即使我們不del,他它過了這個(gè)時(shí)間會(huì)自動(dòng)釋放

> setnx lookname mango(integer) 1>?expire?lookname?5(integer) 1> get lookname(nil)

還有一個(gè)問題,如果我在執(zhí)行setnx和expire的過程中出現(xiàn)了異常怎么辦?我們很快想到了用事務(wù),但是我們這里注意expire依賴setnx,expire這個(gè)是當(dāng)setnx搶到了資源的時(shí)候我們的expire才會(huì)執(zhí)行,否則是執(zhí)行不成功的,事務(wù)里面沒有if else語句。

為了解決這個(gè)問題,redis開源社區(qū)開發(fā)出很多分布式鎖的lib庫,也就是說我們每次使用分布式鎖的時(shí)候都要引入這個(gè)第三方的庫,關(guān)于這個(gè)問題作者在Redis2.8版本中加入了set擴(kuò)展,把這兩個(gè)命令放在一起執(zhí)行。

> set lookname mango ex 5 nxOK> get lookname"mango">?get?lookname????#?5s?后(nil)

超時(shí)問題

如果我們?cè)诩渔i后到這個(gè)鎖被釋放的時(shí)間內(nèi)的業(yè)務(wù)邏輯還沒有執(zhí)行完,那么這個(gè)時(shí)候出現(xiàn)了新的問題就是超時(shí),比如說我只想的邏輯需要30秒,而我的鎖過期時(shí)間只有10秒,此時(shí)我的邏輯還沒有處理完,問題就來了。

不使用過期時(shí)間

解決超時(shí)問題的快捷辦法就是不使用過期時(shí)間,我們需要在key后面添加一個(gè)比較隱私的隨機(jī)數(shù),例如name1564835、name6879425,達(dá)到減少key的碰撞,我們對(duì)這個(gè)key做上標(biāo)記,等執(zhí)行邏輯處理完后程序回收這個(gè)內(nèi)存。

延遲回收

如果10秒鐘不夠那么我們可以給這個(gè)key延長(zhǎng)回收時(shí)間,我們?cè)趉ey回收前判斷客戶端是否還在使用這個(gè)key,如果沒有使用這個(gè)key我們就什么都不做,如果在使用,我們就增加回收時(shí)長(zhǎng),如何做?我們可以在調(diào)用端重開一個(gè)線程,監(jiān)測(cè)快過期的key,客戶端可以給redis服務(wù)實(shí)例發(fā)送一個(gè)Lua腳本檢測(cè)這個(gè)key的值有沒有改變,如果沒有改變讓redis服務(wù)端延長(zhǎng)鎖的時(shí)間。

RedLock算法

我們?cè)谝粋€(gè)集群中,當(dāng)主節(jié)點(diǎn)掛掉時(shí),從節(jié)點(diǎn)會(huì)取而代之,原先第一個(gè)客戶端在主節(jié)點(diǎn)中申請(qǐng)成功了一把鎖,但是這把鎖還沒有來得及同步到從節(jié)點(diǎn),主節(jié)點(diǎn)突然掛掉了,然后從節(jié)點(diǎn)變成了主節(jié)點(diǎn)這個(gè)新的節(jié)點(diǎn)內(nèi)部沒有這個(gè)鎖,所以當(dāng)另一個(gè)客戶端過來請(qǐng)求加鎖時(shí),此時(shí)兩個(gè)客戶端都持有這個(gè)資源,問題又出現(xiàn)了。

但是這個(gè)問題是極小概率事件并且是非常短時(shí)間造成的,從分布式系統(tǒng)角度上我們是可以容忍這個(gè)問題的。但是我們希望redis完全不受影響,可以考慮 redlock。Redlock算法是由Antirez發(fā)明的,它的流程比較復(fù)雜,不過已經(jīng)有了很多開源的 library 做了良好的封裝,用戶可以拿來即用,比如 redlock-py。

redlock.Redlock()

RedLock算法原理:

1.獲取當(dāng)前時(shí)間(單位是毫秒)。

2.輪流用相同的key和隨機(jī)值在N個(gè)節(jié)點(diǎn)上請(qǐng)求鎖,在這一步里,客戶端在每個(gè)master上請(qǐng)求鎖時(shí),會(huì)有一個(gè)和總的鎖釋放時(shí)間相比小的多的超時(shí)時(shí)間。比如如果鎖自動(dòng)釋放時(shí)間是10秒鐘,那每個(gè)節(jié)點(diǎn)鎖請(qǐng)求的超時(shí)時(shí)間可能是5-50毫秒的范圍,這個(gè)可以防止一個(gè)客戶端在某個(gè)宕掉的master節(jié)點(diǎn)上阻塞過長(zhǎng)時(shí)間,如果一個(gè)master節(jié)點(diǎn)不可用了,我們應(yīng)該盡快嘗試下一個(gè)master節(jié)點(diǎn)。

3.客戶端計(jì)算第二步中獲取鎖所花的時(shí)間,只有當(dāng)客戶端在大多數(shù)master節(jié)點(diǎn)上成功獲取了鎖((N/2) +1),而且總共消耗的時(shí)間不超過鎖釋放時(shí)間,這個(gè)鎖就認(rèn)為是獲取成功了。

4.如果鎖獲取成功了,那現(xiàn)在鎖自動(dòng)釋放時(shí)間就是最初的鎖釋放時(shí)間減去之前獲取鎖所消耗的時(shí)間。

5.如果鎖獲取失敗了,不管是因?yàn)楂@取成功的鎖不超過一半(N/2+1)還是因?yàn)榭傁臅r(shí)間超過了鎖釋放時(shí)間,客戶端都會(huì)到每個(gè)master節(jié)點(diǎn)上釋放鎖,即便是那些他認(rèn)為沒有獲取成功的鎖。

注意:加鎖時(shí),它會(huì)向過半節(jié)點(diǎn)發(fā)送?set(key, value, nx=True, ex=xxx)?指令,只要過半節(jié)點(diǎn) set 成功,那就認(rèn)為加鎖成功。釋放鎖時(shí),需要向所有節(jié)點(diǎn)發(fā)送 del 指令。不過 Redlock 算法還需要考慮出錯(cuò)重試、時(shí)鐘漂移等很多細(xì)節(jié)問題,同時(shí)因?yàn)?Redlock 需要向多個(gè)節(jié)點(diǎn)進(jìn)行讀寫,意味著相比單實(shí)例 Redis性能會(huì)下降一些,代碼額外引入第三方lib。

有興趣的童鞋可以參考:Redlock(redis分布式鎖)原理分析?

?

一名正在搶救的coder

筆名:mangolove

CSDN地址:https://blog.csdn.net/mango_love

GitHub地址:https://github.com/mangoloveYu

總結(jié)

以上是生活随笔為你收集整理的Redis分布式锁如何提高可用性的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。