当前位置: 首页 > news >正文

济源网站建设公司苏州网站建设

济源网站建设公司,苏州网站建设,北京工业产品设计公司,网站开发规格redsync使用教程前言redsync结构Pool结构Mutex结构acquire加锁操作release解锁操作redsync包的使用前言 在编程语言中锁可以理解为一个变量,该变量在同一时刻只能有一个线程拥有,以便保护共享数据在同一时刻只有一个线程去操作。对于高可用的分布式锁应…

redsync使用教程

  • 前言
  • redsync结构
    • Pool结构
    • Mutex结构
      • acquire加锁操作
      • release解锁操作
  • redsync包的使用

前言

在编程语言中锁可以理解为一个变量,该变量在同一时刻只能有一个线程拥有,以便保护共享数据在同一时刻只有一个线程去操作。对于高可用的分布式锁应该满足以下条件:
1.互斥:在任意时间内,只有一个客户能够获得一把锁,具有排他性。
2.避免死锁:即使客户端宕机或者从集群中分离了,其它客户端仍然可以获取到该锁
3.容错:只要大部分Redis节点存活,客户端就能正确地获取锁和释放锁。即使锁住某个资源的客户端释放锁之前崩溃或者网络分区仍然能够获取锁和释放锁。
对于Redis高可用集群而言,上述三个条件都非常容易满足,所以适合做分布式锁。

redsync结构

redsync 的通用结构定义如下:

  • Pool:抽象连接池
  • Conn:抽象每个 Redis 连接
  • Script:Redis 脚本

Pool结构

redsync结构的Pools是一个redis.pool数组,每个 redis.Pool 都是上面的 Pool 实现,它代表了一个 Redis 实例的连接池:
在这里插入图片描述

Mutex结构

Mutex代表了一个分布式锁,其成员多为 redlock 算法所需要的条件:

// A Mutex is a distributed mutual exclusion lock.
type Mutex struct {name   string  				// 名称expiry time.Duration    	// 锁的有效时间tries     int   // 尝试次数delayFunc DelayFunc // 失败尝试设置延迟factor float64 // 误差系数控制quorum int // 投票数 一般为节点数 / 2+1,节点数为奇数genValueFunc func() (string, error)  // 加密函数,生成唯一随机串value        string  // 默认就是唯一随机串until        time.Time // 过期时间pools []Pool // 连接池(每个 Pool 指一个 Redis 实例)
}

获取锁的Lock方法实现了redLock的加锁接口,具体实现如下

func (m *Mutex) LockContext(ctx context.Context) error {if ctx == nil {ctx = context.Background()}//生成随机串,base64value, err := m.genValueFunc()if err != nil {return err}//不超过tries次数进行加锁for i := 0; i < m.tries; i++ {if i != 0 {time.Sleep(m.delayFunc(i))}start := time.Now()n, err := func() (int, error) {ctx, cancel := context.WithTimeout(ctx, time.Duration(int64(float64(m.expiry)*m.timeoutFactor)))defer cancel()//尝试异步去获取锁return m.actOnPoolsAsync(func(pool redis.Pool) (bool, error) {return m.acquire(ctx, pool, value)})}()now := time.Now()// 过期时间 = 有效时间值 - 获取锁消耗的时间值 - 有效时间值 * 误差系数until := now.Add(m.expiry - now.Sub(start) - time.Duration(int64(float64(m.expiry)*m.driftFactor)))//成功节点数>=节点数/2+1&& 未过期时,判定加锁成功	if n >= m.quorum && now.Before(until) {m.value = valuem.until = untilreturn nil}func() (int, error) {ctx, cancel := context.WithTimeout(ctx, time.Duration(int64(float64(m.expiry)*m.timeoutFactor)))defer cancel()//获取锁失败,尝试异步去释放锁return m.actOnPoolsAsync(func(pool redis.Pool) (bool, error) {return m.release(ctx, pool, value)})}()if i == m.tries-1 && err != nil {return err}}return ErrFailed
}

time.Sleep(m.delayFunc(i))的失败重试逻辑是当客户端无法获取锁时会设置一个随机值来重试。这个随机值应当和申请锁时间错开,减少脑裂的可能性。此外,还调用了actOnPoolsAsync来实现非阻塞方式同时向多个Redis实例发送set请求。我们来看下actOnPoolsAsync是如何定义的。

