golang对redis哨兵模式的实验

介绍

  • redis的哨兵模式(Sentinel)是以主从复制为架构的运行模式,旨在提高redis集群的容错性,可搭配cluster模式组合使用,本文不涉及cluster

  • 假设一个场景,redis配置了主从,程序中链接主节点地址进行写入查询操作,当主节点挂了后,为了让从节点顶上来,需要手动将程序中主节点ip换成从节点的,人工干预费事费力,还会造成一段时间内服务不可用

  • Sentinel 哨兵模式是一种特殊的模式,独立的进程,程序中链接哨兵服务的ip,将会为程序提供安全可靠的节点容灾切换,有些类似于服务发现

  • 哨兵模式通常设置多个节点,其中挂了一个后,其它的也能顶上来,这也就要求程序中需要将哨兵的所有节点地址都写进去

环境概述

redis 主从节点

  • 主 127.0.0.1:6388
  • 从 127.0.0.1:6398

假如有3个sentinel实例依次为:

  • 127.0.0.1:26379
  • 127.0.0.1:26380
  • 127.0.0.1:26381

哨兵节点配置文件,以 26379 为例

sentinel.conf

port 26379
dir /tmp
sentinel monitor mymaster 127.0.0.1 6388 2
sentinel down-after-milliseconds mymaster 6000
sentinel failover-timeout mymaster 18000
sentinel parallel-syncs mymaster 1

配置详解
sentinel monitor mymaster 127.0.0.1 6388 2

  • 设置 Sentinel 监控名为 mymaster 的 Redis 主服务器。
  • 127.0.0.1 是主服务器的 IP 地址,6388 是主服务器的端口号。
  • 2 是最小数量的 Sentinel 节点,当这些节点都同意主服务器处于下线状态时,Sentinel 会开始故障转移。

sentinel down-after-milliseconds mymaster 6000

  • 设置当 Sentinel 认为主服务器 mymaster 下线之前,需要等待的时间,单位是毫秒。
  • 如果在 6000 毫秒内没有收到主服务器的响应,Sentinel 将认为主服务器处于下线状态。

sentinel failover-timeout mymaster 18000

  • 设置故障转移操作的超时时间,单位是毫秒。
  • 如果故障转移操作在 18000 毫秒内没有完成,Sentinel 将停止故障转移尝试。

sentinel parallel-syncs mymaster 1

  • 这个命令设置在故障转移过程中,可以同时进行数据同步的从服务器的数量。
  • 在这个例子中,1 表示只有一个从服务器可以同时进行数据同步。

实验准备,程序客户端体现

使用NewFailoverClient实例化一个可故障转移的客户端

main.go

package main
 
import (
        "fmt"
        "github.com/go-redis/redis"
        "time"
)
 
func main() {
        client := redis.NewFailoverClient(&redis.FailoverOptions{
                MasterName:    "mymaster", // 与哨兵配置文件中 mymaster 对应
                SentinelAddrs: []string{"127.0.0.1:26379", "127.0.0.1:26380", "127.0.0.1:26381"},
                Password:      "",
                DB:            0,
        })
 
        for {
                reply, err := client.Incr("pvcount").Result()
                fmt.Printf("reply=%v err=%v\n", reply, err)
                time.Sleep(1 * time.Second)
        }
 
}

实验开始

实验1:redis节点主从切换

运行 main.go
在执行过程中,shutdown redis 主节点 127.0.0.1:6388
可以看到在reply等于93和94之间,客户端监测到了主从切换,并重新连接到新的主节点,这段时间大致等于sentinel配置down-after-milliseconds的时长。

[root@dev example]# go run main.go
redis: 2024/07/16 00:09:53 sentinel.go:379: sentinel: discovered new sentinel="93db6069e9bde858a99b873048891912eecd45d4" for master="mymaster"
redis: 2024/07/16 00:09:53 sentinel.go:379: sentinel: discovered new sentinel="48ee106539cf267a79a84db621a01ee01b73ca5e" for master="mymaster"
redis: 2024/07/16 00:09:53 sentinel.go:332: sentinel: new master="mymaster" addr="127.0.0.1:6388"
reply=1 err=<nil>
reply=2 err=<nil>
reply=3 err=<nil>
reply=4 err=<nil>
reply=5 err=<nil>
reply=6 err=<nil>
...
reply=83 err=<nil>
reply=84 err=<nil>
reply=85 err=<nil>
reply=86 err=<nil>
reply=87 err=<nil>
reply=88 err=<nil>
reply=89 err=<nil>
reply=90 err=<nil>
reply=91 err=<nil>
reply=92 err=<nil>
reply=93 err=<nil>
reply=0 err=EOF
reply=0 err=dial tcp 127.0.0.1:6388: connect: connection refused
reply=0 err=dial tcp 127.0.0.1:6388: connect: connection refused
reply=0 err=dial tcp 127.0.0.1:6388: connect: connection refused
reply=0 err=dial tcp 127.0.0.1:6388: connect: connection refused
reply=0 err=dial tcp 127.0.0.1:6388: connect: connection refused
reply=0 err=dial tcp 127.0.0.1:6388: connect: connection refused
redis: 2024/07/16 00:11:33 sentinel.go:332: sentinel: new master="mymaster" addr="127.0.0.1:6398"
reply=94 err=<nil>
reply=95 err=<nil>
reply=96 err=<nil>
reply=97 err=<nil>
reply=98 err=<nil>
reply=99 err=<nil>
reply=100 err=<nil>
实验2:sentinel实例全部挂掉后,redis的读写操作

