分佈式鎖總結

1> redis處理過時key的方式:html

redis 當key過時的時候,可能會採起策略來清除掉key. 有如下三種方式: 當即清除(設置過時時間的時候,設置一下回調,當時間過時,直接刪除掉key)   惰性清除(key過時的時候不會當即去清除掉key,等下次取數據的時候,判斷是否過時,過時了就會刪除掉key). 定時清除. redis使用的是 定時清除和惰性清除 兩種策略.java

關於分佈式鎖:python

在平常開發中,若是是單應用實例,爲了防止併發所致使的一系列的問題,咱們可使用java中提供的那些鎖機制來保障( synchronized或者reentrantlock).  可是在分佈式環境中,因爲會存在多個jvm進程,致使鎖對象不惟一,這樣java中提供的那些鎖機制就沒有用了,這時候咱們就須要尋求分佈式鎖來保障 併發帶來的問題.redis

 

                   分佈式鎖是用於解決分佈式系統中操做共享資源時的數據一致性問題。數據庫

分佈式鎖須要注意一些問題:緩存

互斥:   分佈式系統中運行着多個節點,必須確保在同一時刻只能有一個節點的一個線程得到鎖。

死鎖: 分佈式系統中若是一個節點獲取到鎖掛掉,鎖一直不能釋放,致使其餘節點處於阻塞狀態,因此有必要設置時效,不管什麼狀態,鎖都能釋放.

性能: 對於訪問量大的共享資源,若是獲取到鎖會形成長時間的等待,致使大量節點阻塞,不能夠.儘可能減小等待時間(業務執行時間以及及時通知)併發

重入: 鎖是基於線程的分配.

阻塞性: 根據實際業務場景來判斷,當沒有獲取到鎖的時候,採起阻塞等待仍是直接返回.jvm

 

 

 

多個線程併發執行一個方法場景.分佈式

1>>>>>若是該方法裏面所有是操做數據庫的一些東西, 能夠直接使用數據庫的事務併發機制來控制.不須要其餘的分佈式鎖來保障.(單業務節點也可使用)性能

    通常存在repeatable read隔離級別下,對數據的讀取,修改事務提交操做.(repeatable隔離級別下加鎖機制,可能會死鎖,用更新鎖來解決)

2>>>>>若是是爲了防止多個線程執行同一方法致使數據不一致性,可使用分佈式鎖.

 

分佈式鎖的實現方式:

1>基於數據庫來實現. 新建一張表: id  method_name  創建method_name惟一索引,由數據庫來保障. 執行方法前,先必須獲取到鎖,insert into tb (method_name) value(method_name) 返回成功就獲取到鎖,沒有成功就沒有獲取到鎖,執行完的時候 刪除掉這條數據,讓其餘線程能夠開始去處理.

缺點: 數據庫單點故障,萬一表掛了,則整個出錯. 非重入性 沒有過時時間,萬一內部崩潰則鎖一直沒法釋放  非阻塞

改進:使用select.....for update 有效避免非阻塞 可是可能會鎖表.

 

3>基於zookeeper實現分佈式鎖

https://www.cnblogs.com/austinspark-jessylu/p/8043726.html

https://www.cnblogs.com/linjiqin/p/8003838.html

2>基於redis緩存來實現分佈式鎖

  注意點: 2.1> redis加鎖的時候  setnx 和 設置有效期不能拆開,由於不是一個原子操做.正確使用

                  String result = jedis.set(lockKey, requestId, nx=Ture, px=5);

2.2> 刪除鎖的時候要注意:判斷一下當前對象和持有鎖的對象是否一致,避免釋放掉其餘線程的鎖.(根據不一樣業務來選擇是否須要判斷) 

實現的幾種方式:直接上代碼

1>  set方式:

while(jedis.exists(lock)){
Thread.sleep(500);
}

set(lock,1);
執行業務代碼;
jedis.del(lock);

2> setnx 方式:

while(jedis.setnx(lock,1)==0){

Thread.sleep(300);

}

執行業務代碼;
jedis.del(lock);






setnx不直接設置timeout:

while(jedis.setnx(lock,now+超時時間)==0){
    if(jedis.get(lock)<now){
       jedis.del(lock);
    jedis.setnx(lock,now+超時時間);
               break;
              }else{
                     Thread.sleep(300);
              }}

執行業務代碼;
jedis.del(lock);

 

 

while(jedis.setnx(lock, now+超時時間)==0){
               if(now>jedis.get(lock) && now>jedis.getset(lock, now+超時時間)){
                     break;
             }else{ 
                    Thread.sleep(300);
              }
}
執行業務代碼;
jedis.del(lock);



redis中存在一種   set 直接設置nx px(過時時間)  讓判斷過時時間的工做扔給redis更高效

目前python中改造採用:

while not cls.get_lock_rs().set(sender_rs_key, 1, nx=True, px=5):  #setnx+timeout 若是沒有獲取到鎖    time.sleep(0.005)         #sleep 5ms執行業務代碼;del(key)考慮一個問題:針對python部分的鎖方式,若是保證鎖的正確釋放(A線程不能釋放B線程的鎖),能夠採用value=thread_id del的時候進行判斷對於java中的分佈式鎖服務 採用redisson來實現. redisson是對jedis的上層封裝,提供分佈式集合 和分佈式鎖.主要看一下分佈式鎖: 使用方式: 能夠以redis單節點或者集羣搭建不一樣的redisson鏈接對象.使用集羣能夠避免redis單節點故障.  java中的鎖具備重入性 unlock 能夠判斷是不是同一個線程.  python調用要注意: 超時時間  不一樣的線程id問題.
相關文章
相關標籤/搜索