本文會陸續更新;先寫下大綱和劣勢
部落客:隻針對JAVA其他語言未知未測;
redis 2x版本鎖:3x版本已移除
redis setnx鎖:1.死鎖問題,2.哨兵模式會有多個線程同時擷取鎖,舍棄 3.無法動态控制程式執行時間
redis+lua鎖:1.哨兵模式會有多個線程同時擷取鎖,舍棄
redLock算法鎖:1.主觀念抛棄了主從叢集
redisson鎖:是對redis鎖加強,需要續約,不好把控續約時間,有SpringBoot整合版;
spring-boot-klock-starter:一個開源項目基于redisson鎖
以上全是基于redis的鎖,redis主從模式下全部不推薦,全部會導緻多個線程(程序)同時擷取鎖;但可以考慮TTL(鎖過期時間)>從節點上位時間的方案,但是TTL可能很久,也非常耗性能與時間,是以全部抛棄;
mysql單機實作比較粗暴;集分庫表很麻煩,方案不多不推薦
zookeper臨時節點鎖:目前2020/3/17看來是比較好的方案,性能消耗比redis單機高,需要持續監聽節點,還支援叢集高可用;
總結:
如果對性能要求較高,redLock,是你的選擇,如果可控時間redisson是你的選擇(需要保證多數以上成功,且叢集必須要高可用)
反之zookeper
注意事項:
1.使用redisson注意版本,一定要測試!!!
2.使用redisson一定要自定義權衡逾時時間(預設30s),太短會持續續約消耗性能,太長會阻塞大量線程等待擷取鎖;在大量線程阻塞等待時鎖注意使用redistemplte時,redis逾時時間小心超過等待時間導緻逾時(不合理将會導緻大量異常傳回逾時),那麼逾時後會不會導緻程式混亂,這時候需要認認真真的控制代碼(ps:不想煩躁方案:直接鎖根方法,并控制代碼反應時間)
3.盡量使用redis線程池技術,可間接避免擷取逾時;使用線程池時,注意redis包版本對應的線程池,以及redission支援的線程池
特别注意:
部落客表述不清楚的地方可以指出來,我沒辦法寫出所有的細節考慮(文筆不好);比如:網絡抖動,記憶體爆滿,交換區爆滿,丢失等等組合情況,也一般比較少遇到是以不寫了。可以提問喲
下面是redisson單機整合版和zk,我已經測試過的了
加入依賴
<dependencies>
<dependency>
<groupId>org.redisson</groupId>
<artifactId>redisson-spring-boot-starter</artifactId>
</dependency>
</dependencies>
直接注入就可使用,需要注意的是與redistemplate可能有沖突,記得測試喲~
@Slf4j
@Service
public class RedissonLock implements LockClient {
@Autowired
private RedissonClient redissonClient;
/**
* 擷取自定義時間鎖
*
* @param key
*/
@Override
public void lock(String key,int outTime){
redissonClient.getLock(key).lock(outTime, TimeUnit.SECONDS);
}
/**
* 釋放鎖
*
* @param key
*/
@Override
public void unLock(String key) {
redissonClient.getLock(key).unlock();
}
//5秒,自動續約
public void lock(String key) {
// redissonClient.getLock(key).lock();
redissonClient.getLock(key).lock(5L, TimeUnit.SECONDS);
}
/**
* 嘗試擷取鎖
*
* @param lockKey
* @param waitTime 最多等待時間
* @param leaseTime 釋放時間
* @return
*/
@Transactional
public boolean tryLock(String lockKey, int waitTime, int leaseTime) {
boolean b = false;
try {
b = redissonClient.getLock(lockKey).tryLock(waitTime, leaseTime, TimeUnit.MILLISECONDS);
} catch (InterruptedException e) {
log.error("擷取分布式鎖異常:", e);
}
return b;
}