分布式鎖 redis Redisson

lfssst 2022-01-07 18:16:08 阅读数:433

分布式 分布 redis redisson

在這裏插入圖片描述

1.購票占座

​ 11車 7D的一比特只能被一個人使用

java可以使用sync實現,但是占座服務可能多個jvm同時搶座比特,sync只能給一個jvm中的資源加鎖。

分布式鎖 redis

[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-igELvge5-1637651571703)(/Users/zhaokaijie/Library/Application Support/typora-user-images/image-20211120200522081.png)]

Redis統一管理一把鎖搶到鎖的再進行統一的操作

在這裏插入圖片描述

setnx 判斷加鎖成功和鎖的互斥

expire 設置鎖的過期時間

在這裏插入圖片描述

這樣客戶端中斷30s 鎖會釋放

在這裏插入圖片描述

單純這倆命令不完美

解决方案:1. Set lock “1234” EX 1000NX/PX s/ms

​ 要麼都成功 要麼都失敗 具有原子性

 2. lua 脚本 lua中無論有多少命令都認為是一個任務 同時成功 失敗

[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-5wpKHNDp-1637651571720)(/Users/zhaokaijie/Library/Application Support/typora-user-images/image-20211120201525807.png)]

參數解析:

1.EX 設置的時間 單比特為秒

2.PX 設置的時間 單比特為毫秒

3.NX 不存在設置值 eg:“123”

4.XX 不存在設置值 eg:“123” -> “1234”

在這裏插入圖片描述

具有原子性,設置鎖和失效時間同時完成

EVAL script numkeys key [key …] arg [arg …]

在這裏插入圖片描述

lua脚本的意思是,返回KEYS[1], KEYS[2] ,ARGV[1],ARGV[2] 2個key k1,k2

,ARGV[1],ARGV[2] a1,a2

第二行意思是 返回KEYS[1], KEYS[2] ,ARGV[1],ARGV[2] 3個key k1,k2 a1

ARG[1] 為a2 ARGV【2】沒有值

在這裏插入圖片描述

在這裏插入圖片描述

Test2 這個鎖可以得到

[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-H183Ztqy-1637651571762)(/Users/zhaokaijie/Library/Application Support/typora-user-images/image-20211120203453480.png

1.沒有判斷是否是我的鎖

  1. get 和 到delete之前有時間差

    要保障解鎖的原子性

    [外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-p5husyJx-1637651571765)(/Users/zhaokaijie/Library/Application Support/typora-user-images/image-20211120204131927.png)]

嚴禁就都用原子性

在這裏插入圖片描述

鎖的時長是30s,10s的時候客戶端1申請鎖後成功獲得鎖,可以去修改文件,但是35s的時候發生了STW fullGC,40時候鎖到期之後,60s時候客戶端2申請鎖並獲得鎖,並去寫入文件,當75s時STW結束,繼續修改文件發生錯誤

STW引起的鎖過期的問題,網絡波動也會造成

解决方式:

1.采用樂觀鎖的方式,侵入代碼中增加版本號

2.用watch dog將鎖自動延期

[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-inJkMXdL-1637651571774)(/Users/zhaokaijie/Library/Application Support/typora-user-images/image-20211122091140173.png)]

侵入代碼加入版本號,客戶端1第一次得到鎖的時候編寫文件的version=33,之後發生STW,在STW期間,失去鎖,客戶端2獲得鎖並且在寫入文件的過程中將version改變成了34,當客戶端1完成STW之後先要繼續操作文件的時候發現version已經是34了,不能繼續編輯文件

在這裏插入圖片描述

redis中鎖重構的功能比較單薄

鎖是可以重入的,一個線程可以進入多次

redisson已經想好了一些場景和需要的鎖

[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-qSyPgqoR-1637651571782)(/Users/zhaokaijie/Library/Application Support/typora-user-images/image-20211120205939482.png)]

可以實現基本數據類型 String,List,Hash

@Test
public void testRBucketExamples() {

// RList 繼承了 java.util.List 接口
RBucket<String> rstring = client.getBucket("redission:test:bucket:string");
rstring.set("this is a string");
RBucket<UserDTO> ruser = client.getBucket("redission:test:bucket:user");
UserDTO dto = new UserDTO();
dto.setToken(UUID.randomUUID().toString());
ruser.set(dto);
System.out.println("string is: " + rstring.get());
System.out.println("dto is: " + ruser.get());
client.shutdown();
}
@Test
public void testListExamples() {

// 默認連接上 127.0.0.1:6379
// RList 繼承了 java.util.List 接口
RList<String> nameList = client.getList("redission:test:nameList");
nameList.clear();
nameList.add("張三");
nameList.add("李四");
nameList.add("王五");
nameList.remove(-1);//删除王五
System.out.println("List size: " + nameList.size());
boolean contains = nameList.contains("李四");
System.out.println("Is list contains name '李四': " + contains);
nameList.forEach(System.out::println);
client.shutdown();
}

