go-redis/v8创建一个cluster的对象的过程

202 阅读1分钟

go-redis中创建一个redis的cluster对象

redisCluster := redis.NewClusterClient(&redis.ClusterOptions{
   Addrs:        c.RedisCluster.Host,
   Password:     c.RedisCluster.Password,
   PoolSize:     c.RedisCluster.PoolSize,
   MinIdleConns: c.RedisCluster.MinIdle,
   IdleTimeout:  time.Second * 3,
   MaxRetries:   3,
})

使用ClusterOptions结构体接收参数

实例化中使用init函数初始化一些参数


func (opt *ClusterOptions) init() {
   if opt.MaxRedirects == -1 {
      opt.MaxRedirects = 0
   } else if opt.MaxRedirects == 0 {
      opt.MaxRedirects = 3
   }

   if opt.RouteByLatency || opt.RouteRandomly {
      opt.ReadOnly = true
   }

   if opt.PoolSize == 0 {
      opt.PoolSize = 5 * runtime.GOMAXPROCS(0)
   }
   ......
   }

对于redis中的各种操作,get,set等,cluster是怎么处理的呢?

// Get Redis `GET key` command. It returns redis.Nil error when key does not exist.
func (c cmdable) Get(ctx context.Context, key string) *StringCmd {
   cmd := NewStringCmd(ctx, "get", key)
   _ = c(ctx, cmd)
   return cmd
}

cmdable是一个函数

type cmdable func(ctx context.Context, cmd Cmder) error

在cluster实例化的时候,对cmdable这个函数,赋值了

c.cmdable = c.Process

所以函数cluster的Process函数实现了cmdable

func (c *ClusterClient) Process(ctx context.Context, cmd Cmder) error {
   return c.hooks.process(ctx, cmd, c.process)
}

对于hooks的process,接收了真正处理cmd的process函数,也在自己的procee中里面增加了hook的处理

func (hs hooks) process(
   ctx context.Context, cmd Cmder, fn func(context.Context, Cmder) error,
) error {
   if len(hs.hooks) == 0 {
      err := fn(ctx, cmd)
      cmd.SetErr(err)
      return err
   }

   var hookIndex int
   var retErr error

   for ; hookIndex < len(hs.hooks) && retErr == nil; hookIndex++ {
      ctx, retErr = hs.hooks[hookIndex].BeforeProcess(ctx, cmd)
      if retErr != nil {
         cmd.SetErr(retErr)
      }
   }

   if retErr == nil {
      retErr = fn(ctx, cmd)
      cmd.SetErr(retErr)
   }

   for hookIndex--; hookIndex >= 0; hookIndex-- {
      if err := hs.hooks[hookIndex].AfterProcess(ctx, cmd); err != nil {
         retErr = err
         cmd.SetErr(retErr)
      }
   }

   return retErr
}

通过函数AddHook增加多个hook切片,循环的调用每个hook的处理方法

func (hs *hooks) AddHook(hook Hook) {
   hs.hooks = append(hs.hooks, hook)
}

例如增加一个hook:

clusterHook := &hook{
   beforeProcess: func(ctx context.Context, cmd redis.Cmder) (context.Context, error) {
      Expect(cmd.String()).To(Equal("ping: "))
      stack = append(stack, "cluster.BeforeProcess")
      return ctx, nil
   },
   afterProcess: func(ctx context.Context, cmd redis.Cmder) error {
      Expect(cmd.String()).To(Equal("ping: PONG"))
      stack = append(stack, "cluster.AfterProcess")
      return nil
   },
}
client.AddHook(clusterHook)