Redis的哨兵详解

、Redis Sentinel

       如果主节点凌晨3 点突发宕机怎么办?就坐等运维从床上爬起来,然后手工进行从主切换,再通知所有的程序把地址统统改一遍重新上线么?毫无疑问,这样的人工运维效率太低,事故发生时估计得至少 1 个小时才能缓过来。如果是一个大型公司,这样的事故足以上新闻了。

所以我们必须有一个高可用方案来抵抗节点故障,当故障发生时可以自动进行从主切换,程序可以不用重启,运维可以继续睡大觉,仿佛什么事也没发生一样。Redis 官方提供了这样一种方案 —— Redis Sentinel(哨兵)。

 

 二、Redis Sentinel简介

             Sentinel(哨兵)进程是用于监控redis集群中Master主服务器工作的状态,在Master主服务器发生故障的时候,可以实现Master和Slave服务器的切换,保证系统的高可用,其已经被集成在redis2.6+的版本中,Redis的哨兵模式到了2.8版本之后就稳定了下来。一般在生产环境也建议使用Redis的2.8版本的以后版本。哨兵(Sentinel) 是一个分布式系统,你可以在一个架构中运行多个哨兵(sentinel) 进程,这些进程使用流言协议(gossipprotocols)来接收关于Master主服务器是否下线的信息,并使用投票协议(Agreement Protocols)来决定是否执行自动故障迁移,以及选择哪个Slave作为新的Master。每个哨兵(Sentinel)进程会向其它哨兵(Sentinel)、Master、Slave定时发送消息,以确认对方是否”活”着,如果发现对方在指定配置时间(可配置的)内未得到回应,则暂时认为对方已掉线,也就是所谓的”主观认为宕机” ,英文名称:Subjective Down,简称SDOWN。有主观宕机,肯定就有客观宕机。当“哨兵群”中的多数Sentinel进程在对Master主服务器做出 SDOWN 的判断,并且通过 SENTINEL is-master-down-by-addr 命令互相交流之后,得出的Master Server下线判断,这种方式就是“客观宕机”,英文名称是:Objectively Down, 简称 ODOWN。通过一定的vote算法,从剩下的slave从服务器节点中,选一台提升为Master服务器节点,然后自动修改相关配置,并开启故障转移(failover)。

            哨兵(sentinel) 虽然有一个单独的可执行文件 redis-sentinel ,但实际上它只是一个运行在特殊模式下的 Redis 服务器,你可以在启动一个普通 Redis 服务器时通过给定 --sentinel 选项来启动哨兵(sentinel),哨兵(sentinel) 的一些设计思路和zookeeper非常类似。

           Sentinel集群之间会互相通信,沟通交流redis节点的状态,做出相应的判断并进行处理,这里的主观下线状态和客观下线状态是比较重要的状态,它们决定了是否进行故障转移,可以 通过订阅指定的频道信息,当服务器出现故障得时候通知管理员,客户端可以将 Sentinel 看作是一个只提供了订阅功能的 Redis 服务器,你不可以使用 PUBLISH 命令向这个服务器发送信息,但你可以用 SUBSCRIBE 命令或者 PSUBSCRIBE 命令, 通过订阅给定的频道来获取相应的事件提醒。一个频道能够接收和这个频道的名字相同的事件。 比如说, 名为 +sdown 的频道就可以接收所有实例进入主观下线(SDOWN)状态的事件。

      1、Sentinel(哨兵)进程的作用:

              1】、监控(Monitoring): 哨兵(sentinel) 会不断地检查你的Master和Slave是否运作正常。

              2】、提醒(Notification):当被监控的某个Redis节点出现问题时, 哨兵(sentinel) 可以通过 API 向管理员或者其他应用程序发送通知。

              3】、自动故障迁移(Automatic failover):当一个Master不能正常工作时,哨兵(sentinel) 会开始一次自动故障迁移操作,它会将失效Master的其中一个Slave升级为新的Master, 并让失效Master的其他Slave改为复制新的Master;当客户端试图连接失效的Master时,集群也会向客户端返回新Master的地址,使得集群可以使用现在的Master替换失效Master。Master和Slave服务器切换后,Master的redis.conf、Slave的redis.conf和sentinel.conf的配置文件的内容都会发生相应的改变,即,Master主服务器的redis.conf配置文件中会多一行slaveof的配置,sentinel.conf的监控目标会随之调换
      
       2、Sentinel(哨兵)进程的工作方式:

             1】、每个Sentinel(哨兵)进程以每秒钟一次的频率向整个集群中的Master主服务器,Slave从服务器以及其他Sentinel(哨兵)进程发送一个 PING 命令。

             2】、如果一个实例(instance)距离最后一次有效回复 PING 命令的时间超过 down-after-milliseconds 选项所指定的值, 则这个实例会被 Sentinel(哨兵)进程标记为主观下线(SDOWN)。

             3】、如果一个Master主服务器被标记为主观下线(SDOWN),则正在监视这个Master主服务器的所有 Sentinel(哨兵)进程要以每秒一次的频率确认Master主服务器的确进入了主观下线状态。

             4】、当有足够数量的 Sentinel(哨兵)进程(大于等于配置文件指定的值)在指定的时间范围内确认Master主服务器进入了主观下线状态(SDOWN), 则Master主服务器会被标记为客观下线(ODOWN)。

             5】、在一般情况下, 每个 Sentinel(哨兵)进程会以每 10 秒一次的频率向集群中的所有Master主服务器、Slave从服务器发送 INFO 命令。

             6】、当Master主服务器被 Sentinel(哨兵)进程标记为客观下线(ODOWN)时,Sentinel(哨兵)进程向下线的 Master主服务器的所有 Slave从服务器发送 INFO 命令的频率会从 10 秒一次改为每秒一次。

             7】、若没有足够数量的 Sentinel(哨兵)进程同意 Master主服务器下线, Master主服务器的客观下线状态就会被移除。若 Master主服务器重新向 Sentinel(哨兵)进程发送 PING 命令返回有效回复,Master主服务器的主观下线状态就会被移除。

 三、Redis Sentinel搭建

 准备3个redis和sentinel的配置文件

