go实现redis分布式锁
2019-07-15 15:01
1546 查看
下载 github.com/garyburd/redigo,这个分布式锁是根据上面所实现;
下载 gopkg.in/redsync.v1 这个就是实现分布式锁的源代码(如果测试需要下载 github.com/stvp/tempredis);
看下源码
package redsync import ( "crypto/rand" "encoding/base64" "sync" "time" "github.com/garyburd/redigo/redis" ) // A Mutex is a distributed mutual exclusion lock. type Mutex struct { name string expiry time.Duration tries int delay time.Duration factor float64 quorum int value string until time.Time nodem sync.Mutex pools []Pool } name string //命名一个名字 expiry time.Duration //最多可以获取锁的时间,超过自动解锁 tries int //失败最多获取锁的次数 delay time.Duration //获取锁失败后等待多少时间后重试 factor float64 quorum int value string //每一个锁独有一个值, until time.Time nodem sync.Mutex pools []Pool //连接池 // New creates and returns a new Redsync instance from given Redis connection pools. func New(pools []Pool) *Redsync { return &Redsync{ pools: pools, } } // NewMutex returns a new distributed mutex with given name. func (r *Redsync) NewMutex(name string, options ...Option) *Mutex { m := &Mutex{ name: name, expiry: 8 * time.Second, tries: 32, delay: 500 * time.Millisecond, factor: 0.01, quorum: len(r.pools)/2 + 1, pools: r.pools, } for _, o := range options { o.Apply(m) } return m } // An Option configures a mutex. type Option interface { Apply(*Mutex) } // OptionFunc is a function that configures a mutex. type OptionFunc func(*Mutex) // Apply calls f(mutex) func (f OptionFunc) Apply(mutex *Mutex) { f(mutex) } // SetExpiry can be used to set the expiry of a mutex to the given value. func SetExpiry(expiry time.Duration) Option { return OptionFunc(func(m *Mutex) { m.expiry = expiry }) } // SetTries can be used to set the number of times lock acquire is attempted. func SetTries(tries int) Option { return OptionFunc(func(m *Mutex) { m.tries = tries }) } // SetRetryDelay can be used to set the amount of time to wait between retries. func SetRetryDelay(delay time.Duration) Option { return OptionFunc(func(m *Mutex) { m.delay = delay }) } // SetDriftFactor can be used to set the clock drift factor. func SetDriftFactor(factor float64) Option { return OptionFunc(func(m *Mutex) { m.factor = factor }) }
//这里的SET*方法,是自定义设置Mutex的参数
//下面是测试代码
package main import ( "gopkg.in/redsync.v1" "testing" "github.com/garyburd/redigo/redis" "time" "fmt" ) //redis命令执行函数 func DoRedisCmdByConn(conn *redis.Pool,commandName string, args ...interface{}) (interface{}, error) { redisConn := conn.Get() defer redisConn.Close() //检查与redis的连接 return redisConn.Do(commandName, args...) } func TestRedis(t *testing.T) { //单个锁 //pool := newPool() //rs := redsync.New([]redsync.Pool{pool}) //mutex1 := rs.NewMutex("test-redsync1") // //mutex1.Lock() //conn := pool.Get() //conn.Do("SET","name1","ywb1") //conn.Close() //mutex1.Unlock() curtime := time.Now().UnixNano() //多个同时访问 pool := newPool() mutexes := newTestMutexes([]redsync.Pool{pool}, "test-mutex", 2) orderCh := make(chan int) for i,v :=range mutexes { go func(i int,mutex *redsync.Mutex) { if err := mutex.Lock(); err != nil { t.Fatalf("Expected err == nil, got %q", err) return } fmt.Println(i,"add lock ....") conn := pool.Get() DoRedisCmdByConn(pool,"SET",fmt.Sprintf("name%v",i),fmt.Sprintf("name%v",i)) str,_ := redis.String(DoRedisCmdByConn(pool,"GET",fmt.Sprintf("name%v",i)) fmt.Println(str) DoRedisCmdByConn(pool,"DEL",fmt.Sprintf("name%v",i)) conn.Close() mutex.Unlock() fmt.Println(i,"del lock ....") orderCh <- i }(i,v) } for range mutexes { <-orderCh } fmt.Println(time.Now().UnixNano() - curtime ) } func newTestMutexes(pools []redsync.Pool, name string, n int) []*redsync.Mutex { mutexes := []*redsync.Mutex{} for i := 0; i < n; i++ { mutexes = append(mutexes,redsync.New(pools).NewMutex(name, redsync.SetExpiry(time.Duration(2)*time.Second), redsync.SetRetryDelay(time.Duration(10)*time.Millisecond)), ) } return mutexes } func newPool() *redis.Pool { return &redis.Pool{ MaxIdle: 3, IdleTimeout: time.Duration(24) * time.Second, Dial: func() (redis.Conn, error) { c, err := redis.Dial("tcp", "127.0.0.1:6379") if err != nil { panic(err.Error()) //s.Log.Errorf("redis", "load redis redisServer err, %s", err.Error()) return nil, err } return c, err }, TestOnBorrow: func(c redis.Conn, t time.Time) error { _, err := c.Do("PING") if err != nil { //s.Log.Errorf("redis", "ping redis redisServer err, %s", err.Error()) return err } return err }, } }
相关文章推荐
- GO学习笔记 - 用":="实现短声明变量!
- PAT乙 1012 数字分类(GO实现)
- 循环识别的C++/Java/Go/Scala实现比较
- Go语言实现的一个简单Web服务器
- GO1.5实现简单的http并发请求,支持:GET、POST、HEAD、PUT
- 使用go channel实现一个简单的信号量
- Go如何实现枚举小实例分享
- Go语言实现telnet远程登录
- go语言实现处理表单输入
- Go实现tls的通信的简单代码例子
- go通过共享变量实现并发
- 【寒江雪】Go实现外观模式
- Go中的用组合实现继承
- go map的实现
- go语言实现sqrt的方法
- Go(单链表)实现简单Stack
- [算法Rust,Go,Python,JS实现)]LeetCode之01-两数之和
- 算法代码实现之冒泡排序,Golang(Go语言)实现
- Redis分布式锁Java实现
- go实现一个简单的游戏服务器框架(lotou)多节点