Golang基於Redis的分佈式鎖
我理解的分佈式鎖:
一、爲了不單持有鎖的進程奔潰而沒法釋放鎖,因此必須可以爲鎖設定過時時間自動釋放鎖資源 二、使用TTL檢查鎖是否成功的被設置過時時間,若是返回-1(未被設置)的話,使用Expire爲其設定過時時間 三、在釋放鎖的時候須要使用Watch命令,確保監測的值在事務執行時時未被改變,若是其餘進程修改了鎖,會觸發事務異常,而後從新執行Watch。git
分享一個我寫的Redis封裝類,僅實現了鏈接和鎖github
package dao import ( "time" "github.com/go-redis/redis/v7" uuid "github.com/satori/go.uuid" ) type Rds struct { Client *redis.Client AcquireTimeout int32 LockTimeout int32 } func NewRds(host, passwd string, db int) (rds *Rds, err error) { rdsOpt := &redis.Options{ Addr: host, Password: passwd, DB: db, } client := redis.NewClient(rdsOpt) _, err = client.Ping().Result() if err != nil { return } rds = &Rds{Client: client, AcquireTimeout: 10, LockTimeout: 10} return } func (r *Rds) AcquireLockWithTimeout(key string) (identifier string, b bool) { identifier = uuid.NewV4().String() lockname := "lock:" + key end := time.Now().Add(time.Second * time.Duration(r.AcquireTimeout)) for time.Now().Before(end) { if r.Client.SetNX(lockname, identifier, time.Second*time.Duration(r.LockTimeout)).Val() { // 若是key不存在,併成功設置了key b = true return } else if r.Client.TTL(lockname).Val() == -1 { // 若是key存在,可是沒有剩餘時間 r.Client.Expire(lockname, time.Second*time.Duration(r.LockTimeout)) } time.Sleep(time.Microsecond) } return } func (r *Rds) ReleaseLock(key, identifier string) (b bool) { lockname := "lock:" + key txf := func(tx *redis.Tx) error { v, err := tx.Get(lockname).Result() if err != nil { return err } _, err = tx.Pipelined(func(pipe redis.Pipeliner) error { if v == identifier { pipe.Del(lockname) b = true } return nil }) return err } for { err := r.Client.Watch(txf, lockname) if err == nil { break } else if err == redis.TxFailedErr { glog.Error(err) } } return }