[root@iZbp143t3oxhfc3ar7jey0Z redis-4.0.12]# ll
total 340
-rw-rw-r--  1 root root 165586 Dec 12  2018 00-RELEASENOTES
-rw-rw-r--  1 root root     53 Dec 12  2018 BUGS
-rw-rw-r--  1 root root   1815 Dec 12  2018 CONTRIBUTING
-rw-rw-r--  1 root root   1487 Dec 12  2018 COPYING
drwxr-xr-x  2 root root   4096 Apr 12 11:53 data
drwxrwxr-x  6 root root   4096 Mar 11 21:03 deps
-rw-r--r--  1 root root    893 Mar 21 13:32 dump.rdb
-rw-rw-r--  1 root root     11 Dec 12  2018 INSTALL
-rw-rw-r--  1 root root    151 Dec 12  2018 Makefile
-rw-rw-r--  1 root root   4223 Dec 12  2018 MANIFESTO
-rw-rw-r--  1 root root  20543 Dec 12  2018 README.md
-rw-r--r--  1 root root     54 Apr 12 11:53 redis-6380.conf
-rw-r--r--  1 root root     76 Apr 12 11:53 redis-6381.conf
-rw-rw-r--  1 root root  58781 Apr 12 11:23 redis.conf
-rw-r--r--  1 root root      0 Mar 22 14:32 redis.log
-rwxrwxr-x  1 root root    271 Dec 12  2018 runtest
-rwxrwxr-x  1 root root    280 Dec 12  2018 runtest-cluster
-rwxrwxr-x  1 root root    281 Dec 12  2018 runtest-sentinel
-rw-r--r--  1 root root    565 Apr 12 11:53 sentinel-26379.conf
-rw-r--r--  1 root root    565 Apr 12 11:53 sentinel-26380.conf
-rw-r--r--  1 root root    565 Apr 12 11:53 sentinel-26381.conf
-rw-rw-r--  1 root root   7921 Dec 12  2018 sentinel.conf
drwxrwxr-x  3 root root   4096 Mar 11 21:07 src
drwxrwxr-x 10 root root   4096 Dec 12  2018 tests
drwxrwxr-x  8 root root   4096 Dec 12  2018 utils
[root@iZbp143t3oxhfc3ar7jey0Z redis-4.0.12]#
[root@iZbp143t3oxhfc3ar7jey0Z redis-4.0.12]# cat sentinel.conf | grep -v "#" |grep -v "^$"
port 26379
dir /tmp
sentinel monitor mymaster 127.0.0.1 6379 2
sentinel down-after-milliseconds mymaster 30000
sentinel parallel-syncs mymaster 1
sentinel failover-timeout mymaster 180000
sentinel deny-scripts-reconfig yes
[root@iZbp143t3oxhfc3ar7jey0Z redis-4.0.12]# sed 's/26379/26380/g' sentinel-26379.conf > sentinel-26380.conf
[root@iZbp143t3oxhfc3ar7jey0Z redis-4.0.12]# cat sentinel-26380.conf
port 26380
dir /root/redis-4.0.12/data/
sentinel monitor mymaster 127.0.0.1 6379 2
sentinel down-after-milliseconds mymaster 30000
sentinel parallel-syncs mymaster 1
sentinel failover-timeout mymaster 180000
sentinel deny-scripts-reconfig yes
[root@iZbp143t3oxhfc3ar7jey0Z redis-4.0.12]# sed 's/26379/26381/g' sentinel-26379.conf > sentinel-26381.conf
[root@iZbp143t3oxhfc3ar7jey0Z redis-4.0.12]# cat sentinel-26381.conf
port 26381
dir /root/redis-4.0.12/data/
sentinel monitor mymaster 127.0.0.1 6379 2
sentinel down-after-milliseconds mymaster 30000
sentinel parallel-syncs mymaster 1
sentinel failover-timeout mymaster 180000
sentinel deny-scripts-reconfig yes
[root@iZbp143t3oxhfc3ar7jey0Z redis-4.0.12]# cat redis-6381.conf
port 6381
daemonize no
dir ./data/
slaveof 127.0.0.1 6379