如果把3个sentinel实例全部 kill掉,则go-redis会记录一条日志,而对redis的读写操作仍然正常。

reply=233 err=<nil>
reply=234 err=<nil>
reply=235 err=<nil>
reply=236 err=<nil>
reply=237 err=<nil>
redis: 2024/07/16 22:06:45 pubsub.go:159: redis: discarding bad PubSub connection: EOF                                                                                                   
reply=238 err=<nil>
reply=239 err=<nil>
reply=240 err=<nil>
实验3:sentinel实例部分挂掉后(剩余实例数目多于配置的quorum),redis实例的主从切换

quorum 对应哨兵配置文件中的同意个数 2 sentinel monitor mymaster 127.0.0.1 6388 2

如果只kill掉1个sentinel,则剩余两个sentinel还能正常监测redis主从切换。
例如下面是kill掉 127.0.0.1:26379 之后,再kill redis主节点 127.0.0.1:6388 的实验

reply=322 err=<nil>
reply=323 err=<nil>
reply=324 err=<nil>
reply=325 err=<nil>
reply=326 err=<nil>
reply=327 err=<nil>
reply=328 err=<nil>
reply=329 err=<nil>
reply=330 err=<nil>
reply=0 err=EOF
redis: 2024/07/16 22:08:19 sentinel.go:313: sentinel: GetMasterAddrByName name="mymaster" failed: EOF
redis: 2024/07/16 22:08:19 sentinel.go:313: sentinel: GetMasterAddrByName name="mymaster" failed: dial tcp 127.0.0.1:26379: connect: connection refused
redis: 2024/07/16 22:08:19 sentinel.go:287: sentinel: GetMasterAddrByName master="mymaster" failed: dial tcp 127.0.0.1:26379: connect: connection refused
redis: 2024/07/16 22:08:19 sentinel.go:379: sentinel: discovered new sentinel="9a023490096f5f87db1c7f445d883f56e75275db" for master="mymaster"
reply=0 err=dial tcp 127.0.0.1:6388: connect: connection refused
reply=0 err=dial tcp 127.0.0.1:6388: connect: connection refused
reply=0 err=dial tcp 127.0.0.1:6388: connect: connection refused
reply=0 err=dial tcp 127.0.0.1:6388: connect: connection refused
reply=0 err=dial tcp 127.0.0.1:6388: connect: connection refused
reply=0 err=dial tcp 127.0.0.1:6388: connect: connection refused
redis: 2024/07/16 22:08:24 sentinel.go:332: sentinel: new master="mymaster" addr="127.0.0.1:6398"
reply=331 err=<nil>
reply=332 err=<nil>
reply=333 err=<nil>
reply=334 err=<nil>
实验4:sentinel实例都正常的情况下,进行redis实例迁移

当3个sentinel都正常运行的情况下,动态增减从节点对客户端没有影响。
例如

  • 增加一个从节点 127.0.0.1:6378
  • 再把原从节点 127.0.0.1:6398 shutdown,客户端没有影响。
  • 进而把主节点 127.0.0.1:6388 shutdown,迫使主从切换,此时 127.0.0.1:6378 成为了新的主节点。
reply=525 err=<nil>
reply=526 err=<nil>
reply=527 err=<nil>
reply=528 err=<nil>
reply=529 err=<nil>
reply=530 err=<nil>
reply=531 err=<nil>
reply=0 err=EOF
reply=0 err=dial tcp 127.0.0.1:6398: connect: connection refused
reply=0 err=dial tcp 127.0.0.1:6398: connect: connection refused
reply=0 err=dial tcp 127.0.0.1:6398: connect: connection refused
reply=0 err=dial tcp 127.0.0.1:6398: connect: connection refused
reply=0 err=dial tcp 127.0.0.1:6398: connect: connection refused
reply=0 err=dial tcp 127.0.0.1:6398: connect: connection refused
reply=0 err=dial tcp 127.0.0.1:6398: connect: connection refused
redis: 2024/07/16 22:43:19 sentinel.go:332: sentinel: new master="mymaster" addr="127.0.0.1:6378"
reply=532 err=<nil>
reply=533 err=<nil>
reply=534 err=<nil>
reply=535 err=<nil>
reply=536 err=<nil>
reply=537 err=<nil>

结论

redis的go-redis包操作哨兵模式是可靠的

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值