一. 什麼是分佈式鎖html
分佈式鎖其實能夠理解爲:控制分佈式系統有序的去對共享資源進行操做,經過互斥來保持一致性。java
舉個不太恰當的例子:假設共享的資源就是一個房子,裏面有各類書,分佈式系統就是要進屋看書的人,分佈式鎖就是保證這個房子只有一個門而且一次只有一我的能夠進,並且門只有一把鑰匙。而後許多人要去看書,能夠,排隊,第一我的拿着鑰匙把門打開進屋看書而且把門鎖上,而後第二我的沒有鑰匙,那就等着,等第一個出來,而後你在拿着鑰匙進去,而後就是以此類推redis
二. 保證分佈式鎖知足的四個條件安全
1.互斥性分佈式
2.安全性lua
3.避免死鎖spa
4.容錯code
三. 使用redis實現分佈式鎖htm
使用redis命令 set key value NX EX max-lock-time 實現加鎖blog
使用redis命令 EVAL 實現解鎖
加鎖:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
|
Jedis jedis =
new
Jedis(
"127.0.0.1"
,
6379
);
private
static
final
String SUCCESS =
"OK"
;
/**
* 加鎖操做
* @param key 鎖標識
* @param value 客戶端標識
* @param timeOut 過時時間
*/
public
Boolean lock(String key,String value,Long timeOut){
String var1 = jedis.set(key,value,
"NX"
,
"EX"
,timeOut);
if
(LOCK_SUCCESS.equals(var1)){
return
true
;
}
return
false
;
}
|
解讀:
加鎖操做:jedis.set(key,value,"NX","EX",timeOut)【保證加鎖的原子操做】
key就是redis的key值做爲鎖的標識,value在這裏做爲客戶端的標識,只有key-value都比配纔有刪除鎖的權利【保證安全性】
經過timeOut設置過時時間保證不會出現死鎖【避免死鎖】
NX,EX什麼意思?
NX:只有這個key不存才的時候纔會進行操做,if not exists;
EX:設置key的過時時間爲秒,具體時間由第5個參數決定
解鎖
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
|
Jedis jedis =
new
Jedis(
"127.0.0.1"
,
6379
);
private
static
final
Long UNLOCK_SUCCESS = 1L;
/**
* 解鎖操做
* @param key 鎖標識
* @param value 客戶端標識
* @return
*/
public
static
Boolean unLock(String key,String value){
String luaScript =
"if redis.call(\"get\",KEYS[1]) == ARGV[1] then return redis.call(\"del\",KEYS[1]) else return 0 end"
;
Object var2 = jedis.eval(luaScript,Collections.singletonList(key), Collections.singletonList(value));
if
(UNLOCK_SUCCESS == var2) {
return
true
;
}
return
false
;
}
|
解讀:
luaScript 這個字符串是個lua腳本,表明的意思是若是根據key拿到的value跟傳入的value相同就執行del,不然就返回0【保證安全性】
jedis.eval(String,list,list);這個命令就是去執行lua腳本,KEYS的集合就是第二個參數,ARGV的集合就是第三參數【保證解鎖的原子操做】
上述就實現了怎麼使用redis去正確的實現分佈式鎖,可是有個小缺陷就是鎖過時時間要設置爲多少合適,這個其實仍是須要去根據業務場景考量一下的
上面那只是講了加鎖與解鎖的操做,試想一下若是在業務中去拿鎖若是沒有拿到是應該阻塞着一直等待仍是直接返回,這個問題其實能夠寫一個重試機制,根據重試次數和重試時間作一個循環去拿鎖,固然這個重試的次數和時間設多少合適,是須要根據自身業務去衡量的
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
|
/**
* 重試機制
* @param key 鎖標識
* @param value 客戶端標識
* @param timeOut 過時時間
* @param retry 重試次數
* @param sleepTime 重試間隔時間
* @return
*/
public
Boolean lockRetry(String key,String value,Long timeOut,Integer retry,Long sleepTime){
Boolean flag =
false
;
try
{
for
(
int
i=
0
;i<retry;i++){
flag = lock(key,value,timeOut);
if
(flag){
break
;
}
Thread.sleep(sleepTime);
}
}
catch
(Exception e){
e.printStackTrace();
}
return
flag;
}
|
到這,用redis實現分佈式鎖就寫完了