首先启动redis的3台主从

[root@iZbp143t3oxhfc3ar7jey0Z redis-4.0.12]# redis-server  redis.conf
7853:C 12 Apr 11:41:01.966 # oO0OoO0OoO0Oo Redis is starting oO0OoO0OoO0Oo
7853:C 12 Apr 11:41:01.967 # Redis version=4.0.12, bits=64, commit=00000000, modified=0, pid=7853, just started
7853:C 12 Apr 11:41:01.967 # Configuration loaded
7853:M 12 Apr 11:41:01.968 # Creating Server TCP listening socket *:6379: bind: Address already in use
[root@iZbp143t3oxhfc3ar7jey0Z redis-4.0.12]# kill -9 6209
[root@iZbp143t3oxhfc3ar7jey0Z redis-4.0.12]# redis-server  redis.conf
7866:C 12 Apr 11:41:16.642 # oO0OoO0OoO0Oo Redis is starting oO0OoO0OoO0Oo
7866:C 12 Apr 11:41:16.643 # Redis version=4.0.12, bits=64, commit=00000000, modified=0, pid=7866, just started
7866:C 12 Apr 11:41:16.643 # Configuration loaded
                _._
           _.-``__ ''-._
      _.-``    `.  `_.  ''-._           Redis 4.0.12 (00000000/0) 64 bit
  .-`` .-```.  ```\/    _.,_ ''-._
 (    '      ,       .-`  | `,    )     Running in standalone mode
 |`-._`-...-` __...-.``-._|'` _.-'|     Port: 6379
 |    `-._   `._    /     _.-'    |     PID: 7866
  `-._    `-._  `-./  _.-'    _.-'
 |`-._`-._    `-.__.-'    _.-'_.-'|
 |    `-._`-._        _.-'_.-'    |           http://redis.io
  `-._    `-._`-.__.-'_.-'    _.-'
 |`-._`-._    `-.__.-'    _.-'_.-'|
 |    `-._`-._        _.-'_.-'    |
  `-._    `-._`-.__.-'_.-'    _.-'
      `-._    `-.__.-'    _.-'
          `-._        _.-'
              `-.__.-'

 6380服务

[root@iZbp143t3oxhfc3ar7jey0Z redis-4.0.12]# redis-server redis-6380.conf
7983:C 12 Apr 11:42:44.644 # oO0OoO0OoO0Oo Redis is starting oO0OoO0OoO0Oo
7983:C 12 Apr 11:42:44.644 # Redis version=4.0.12, bits=64, commit=00000000, modified=0, pid=7983, just started
7983:C 12 Apr 11:42:44.644 # Configuration loaded
                _._
           _.-``__ ''-._
      _.-``    `.  `_.  ''-._           Redis 4.0.12 (00000000/0) 64 bit
  .-`` .-```.  ```\/    _.,_ ''-._
 (    '      ,       .-`  | `,    )     Running in standalone mode
 |`-._`-...-` __...-.``-._|'` _.-'|     Port: 6380
 |    `-._   `._    /     _.-'    |     PID: 7983
  `-._    `-._  `-./  _.-'    _.-'
 |`-._`-._    `-.__.-'    _.-'_.-'|
 |    `-._`-._        _.-'_.-'    |           http://redis.io
  `-._    `-._`-.__.-'_.-'    _.-'
 |`-._`-._    `-.__.-'    _.-'_.-'|
 |    `-._`-._        _.-'_.-'    |
  `-._    `-._`-.__.-'_.-'    _.-'
      `-._    `-.__.-'    _.-'
          `-._        _.-'
              `-.__.-'

 6381服务

[root@iZbp143t3oxhfc3ar7jey0Z redis-4.0.12]# redis-server redis-6381.conf
8055:C 12 Apr 11:43:23.333 # oO0OoO0OoO0Oo Redis is starting oO0OoO0OoO0Oo
8055:C 12 Apr 11:43:23.333 # Redis version=4.0.12, bits=64, commit=00000000, modified=0, pid=8055, just started
8055:C 12 Apr 11:43:23.333 # Configuration loaded
                _._
           _.-``__ ''-._
      _.-``    `.  `_.  ''-._           Redis 4.0.12 (00000000/0) 64 bit
  .-`` .-```.  ```\/    _.,_ ''-._
 (    '      ,       .-`  | `,    )     Running in standalone mode
 |`-._`-...-` __...-.``-._|'` _.-'|     Port: 6381
 |    `-._   `._    /     _.-'    |     PID: 8055
  `-._    `-._  `-./  _.-'    _.-'
 |`-._`-._    `-.__.-'    _.-'_.-'|
 |    `-._`-._        _.-'_.-'    |           http://redis.io
  `-._    `-._`-.__.-'_.-'    _.-'
 |`-._`-._    `-.__.-'    _.-'_.-'|
 |    `-._`-._        _.-'_.-'    |
  `-._    `-._`-.__.-'_.-'    _.-'
      `-._    `-.__.-'    _.-'
          `-._        _.-'
              `-.__.-'

再启动sentinel集群,剩下2台的启动我就不贴出来了。

[root@iZbp143t3oxhfc3ar7jey0Z redis-4.0.12]# redis-sentinel sentinel-26379.conf
8161:X 12 Apr 11:45:27.141 # oO0OoO0OoO0Oo Redis is starting oO0OoO0OoO0Oo
8161:X 12 Apr 11:45:27.141 # Redis version=4.0.12, bits=64, commit=00000000, modified=0, pid=8161, just started
8161:X 12 Apr 11:45:27.141 # Configuration loaded
                _._
           _.-``__ ''-._
      _.-``    `.  `_.  ''-._           Redis 4.0.12 (00000000/0) 64 bit
  .-`` .-```.  ```\/    _.,_ ''-._
 (    '      ,       .-`  | `,    )     Running in sentinel mode
 |`-._`-...-` __...-.``-._|'` _.-'|     Port: 26379
 |    `-._   `._    /     _.-'    |     PID: 8161
  `-._    `-._  `-./  _.-'    _.-'
 |`-._`-._    `-.__.-'    _.-'_.-'|
 |    `-._`-._        _.-'_.-'    |           http://redis.io
  `-._    `-._`-.__.-'_.-'    _.-'
 |`-._`-._    `-.__.-'    _.-'_.-'|
 |    `-._`-._        _.-'_.-'    |
  `-._    `-._`-.__.-'_.-'    _.-'
      `-._    `-.__.-'    _.-'
          `-._        _.-'
              `-.__.-'

8161:X 12 Apr 11:45:27.142 # WARNING: The TCP backlog setting of 511 cannot be enforced because /proc/sys/net/core/somaxconn is set to the lower value of 128.

 当3台都启动好了,发现原来的sentinel的配置会多了一些信息。

 Sentinel的原理

哨兵在进行主从切换过程中经历三个阶段

  • 监控
  • 通知
  • 故障转移

第一阶段:

首先要获取各个哨兵在不在,通过ping的指令,还要获取matser信息,可以通过info命令,拿到它的runid和它的角色,再获取各个slave的详细信息

,也是通过info向各个slave获取信息,拿到各种信息,准备后面的主节点挂了有用,当第二个sentinel也要重复一样的事情,它存的SentinelState

中的sentinels的信息会比第一个多点,为了保证他们的信息一样,就会通过发布订阅一直用来同步,并且看对方在不在。

 

 

 

 第二阶段:

sentinel会用redis发送hello信息,看各个服务在不在,拿到返回的信息然后,sentinel在与别的sentinel节点发布,进行信息的传播

 第三阶段:

sentinel当发现master挂了以后,会标记成S_DOWN,剩下的sentinel就会也去发hello,去看master是不是真的挂了,当过了半数以后,就会标记成O_DOWN,即客观下线。

会在sentinel中发送信息,如:那个服务挂了,挂的端口,自己参加竞选的次数已经自己的runid,sentinel先接到别的节点的信息,就会把

票投给谁,到最后会得到一个投票的结论,如果票数一致,会继续投票,竞选次数加1,到最后选出老大

 

于是去开始进行选择matser,首选要选择选择在线的,然后一直发送hello,在pass响应慢的,

接下来与原master断开的时间久的,找到最近连接的,最后就是优选原则,偏移量,到最后

就是去找小的runid,就是当成master,然后与各个slave发送信息,与自己相连。

主从切换演示:我把master的服务停了。

 下面就是sentinel的日志变化

 由于之前的从不能进行写,现在去6380的客户端测试一下

[root@iZbp143t3oxhfc3ar7jey0Z ~]# redis-cli -p 6380
127.0.0.1:6380> get name
"wgr"
127.0.0.1:6380> set n1 test
OK
127.0.0.1:6380> get n1
"test"
127.0.0.1:6380> exit
posted @ 2020-04-12 14:01  天宇轩-王  阅读(857)  评论(0编辑  收藏  举报