分布式鎖
-
數據庫
數據庫是使用唯一索引不允許重復的特性(或自定義實現如樂觀鎖). 但持有鎖的進程如果釋放鎖時異常則容易導致死鎖.
-
zookeeper
使用臨時節點, watcher可以獲得節點被刪除的通知, 當客戶端連接失效后, 臨時節點清除, 所以這種情況下不會有死鎖發生.
-
redis
setNX實現
// 為了簡單就不用配置文件了
@Configuration
public class RedisManager {
private JedisPool jedisPool ;
public RedisManager(){
JedisPoolConfig jedisPoolConfig = new JedisPoolConfig();
jedisPoolConfig.setMaxTotal(20);
jedisPoolConfig.setMaxIdle(10);
this.jedisPool = new JedisPool(jedisPoolConfig, "127.0.0.1",6379);
}
@Bean
public Jedis getJedis(){
if (this.jedisPool==null){
return null;
}
return jedisPool.getResource();
}
}
// lock, unlock 方法這里沒有用異常處理.
@Component
public class RedisLock {
@Autowired
private Jedis jedis;
public String lock(String key, int timeout){
String uuid = UUID.randomUUID().toString();
long lockTime = System.currentTimeMillis();
while(System.currentTimeMillis()-lockTime<timeout*1000) {
long rs = jedis.setnx(key, uuid);
if (rs==1){
jedis.expire(key, (int) timeout);
return uuid;
}
// 保證key被設置了超時時間
if (jedis.ttl(key)==-1){
jedis.expire(key, (int) timeout);
}
}
return uuid;
}
public boolean unlock(String key, String value){
while(true) {
jedis.watch(key);
String ret = jedis.get(key);
if (value.equals(ret)) {
Transaction transaction = jedis.multi();
transaction.del(key);
List<Object> transResult = transaction.exec();
if (transResult == null) {
continue;
}
jedis.unwatch();
return true;
}
jedis.unwatch();
break;
}
return false;
}
}
lua語言
redis可以使用lua腳本. lua是動態類型語言.
-
減少網絡開銷
-
原子操作
-
代碼可以復用
-
輕量級
安裝
tar -zxvf ...
make linux
make install
出現fatal error: readline/readline.h: No such file or directory
則需要運行
sudo apt-get install libreadline-dev
命令
- 全局變量, 局部變量
a=1
print(a)
local b=2 print(b) //局部變量,在一條語句
local array = {"a","b"} //數組定義
- 邏輯表達式
-
-
- / %
-
不等於使用~=
- 邏輯運算
not (a and/or B)
- 字符串連接
str1..str2
- 字符串長度用
#
#"hello"
- 分支
if expression then elseif expression then end
- 循環
while expression do ..... end
for i=1,100 do .... end
for i,v in iparis(array) do ..... end
- 注釋
單行使用--
; 范圍使用--[[ ..... ]]
- 函數
function(params...)
--......
return a;
end
內置對象: String
, Table
tonumber()
- lua 可以調用redis命令
redis.call()
--需要引入庫支持, redis內置的lua, 可以在redis內部執行
lua在Redis中的使用
-
執行
eval 'lua script' keynumber key...
-
KEYS[]
ARGV[]
入參, 必須大寫 -
執行lua腳本文件
./redis-cli --eval luafile.lua keyparam1 , valueparam2 vlaueparam3
程序中使用lua
String lua = "local num = redis.call('incr',KEYS[1]) ... ";
jedis.eval();
可以使用摘要執行腳本, 這對大腳本文件比較有用.
jedis.evalsha(jedis.scriptLoad(lua),key,value);