• redis sentinel哨兵的使用


    哨兵模式是Redis集群管理的一种方式。
    下面以Go语言为例介绍其使用方式。

    使用举例

    package main
    import (
        "fmt"
    	"strings"
    	"github.com/garyburd/redigo/redis"
    
    	"github.com/FZambia/sentinel"
    )
    
    var RedisConnPool *redis.Pool
    
    func InitRedisSentinelConnPool() {
    	redisAddr := "192.168.1.11:26378,192.168.1.22:26378"
    	redisAddrs := strings.Split(redisAddr, ",")
    	masterName := "master1" // 根据redis集群具体配置设置
    
    	sntnl := &sentinel.Sentinel{
    		Addrs:      redisAddrs,
    		MasterName: masterName,
    		Dial: func(addr string) (redis.Conn, error) {
    			timeout := 500 * time.Millisecond
    			c, err := redis.DialTimeout("tcp", addr, timeout, timeout, timeout)
    			if err != nil {
    				return nil, err
    			}
    			return c, nil
    		},
    	}
    
    	RedisConnPool = &redis.Pool{
    		MaxIdle:     redisConfig.MaxIdle,
    		IdleTimeout: 240 * time.Second,
    		Dial: func() (redis.Conn, error) {
    			masterAddr, err := sntnl.MasterAddr()
    			if err != nil {
    				return nil, err
    			}
    			c, err := redis.Dial("tcp", masterAddr)
    			if err != nil {
    				return nil, err
    			}
    			return c, nil
    		},
    		TestOnBorrow: CheckRedisRole,
    	}
    }
    
    func CheckRedisRole(c redis.Conn, t time.Time) error {
    	if !sentinel.TestRole(c, "master") {
    		return fmt.Errorf("Role check failed")
    	} else {
    		return nil
    	}
    }
    
    
    
    func main(){
    	rc := RedisConnPool.Get()
    	defer rc.Close()
    
    	for {
    		reply, err := redis.String(rc.Do("RPOP", "/queue/cmd"))
    		if err != nil {
    			if err != redis.ErrNil {
    				log.Println("Redis RPOP failed:", err)
    			}
    
                fmt.Println("reply:", reply)
    			break
    		}// if
    
    	}// for
    }
    

    哨兵方式client端的实现原理

    client查询集群中的master节点。

    client查询Master
    其代码如下:

    // MasterAddr returns an address of current Redis master instance.
    func (s *Sentinel) MasterAddr() (string, error) {
    	res, err := s.doUntilSuccess(func(c redis.Conn) (interface{}, error) {
    		return queryForMaster(c, s.MasterName)
    	})
    	if err != nil {
    		return "", err
    	}
    	return res.(string), nil
    }
    

    基本过程是:使用redis 服务器地址,创建连接,发送请求,返回Redis Master地址。

    连接redis集群使用的是轮询方式(见doUntilSuccess函数)。
    doUntilSuccess函数接收查询master的函数queryForMaster作为参数,queryForMaster的代码如下。

    查询master节点

    func queryForMaster(conn redis.Conn, masterName string) (string, error) {
    	res, err := redis.Strings(conn.Do("SENTINEL", "get-master-addr-by-name", masterName))
    	if err != nil {
    		return "", err
    	}
    	if len(res) < 2 {
    		return "", errors.New("redigo: malformed get-master-addr-by-name reply")
    	}
    	masterAddr := net.JoinHostPort(res[0], res[1])
    	return masterAddr, nil
    }
    

    轮询方式连接服务器doUntilSuccess

    基本过程如下:

    从Redis服务器地址中选择一台机器,尝试连接,并执行查询操作。如果成功,则直接返回结果。并将这台机器地址活跃性权重提升。

    如果第一个地址失败,把这个地址从连接池中去掉,并降低活跃性权重。接着,尝试下一个地址。
    如果所有地址都失败,则返回错误。

    具体代码如下:

    func (s *Sentinel) doUntilSuccess(f func(redis.Conn) (interface{}, error)) (interface{}, error) {
    	s.mu.RLock()
    	addrs := s.Addrs
    	s.mu.RUnlock()
    
    	var lastErr error
    
    	for _, addr := range addrs {
    		conn := s.get(addr)
    		reply, err := f(conn)
    		conn.Close()
    		if err != nil {
    			lastErr = err
    			s.mu.Lock()
    			pool, ok := s.pools[addr]
    			if ok {
    				pool.Close()
    				delete(s.pools, addr)
    			}
    			s.putToBottom(addr)
    			s.mu.Unlock()
    			continue
    		}
    		s.putToTop(addr)
    		return reply, nil
    	}
    
    	return nil, NoSentinelsAvailable{lastError: lastErr}
    }
    

    参考

    https://github.com/garyburd/redigo
    https://github.com/FZambia/go-sentinel

    https://godoc.org/github.com/FZambia/go-sentinel

    https://redis.io/topics/sentinel-clients

  • 相关阅读:
    DotText源码阅读
    看来这世界看得太清楚了也未必是种好事呢~~~~~~~
    在Init之前究竟执行了什么?
    孙子兵法
    Excel区域重命名
    Getbuffer ReleaseBuffer Cstring
    批量删除svn标志
    VB制作网页自动填表(强烈推荐)
    GetModuleFileName
    ansi编码
  • 原文地址:https://www.cnblogs.com/lanyangsh/p/9349694.html
Copyright © 2020-2023  润新知