哨兵模式是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

最新文章

  1. tomcat实现ServletContext的addListener方法的源码解说(原创)
  2. QT 记事本小程序
  3. ecshop的订单状态
  4. CAGradientLayer
  5. [原创]javascript prototype 对象 函数 &lt;精简的美丽......&gt;
  6. android开发之使用拼音搜索汉字
  7. Windows server 2008系统下FTP服务器的安装
  8. ZooKeeper数据结构
  9. gdb不知为何显示2次析构
  10. StringBuffer与StringBuilder
  11. Java基础知识回顾之六 ----- IO流
  12. pandas之whl格式安装
  13. 2019清明期间qbxt培训qaq
  14. Linux内核 实践二
  15. 20145333茹翔 Exp8 Web基础
  16. 《程序员面试金典》习题解答(C/C++)
  17. IPV6的链路本地地址和站点本地地址的不同
  18. OpenGL笔记&lt;第一章&gt; 构建 GLSL class
  19. 使用Xcode 查看objective-C的汇编代码
  20. Python sqrt() 函数

热门文章

  1. ios九宫格算法
  2. 对jQuery ajax的认识
  3. linux 实用命令 —— tr
  4. PHP目前比较常见的五大运行模式SAPI(转)
  5. Oval框架如何校验枚举类型的一种思路
  6. HihoCoder - 1807:好的数字串 (KMP DP)
  7. 添加aimate动画
  8. XTU1254 Blance 如何实现称出1∼n 克的物品,请问最少需要几颗砝码?
  9. 20165313 《Java程序设计》第一周学习总结
  10. java 编译 运行 及 引用外部 jar 包的方法