Redis實現分散式鎖機制
阿新 • • 發佈:2018-12-22
Redis實現分散式鎖思路
常用的是redis函式是setnx(),這個應該是實現分散式鎖最主要的函式。首先是將某一業務標識名作為鍵存到redis裡,併為其設個過期時間,如果是還有加鎖請求過來,先是通過setnx()看看是否能將鎖的標識插入到redis裡,可以的話就返回true,不可以就返回false。
此處使用Lua指令碼簡單的實現Redis鎖的實現 :
package com.tencent.sxwx.wechat.util;
import redis.clients.jedis.Jedis;
public class DistributeLocker {
private Jedis jedis;
private Lock lock;
/**
* 加鎖成功標識
*/
private static final String LOCK_SUCCESS = "1";
/**
* 指令碼入參個數
*/
private static final int KEY_COUNT = 1;
/**
* 加鎖指令碼
*/
private static String LOCK_SCRIPT;
/**
* 解鎖指令碼
*/
private static String RELEASE_SCRIPT;
/**
* 初始化指令碼
*/
static {
LOCK_SCRIPT = "local key = redis.call('get',KEYS[1]) if ('1' == key) then return 0 "
+ "else redis.call('set',KEYS[1],'1') redis.call('expire',KEYS[1],ARGV[1]) return 1 end";
RELEASE_SCRIPT = "if (redis.call('exists',KEYS[1])) then redis.call('del',KEYS[1]) end" ;
}
/**
* 定義帶參建構函式
*/
public DistributeLocker (Lock lock) { }
public void lock (final String key, final int exprieTime) {
if (isLocked(key, exprieTime)) {
lock.success();
} else {
lock.failure();
}
}
/**
* 加鎖邏輯
*/
private boolean isLocked(final String key, final int exprieTime) {
Object obj = jedis.eval(LOCK_SCRIPT, KEY_COUNT, key, String.valueOf(exprieTime));
if (LOCK_SUCCESS.equals(obj)) {
return true;
}
return false;
}
/**
* 解鎖邏輯
*/
public void releaseLock (String key) {
jedis.eval(RELEASE_SCRIPT, KEY_COUNT, key);
}
}
package com.tencent.sxwx.wechat.util;
public interface Lock {
void success();
void failure();
}
package com.tencent.sxwx.wechat.util;
public class Test {
void purchase(String key, int secondTime){
DistributeLocker locker = new DistributeLocker(new Lock() {
@Override
public void success() {
// do something
}
@Override
public void failure() {
// do something
}
});
try {
locker.lock(key,secondTime);
} finally {
locker.releaseLock(key);
}
}
}
注:Redis分散式鎖的實現方式有很多種,各有利弊,加鎖的時候主要注意檢查鎖與加鎖操作要有原子性,防止重複加鎖成功。過期時間主要是為了防止未釋放鎖導致鎖的一直存在,從而無法獲取鎖操作。