面試被問Redis鎖,我臉都綠了......
Setnx
RedLock
Redisson
Setnx
目前通常所說的 Setnx 命令,并非單指 Redis 的 setnx key value 這條命令。
一般代指 Redis 中對 Set 命令加上 NX 參數(shù)進(jìn)行使用,Set 這個命令,目前已經(jīng)支持這么多參數(shù)可選:
SET?key?value?[EX?seconds|PX?milliseconds]?[NX|XX]?[KEEPTTL]當(dāng)然了,就不在文章中默寫 API 了,基礎(chǔ)參數(shù)還有不清晰的,可以蹦到官網(wǎng)。

點擊領(lǐng)取福利:知乎3萬贊,累計5000頁的 Java 技術(shù)棧手冊,已被瘋轉(zhuǎn)2.6w次!
那么為什么要使用 PX 30000 去設(shè)置一個超時時間?是怕進(jìn)程 A 不講道理啊,鎖沒等釋放呢,萬一崩了,直接原地把鎖帶走了,導(dǎo)致系統(tǒng)中誰也拿不到鎖。

就算這樣,還是不能保證萬無一失。如果進(jìn)程 A 又不講道理,操作鎖內(nèi)資源超過筆者設(shè)置的超時時間,那么就會導(dǎo)致其他進(jìn)程拿到鎖,等進(jìn)程 A 回來了,回手就是把其他進(jìn)程的鎖刪了,如圖:

當(dāng)進(jìn)程 B 操作完成,去釋放鎖的時候(圖中 T8 時刻):

當(dāng)解鎖的時候,先獲取 Value 判斷是否是當(dāng)前進(jìn)程加的鎖,再去刪除。偽代碼:
String?uuid?=?xxxx;
//?偽代碼,具體實現(xiàn)看項目中用的連接工具
//?有的提供的方法名為set?有的叫setIfAbsent
set?Test?uuid?NX?PX?3000
try{
//?biz?handle....
}?finally?{
????//?unlock
????if(uuid.equals(redisTool.get('Test')){
????????redisTool.del('Test');
????}
}這回看起來是不是穩(wěn)了?相反,這回的問題更明顯了,在 Finally 代碼塊中,Get 和 Del 并非原子操作,還是有進(jìn)程安全問題。

搞清劣勢所在,才能更好的完善。
上文中最后這段代碼,還是有很多公司在用的。
大公司實現(xiàn)規(guī)范,但是小司小項目雖然存在不嚴(yán)謹(jǐn),可并發(fā)倒也不高,出問題的概率和大公司一樣低。
-- 魯迅

那么刪除鎖的正確姿勢之一,就是可以使用 Lua 腳本,通過 Redis 的 eval/evalsha 命令來運行:
-- lua刪除鎖:
-- KEYS和ARGV分別是以集合方式傳入的參數(shù),對應(yīng)上文的Test和uuid。
--?如果對應(yīng)的value等于傳入的uuid。
if?redis.call('get',?KEYS[1])?==?ARGV[1]?
????then?
????--?執(zhí)行刪除操作
????????return?redis.call('del',?KEYS[1])?
????else?
????--?不成功,返回0
????????return?0?
end
通過 Lua 腳本能保證原子性的原因說的通俗一點:就算你在 Lua 里寫出花,執(zhí)行也是一個命令(eval/evalsha)去執(zhí)行的,一條命令沒執(zhí)行完,其他客戶端是看不到的。
1.?setnx?Test?uuid
2.?expire?Test?30筆者曾閱讀過一位大佬的文章,其中就有一句指導(dǎo)入門者的面試小套路,具體文字忘記了,大概意思如下:說到 Redis 鎖的時候,可以先從 Setnx 講起,最后慢慢引出 Set 命令的可以加參數(shù),可以體現(xiàn)出自己的知識面。
如果有緣你也閱讀過這篇文章,并且學(xué)到了這個套路,作為本文的筆者我要加一句提醒:請注意你的工作年限!首先回答官網(wǎng)表明即將廢棄的命令,再引出 Set 命令七年前的“新特性”,如果是剛畢業(yè)不久的人這么說,面試官會以為自己穿越了。
你套路面試官,面試官也會套路你。??
-- vt?沃茲基碩德
Redisson
Redisson 是 Java 的 Redis 客戶端之一,提供了一些 API 方便操作 Redis。
但是 Redisson 這個客戶端可有點厲害,筆者在官網(wǎng)截了僅僅是一部分的圖:

筆者也非常嚴(yán)謹(jǐn)?shù)乃伎剂艘幌拢哼@么厲害的東西哪能寫廢代碼?
?
其實筆者仔細(xì)看了一下,加鎖解鎖的 Lua 腳本考慮的非常全面,其中就包括鎖的重入性,這點可以說是考慮非常周全,我也隨手寫了代碼測試一下:

RedLock

筆者大概畫了一下對紅鎖的理解:

RedLock 作者指出,之所以要用獨立的,是避免了 Redis 異步復(fù)制造成的鎖丟失,比如:主節(jié)點沒來的及把剛剛 Set 進(jìn)來這條數(shù)據(jù)給從節(jié)點,就掛了。
順序向五個節(jié)點請求加鎖
根據(jù)一定的超時時間來推斷是不是跳過該節(jié)點
三個節(jié)點加鎖成功并且花費時間小于鎖的有效期
認(rèn)定加鎖成功
回頭看看 Redis 官網(wǎng)關(guān)于紅鎖的描述,就在這篇描述頁面的最下面,你能看到著名的關(guān)于紅鎖的神仙打架事件。

官方掛人,最為致命。開個玩笑,要是質(zhì)疑能被官方掛到官網(wǎng),說明肯定是有價值的。
Martin Kleppmann 的質(zhì)疑貼
Antirez 的反擊貼
總結(jié)
看了這么多,是不是發(fā)現(xiàn)如何實現(xiàn),都不能保證 100% 的穩(wěn)定。程序就是這樣,沒有絕對的穩(wěn)定,所以做好人工補償環(huán)節(jié)也是重要的一環(huán),畢竟:技術(shù)不夠,人工來湊!
作者:Vt
編輯:陶家龍
出處:https://juejin.im/post/5e61a454e51d4526f071e1df
之前給大家發(fā)過四份Java面試寶典,這次新增了更全面的資料,相信在跳槽前準(zhǔn)備準(zhǔn)備,基本沒大問題。
《java基礎(chǔ):設(shè)計模式等》(初中級)
《JVM:整理BAT最新題庫》《并發(fā)編程》(中高級)
《分布式微服務(wù)架構(gòu)》《架構(gòu)|軟技能》(資深)
《一線互聯(lián)網(wǎng)公司面試指南》(資深)
分別適用于初中級,中高級,資深級工程師的面試復(fù)習(xí)。內(nèi)容包含java基礎(chǔ)、JVM、并發(fā)編程、分布式微服務(wù)、架構(gòu)|軟技能、算法等等。
學(xué)習(xí)視頻包含深入運行時數(shù)據(jù)區(qū)、垃圾回收、詳解類裝載過程及類加載機制、手寫Spring-IOC容器、redis入門到高性能緩存組件等等
獲取方式:加小編微信即可領(lǐng)取,資料持續(xù)更新!
點贊是最大的支持?![]()