在這裏插入圖片描述

Redisson實現分布式鎖

 @Test
public void testLockDemo() {

RLock disLock = client.getLock("DISLOCK");
boolean isLock = false;
try {

disLock.lock(); //默認30s
// isLock = disLock.tryLock(20000, 1500000, TimeUnit.MILLISECONDS);
System.out.println(isLock);
if (isLock) {

//TODO if get lock success, do something;
Thread.sleep(15000);
}
} catch (Exception e) {

} finally {

// 無論如何, 最後都要解鎖
//disLock.unlock();
}
}

在這裏插入圖片描述

默認時間是30s

isLock = disLock.tryLock(20000, 1500000, TimeUnit.MILLISECONDS)

[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-5mVUouAO-1637651571789)(/Users/zhaokaijie/Library/Application Support/typora-user-images/image-20211122100422649.png)]

鎖互斥的理論 key相同的鎖不會

在這裏插入圖片描述

@Test
public void testLockDemo2() {

RLock disLock = client.getLock("DISLOCK");
boolean isLock = false;
try {

isLock = disLock.tryLock(2000, 1500000, TimeUnit.MILLISECONDS);
isLock = disLock.tryLock(2000, 1500000, TimeUnit.MILLISECONDS);
isLock = disLock.tryLock(2000, 1500000, TimeUnit.MILLISECONDS);
} catch (Exception e) {

} finally {

// 無論如何, 最後都要解鎖
disLock.unlock();
disLock.unlock();
disLock.unlock();
}
}

[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-wCDc3BhS-1637716392551)(/Users/zhaokaijie/Library/Application Support/typora-user-images/image-20211123163714322.png)]

加鎖一次value增加1,解鎖一次-1,最後鎖失效

[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-dmSTofiU-1637716392553)(/Users/zhaokaijie/Library/Application Support/typora-user-images/image-20211123164239659.png)]

1.獲取鎖:生成鎖1.先生成“DISLOCK”,生成UUID,設置過期時間

2.判斷key是否存在,不存在設置字段值為1,此過程就是生成鎖

3.key存在,判斷字段是否存在,也就是判斷是不是自己的鎖

4.key不存在,字段不存在,鎖互斥

5.key存在,鎖重構,字段值+1

[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-CQmRrV0R-1637716392556)(/Users/zhaokaijie/Library/Application Support/typora-user-images/image-20211123182109351.png)]

existe 存在

hexists 都存在

hincrby 增加值

pexpire 生存時間 毫秒

[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-Lne1F4fJ-1637716392558)(/Users/zhaokaijie/Library/Application Support/typora-user-images/image-20211123183501692.png)]

KEYS[1] = DISLOCK 鎖的名稱

KEYS[2] :訂閱DISLOCK鎖的狀態,只要釋放就可以占用

ARGV[1]:0 狀態

ARGV[2]:生存時間

ARGV[3]:UUID

1.key不存在直接廣播消息,鎖不存在

2.key字段存在,字段值-1

​ 3.字段值大於0,重新設置過期時間

​ 4.字段值小於0,直接廣播消息,鎖不存在

發布0 這樣訂閱的都可以獲得鎖

[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-G43I9yhw-1637716392561)(/Users/zhaokaijie/Library/Application Support/typora-user-images/image-20211123185834273.png)]
[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-dXwgczju-1637716392563)(/Users/zhaokaijie/Library/Application Support/typora-user-images/image-20211124082103189.png)]

[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-VsSWlJB1-1637716392566)(/Users/zhaokaijie/Library/Application Support/typora-user-images/image-20211124084534385.png)]

只對

disLock.lock();

有用 ,每10s監聽一次,沒有完成重回30s。

在這裏插入圖片描述

[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-wOQ0QRly-1637716392573)(/Users/zhaokaijie/Library/Application Support/typora-user-images/image-20211124085231046.png)]

分120段每段5個庫存,這樣5*120 = 600,就達到了每秒600訂單的吞吐量

[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-LUUqqahO-1637716392576)(/Users/zhaokaijie/Library/Application Support/typora-user-images/image-20211124085727834.png)]

根據skuid和分段去减

[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-MpL6QuGf-1637716392578)(/Users/zhaokaijie/Library/Application Support/typora-user-images/image-20211124085913889.png)]

搶占分段鎖,隨機到一個分段

1.搶占成功,秒殺下單

2.搶占失敗 ,是否超時,未超時,嘗試下一個分段

​ 3.搶占成功,秒殺下單

​ 4.搶占失敗,回到2

5.超時搶鎖失敗

1,3,5 結束

版权声明:本文为[lfssst]所创,转载请带上原文链接,感谢。 https://gsmany.com/2022/01/202201071816083275.html