Go 語言下基於Redis分佈式鎖的實現方式
分佈式鎖一般有三種實現方式:1. 數據庫樂觀鎖;2. 基於Redis的分佈式鎖;3. 基於ZooKeeper的分佈式鎖。本篇博客將介紹第二種方式,基於Redis實現分佈式鎖。雖然網上已經有各種介紹Redis分佈式鎖實現的博客,然而他們的實現卻有著各種各樣的問題,為瞭避免誤人子弟,本篇博客將詳細介紹如何正確地實現Redis分佈式鎖。
項目地址: https://github.com/Spongecaptain/redisLock
1. Go 原生的互斥鎖
Go 原生的互斥鎖即 sync 包下的 Mutex 結構體,利用此結構體的 Lock 以及 Unlock 方法能夠實現鎖的占據以及釋放。
關於 sync.Mutex,我們可以總結出如下的特性:
- 支持自旋鎖,在並發沖突不嚴重的背景下提高鎖的使用效率;
- 支持鎖的公平性,能夠避免鎖導致的線程饑餓問題;
- 不支持鎖的重入,持有鎖的協程再次申請鎖資源會導致死鎖;
- 任何協程都可以調用 Mutex.Unlock 方法來解鎖,並不隻允許占據鎖資源的協程進行解鎖;
- 不支持超時鎖獲取,也不支持 TryLock 機制
Go 語言中 sync.Mutex 的特性與 Java 中 java.util.concurrent.locks.Lock 相比,API 語義簡單不少,這也符合 Go 語言對於簡單化的追求。
下面看看本項目-基於 Redis 的分佈式鎖能夠提供哪些分佈鎖特性。
2. redisLock 的特性
github-redisLock 是一個基於 go-redis/redis 客戶端的 Redis 分佈式鎖。其擁有的如下的特性:
- 原子性:利用 Lua 腳本實現原子性語義;
- 阻塞喚醒:利用 Redis 的發佈訂閱來實現鎖的阻塞喚醒;
- 鎖自動過期:避免因為宕機導致的死鎖問題;
- 鎖的自動續期:利用 Go 協程實現鎖資源的自動續期,避免出現業務時間>鎖超時時間導致並發安全問題
- TryLock:嘗試獲取一次鎖,獲取失敗後阻塞
- 自旋鎖:提供自旋鎖 API 來實現分佈式鎖的自旋獲取
github-redisLock 同時不支持如下特性:
重入性:分佈式鎖不可重入,Go 語言並沒有優雅的方式來實現 Java 中的 ThreadLocal 機制
非公平性:分佈式鎖存在非公平問題,在極端情況下會導致饑餓問題
3. Quick Start
Install redisLock:
go get github.com/Spongecaptain/redisLock
Create redis client:
import( "github.com/go-redis/redis" ) var redisClient = redis.NewClient(&redis.Options{ Addr: "localhost:6379", Password: "", // no password set DB: 0, // use default DB })
Create redisLock:
key := "reids-lock-key" value := "redis-lock-value" lock := redisLock.NewRedisLock(redisClient, key, value) err := lock.Lock() if err != nil { fmt.Println(err.Error()) return } fmt.Println("get redis lock success") defer func() { err = lock.Unlock() if err != nil { fmt.Println(err.Error()) return } fmt.Println("release redis lock success") }()
4. API 說明
(1)構造分佈式鎖實例
利用 NewRedisLock 以及 NewRedisLockWithExpireTime 函數能夠構造出一個分佈式鎖實例,NewRedisLockWithExpireTime 的區別在於其能夠自定義鎖的過期時間。
NewRedisLock 方法接收的 key 決定瞭分佈式鎖的粒度,value 決定瞭隻有 value 值相同才能夠進行解鎖。
(2)TryLock
TryLock 僅嘗試一次鎖的獲取,如果失敗,那麼不會阻塞,直接返回。
(3)Lock
Lock 會不斷嘗試索取分佈式鎖,這會導致調用此方法的協程阻塞。
(4)Unlock
Unlock 方法用於解鎖,由於涉及網絡通信,解鎖可能失敗, error!=nil 意味著解鎖失敗。
(5)LockWithTimeout
Lock 方法會在獲取鎖資源成功或者超時後返回。
(6)SpinLock
支持指定次數地進行自旋式的鎖獲取。
以上就是Go 語言下基於 Redis 的分佈式鎖的詳細內容,更多關於Go 分佈式鎖的資料請關註WalkonNet其它相關文章!
推薦閱讀:
- 用Go+Redis實現分佈式鎖的示例代碼
- PHP使用redis實現分佈式鎖的示例詳解
- 關於SpringBoot 使用 Redis 分佈式鎖解決並發問題
- Redis可視化客戶端小結
- 一文掌握Go語言並發編程必備的Mutex互斥鎖