成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

用Redis構建一把高性能的鎖

存儲 存儲軟件 Redis
學過JAVA多線程的朋友都知道,為了防止多個線程同時執行同一段代碼,可以用synchronized關鍵字或JAVA API中ReentrantLock類來控制。

[[267910]]

背景:

筆者所在的公司,上周末經歷了一場大促活動后,系統暴露出這樣一個問題:分布式鎖使用的zk鎖,由于當天大促用戶量比較多,系統瘋狂的加鎖釋放鎖,***zk承受不住這么大的壓力宕機。由于馬上就要618,為了避免再次發生這樣的事情,公司決定把所有系統的zk鎖都替換為高性能的Redis鎖。

在這里簡單的提一下,zk鎖性能比redis低的原因:zk中的角色分為leader,flower,每次寫請求只能請求leader,leader會把寫請求廣播到所有flower,如果flower都成功才會提交給leader,其實這里相當于一個2PC的過程。在加鎖的時候是一個寫請求,當寫請求很多時,zk會有很大的壓力,***導致服務器響應很慢。

正題:

什么情況下需要加鎖?

當多個線程、用戶同時競爭同一個資源時,需要加鎖。比如,下訂單減庫存,搶票,選課,搶紅包等。如果在此處沒有鎖的控制,會導致很嚴重的問題,下訂單減庫存的時候不加鎖,會導致商品超賣;搶票的時候不加鎖,會導致兩個人搶到同一個位置;選課的時候沒有鎖的控制,導致選課成功的人數大于教室的座位數;搶紅包時沒有鎖的控制,搶到紅包的金額大于紅包的實際金額。

什么是分布式鎖?

學過JAVA多線程的朋友都知道,為了防止多個線程同時執行同一段代碼,可以用synchronized關鍵字或JAVA API中ReentrantLock類來控制。

但是目前幾乎任何一個系統都往往部署多臺機器的,單機部署的應用很少,synchronized和ReentrantLock發揮不出任何作用,此時就需要一把全局的鎖,來代替JAVA中的synchronized和ReentrantLock。

當Thread1線程獲取到鎖,執行鎖中的代碼,其他線程或其他機器再次請求該鎖,發現鎖被Thread1占用,加鎖失敗。當Thread1釋放鎖,其他線程則可以獲取到鎖并執行相應的操作。

我們可以用Jedis中是setnx命令來構建這把鎖,首先,我列舉一些錯誤的構建鎖的方式:

錯誤例子1

  1. Long lock= jedis.setnx(key,value); 
  2. if(lock>0){ 
  3. //執行業務邏輯 

通過setnx命令創建一個key、value,如果key不存在,則加鎖成功。這樣做有什么問題呢?如果執行加鎖操作成功,在釋放鎖的時候,系統宕機,導致這個key永遠不會被del掉,也就是說其他線程一直獲取不到鎖,

導致死鎖發生。為了避免這種情況,請看下面的代碼

錯誤例子2

  1. Long lock= jedis.setnx(key,value); 
  2. if(lock>0){ 
  3.    jedis.expire(key,expireTime); 

和上面的例子類似,唯一不同的是這里多了一步設置key過期時間的操作。如果在del的時候系統宕機,等過期時間一到,Redis會刪除這個key。

其他線程可以再次獲取鎖。這樣就可以萬無一失了嗎?這里有一個問題,如果在***步setnx成功后,突然網絡閃斷,expire命令執行失敗,同樣也有死鎖的風險。這兩步并不具備原子性,不保證全部成功或全部失敗。

正確的構建方式

  1. public static boolean getDistributedLock(Jedis jedis, String lockKey, String requestId, int expireTime) { 
  2.     String result = jedis.set(lockKey, requestId, "NX""EX", expireTime); 
  3.     if (LOCK_SUCCESS.equals(result)) { 
  4. return true
  5.      } 
  6. return false

參數解釋:

key:鍵

value:值

nx:如果當前key存在,則set失敗,否則成功

ex:設置key的過期時間

expireTime:key的過期時間,時間到了,Redis會自動刪除key和value。

這個命令,將上面的錯誤例子2中的兩個操作合為一個原子操作,保證了同時成功或同時失敗。

解鎖方式:

錯誤例子1:

  1. jedis.del(key); 

執行這個操作的線程,不去判斷鎖的擁有者就刪除鎖。

還記的set命令可以設置value嗎?在獲取鎖的操作時,主要是判斷key是否存在,那么value有什么用呢??如果在刪除鎖的時候,不去判斷當前鎖的擁有者,任何線程都可以釋放鎖。這個時候,value值就起到作用了。

錯誤例子2:

  1. if(value==jedis.get(key)){ 
  2.     jedis.del(key); 

我們在加鎖的時候,可以將value設置成唯一標識當前線程的一個值,這個值可以是一個UUID,當釋放鎖的時間,判斷value是否和set時的值相同,如果相同,則說明加鎖和釋放鎖是同一個線程,允許釋放。否則釋放鎖失敗。

這樣就可以絕對安全了嗎??答案當然是否定的。這步操作,同樣不具備原子性。如果ThreadA在執行value==jedis.get(key)返回true后的瞬間,del命令還沒來的及執行,key過期了,而此時ThreadB獲取到鎖,之后ThreadA執行del命令,把ThreadB的鎖釋放掉了。

所以要保證兩部操作的原子性,我們不得不利用簡單的Lua腳本。

正確的解鎖姿勢:

  1. public static boolean releaseDistributedLock(Jedis jedis, String lockKey, String requestId) { 
  2. String script = "if redis.call('get', KEYS[1]) == ARGV[1] then return redis.call('del', KEYS[1]) else return 0 end"
  3.     Object result = jedis.eval(script, Collections.singletonList(lockKey), Collections.singletonList(requestId)); 
  4.     if (RELEASE_SUCCESS.equals(result)) { 
  5.         return true
  6.     } 
  7.     return false

Redis在2.6后內部內嵌Lua腳本解釋器,所以我們可以通過簡單的Lua腳本來保證上述操作的原子性。代碼中的Lua腳本的的意思是:我們把LockKey賦值給KEYS[1],把RequestId賦值給ARGV[1],如果key中的值等于RequestId,返回true否則返回false。這樣就保證了釋放鎖操作時原子的,并且當前客戶端只會釋放當前客戶端的鎖。

責任編輯:武曉燕 來源: OutOfMemoryErro
相關推薦

2019-10-30 05:51:07

物聯網設備物聯網安全物聯網

2018-03-23 08:26:44

Hadoop集群SQL

2023-09-22 11:48:37

2022-06-30 08:04:16

Redis分布式鎖Redisson

2020-03-02 17:04:47

戴爾

2021-06-03 08:01:12

JVM性能優化

2016-07-15 10:37:37

云性能云計算

2012-02-07 09:33:14

2020-06-05 07:20:41

測試自動化環境

2011-12-15 13:28:57

2021-03-10 09:52:38

開發技能架構

2011-10-21 14:20:59

高性能計算HPC虛擬化

2011-10-25 13:13:35

HPC高性能計算Platform

2022-12-09 08:40:56

高性能內存隊列

2014-07-04 10:41:19

redis數據庫緩存

2021-08-26 06:00:29

密碼非對稱加密數據安全

2009-10-29 09:11:50

Juniper高性能網絡

2009-06-03 14:24:12

ibmdwWebSphere

2025-06-03 08:15:00

微服務架構異步任務隊列

2025-03-04 08:00:00

機器學習Rust開發
點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: 一级片在线观看视频 | 欧美日韩不卡 | 91精品免费视频 | 色婷婷av一区二区三区软件 | 亚洲区一区二 | 久久国产精品一区二区三区 | 亚洲成人av一区二区 | 日本a∨精品中文字幕在线 亚洲91视频 | 一区二区三区亚洲视频 | 欧美九九九 | 一区二区三区四区不卡 | 久久精品久久综合 | 亚洲综合一区二区三区 | 欧美一区二区三区四区视频 | 九九精品影院 | 久久人人网 | 亚洲精品久久久久久一区二区 | 久久久久久一区 | 99av成人精品国语自产拍 | www.天堂av.com| 黄色在线网站 | 国产精品成人在线 | 国产高清不卡 | 日韩视频精品在线 | 自拍第一页 | 亚洲精品区| 亚洲人成免费 | 草久在线 | 亚洲国产视频一区二区 | 日韩在线免费观看视频 | 中文字幕乱码一区二区三区 | 一区二区精品 | 波多野结衣二区 | 天天爽夜夜操 | 欧美一区二区视频 | 国产综合精品 | 特级黄一级播放 | 亚洲一区| 国产成人jvid在线播放 | 青草视频在线 | 一级片在线观看 |