分佈式鎖面試題

分佈式鎖

分佈式CAP

任何一個分佈式系統都無法同時滿足一致性(Consistency)、可用性(Availability)和分區容錯性(Partition tolerance),最多隻能同時滿足兩項。

1.基於數據庫排他鎖做分佈式鎖

在查詢語句後面增加for update來獲取鎖, 數據庫會在查詢過程中給數據庫表增加排他鎖

InnoDB 引擎在加鎖的時候,只有通過索引進行檢索的時候纔會使用行級鎖,否則會使用表級鎖。

通過connection.commit()操作來釋放鎖

問題: 線程數量上限受數據庫連接池大小限制;

2.基於 Redis 做分佈式鎖

  1. setnx(lockkey, 當前時間+過期超時時間),如果返回 1,則獲取鎖成功;如果返回 0 則沒有獲取到鎖,轉向 2。
  2. get(lockkey) 獲取值 oldExpireTime ,並將這個 value 值與當前的系統時間進行比較,如果小於當前系統時間,則認爲這個鎖已經超時,可以允許別的請求重新獲取,轉向 3。
  3. 計算 newExpireTime = 當前時間+過期超時時間,然後 getset(lockkey, newExpireTime) 會返回當前 lockkey 的值currentExpireTime。
  4. 判斷 currentExpireTime 與 oldExpireTime 是否相等,如果相等,說明當前 getset 設置成功,獲取到了鎖。如果不相等,說明這個鎖又被別的請求獲取走了,那麼當前請求可以直接返回失敗,或者繼續重試。
  5. 在獲取到鎖之後,當前線程可以開始自己的業務處理,當處理完畢後,比較自己的處理時間和對於鎖設置的超時時間,如果小於鎖設置的超時時間,則直接執行 delete 釋放鎖;如果大於鎖設置的超時時間,則不需要再鎖進行處理。
        RedisService redisService = SpringUtils.getBean(RedisService.class);
        long status = redisService.setnx(key, "1");

        if(status == 1) {
            redisService.expire(key, expire);
            return true;
        }
if(oldExpireTime > System.currentTimeMillis()) {        
            redisService.del(key);    
        }

基於 redisson 做分佈式鎖

失效時間設置多長時間爲好?

redisson 的做法是:每獲得一個鎖時,只設置一個很短的超時時間,同時起一個線程在每次快要到超時時間時去刷新鎖的超時時間。在釋放鎖的同時結束這個線程。

3.zookeeper

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章