基於 Redis 做分散式鎖

2022-09-22 22:15:05 字數 2590 閱讀 8112

基於 redis 的 setnx()、expire() 方法做分散式鎖

setnx()

setnx 的含義就是 set if not exists,其主要有兩個引數 setnx(key, value)。該方法是原子的,如果 key 不存在,則設定當前 key 成功,返回 1;如果當前 key 已經存在,則設定當前 key 失敗,返回 0。

expire()

expire 設定過期時間,要注意的是 setnx 命令不能設定 key 的超時時間,只能通過 expire() 來對 key 設定。

使用步驟

1、setnx(lockkey, 1) 如果返回 0,則說明佔位失敗;如果返回 1,則說明佔位成功

2、expire() 命令對 lockkey 設定超時時間,為的是避免死鎖問題。

3、執行完業務**後,可以通過 delete 命令刪除 key。

這個方案其實是可以解決日常工作中的需求的,但從技術方案的**上來說,可能還有一些可以完善的地方。比如,如果在第一步 setnx 執行成功後,在 expire() 命令執行成功前,發生了宕機的現象,那麼就依然會出現死鎖的問題,所以如果要對其進行完善的話,可以使用 redis 的 setnx()、get() 和 getset() 方法來實現分散式鎖。

基於 redis 的 setnx()、get()、getset()方法做分散式鎖

這個方案的背景主要是在 setnx() 和 expire() 的方案上針對可能存在的死鎖問題,做了一些優化。

getset()

這個命令主要有兩個引數 getset(key,newvalue)。該方法是原子的,對 key 設定 newvalue 這個值,並且返回 key 原來的舊值。假設 key 原來是不存在的,那麼多次執行這個命令,會出現下邊的效果:

使用步驟

import cn.com.tpig.cache.redis.redisservice;

import cn.com.tpig.utils.springutils;

//redis分散式鎖

public final class redislockutil

/*** 加鎖

* @param key redis key

* @param expire 過期時間,單位秒

* @return true:加鎖成功,false,加鎖失敗

*/public static boolean lock(string key, int expire)

return false;

}public static boolean lock(string key)

/*** 加鎖

* @param key redis key

* @param expire 過期時間,單位秒

* @return true:加鎖成功,false,加鎖失敗

*/public static boolean lock2(string key, int expire)

long oldexpiretime = long.parselong(redisservice.get(key, "0"));

if(oldexpiretime < system.currenttimemillis())

}return false;

}public static void unlock1(string key)

public static void unlock2(string key)

}}

public void drawredpacket(long userid)  finally 

} else

}

基於 redlock 做分散式鎖

redlock 是 redis 的作者 antirez 給出的叢集模式的 redis 分散式鎖,它基於 n 個完全獨立的 redis 節點(通常情況下 n 可以設定成 5)。

演算法的步驟如下:

使用 redlock 演算法,可以保證在掛掉最多 2 個節點的時候,分散式鎖服務仍然能工作,這相比之前的資料庫鎖和快取鎖大大提高了可用性,由於 redis 的高效效能,分散式快取鎖效能並不比資料庫鎖差。

但是,有一位分散式的專家寫了一篇文章《how to do distributed locking》,質疑 redlock 的正確性。

優缺點優點:效能高

缺點:

失效時間設定多長時間為好?如何設定的失效時間太短,方法沒等執行完,鎖就自動釋放了,那麼就會產生併發問題。如果設定的時間太長,其他獲取鎖的執行緒就可能要平白的多等一段時間。

基於 redisson 做分散式鎖

上面的這個問題 ——> 失效時間設定多長時間為好?這個問題在 redisson 的做法是:每獲得一個鎖時,只設定一個很短的超時時間,同時起一個執行緒在每次快要到超時時間時去重新整理鎖的超時時間。在釋放鎖的同時結束這個執行緒。

為什麼我們做分散式要使用Redis

絕大部分寫業務的程式設計師,在實際開發中使用 redis 的時候,只會 set value 和 get value 兩個操作,對 redis...