func (m *Mutex) actOnPoolsAsync(actFn func(redis.Pool) (bool, error)) (int, error) {type result struct {Node   intStatus boolErr    error}ch := make(chan result)for node, pool := range m.pools {go func(node int, pool redis.Pool) {r := result{Node: node}r.Status, r.Err = actFn(pool)ch <- r}(node, pool)}n := 0var taken []intvar err errorfor range m.pools {r := <-chif r.Status {n++} else if r.Err != nil {err = multierror.Append(err, &RedisError{Node: r.Node, Err: r.Err})} else {taken = append(taken, r.Node)err = multierror.Append(err, &ErrNodeTaken{Node: r.Node})}}if len(taken) >= m.quorum {return n, &ErrTaken{Nodes: taken}}return n, err
}

acquire加锁操作

func (m *Mutex) acquire(ctx context.Context, pool redis.Pool, value string) (bool, error) {conn, err := pool.Get(ctx)if err != nil {return false, err}defer conn.Close()reply, err := conn.SetNX(m.name, value, m.expiry)if err != nil {return false, err}return reply, nil
}

release解锁操作

func (m *Mutex) release(ctx context.Context, pool redis.Pool, value string) (bool, error) {conn, err := pool.Get(ctx)if err != nil {return false, err}defer conn.Close()//调用Eval,以脚本方式释放锁status, err := conn.Eval(deleteScript, m.name, value)if err != nil {return false, err}return status != int64(0), nil
}

redsync包的使用

该包的使用很简单,具体步骤如下:

  • 首先,创建一个Redis的客户端连接;
  • 将该客户端连接加入到Redis的Pool中;
  • redsync基于该Redis Pool进行实例化;
  • 通过redsync实例的NewMutex就可以基于一个具体的key新建一个分布式锁,
    该包进行实例化时有基于Redis的单机模式和集群模式两种使用方式,在使用上主要有两种区别:
  • Redis的客户端是以集群模式还是单机模式创建;
  • 在导入redsync包时,集群模式需要导入goredis/v8的版本
    具体例子如下:
func main() {//创建redis的客户端连接cli := goredislib.NewClient(&goredislib.Options{Addr: "localhost:6379",})pool := goredis.NewPool(cli)rs := redsync.New(pool)mutexname := "test-global-mutex"mutex := rs.NewMutex(mutexname)if err := mutex.Lock(); err != nil {panic(err)}if ok, err := mutex.Unlock(); !ok || err == nil {panic("unlock failed")}}
http://www.jinmujx.cn/news/111603.html

相关文章:

  • 政府网站建设研讨交流怎么做网站卖产品
  • 企业查询宝下载seo工作流程
  • 射阳做企业网站哪家好软文广告经典案例200字
  • 网页小游戏在线玩儿疫情二十条优化措施
  • 苏州外贸网站推广电商产品推广方案
  • 网站建设国内外研究现况qq空间刷赞网站推广
  • wordpress 设置伪静态后企业网站搜索优化网络推广
  • 网站建设公司与前端智能建站网站模板
  • 做网站的素材包含哪些今天重大国际新闻
  • 做相亲网站今日国际新闻摘抄十条
  • 建站之星登录百度搜索风云榜明星
  • 镇江网站建设优化交换友链是什么意思
  • 做播放器电影网站需要多少钱正规考证培训机构
  • wordpress注册没有密码成都网站seo推广
  • 做网站和app需要多久郑州网站优化平台
  • 重庆网站建设公司招聘广告网站大全
  • 广州营销型网站建设公司哪家名气大企业营销型网站有哪些
  • 中国疫情最新消息今天死亡天津优化公司
  • 漯河网站建设 付永磊网站地址ip域名查询
  • 怎么做门户网站java百度搜索引擎优化相关性评价
  • 蓝色云主机一键wordpress北京aso优化
  • 建设手机网站报价企业宣传片视频
  • 做汽车价格的网站建设怎么做百度关键词排名
  • 网站制作 东莞自己如何做网站
  • 做二手平台公益的网站网络销售的好处和意义
  • 做维修注册网站广告公司是做什么的
  • 如何做网站打广告阿里妈妈推广网站
  • 哈尔滨建设厅网站郑州seo联系搜点网络效果好
  • jsp做的大型网站百度竞价排名名词解释
  • 大型网站开发软件企业网络营销案例分析