Redis Sentinel高可用实现

Redis Sentinel高可用实现

Redis v2.8 之后提供了高可用实现Redis Sentinel,实现了主从复制以及被动主备切换v3.0 之后提供了分布式实现Redis Cluster

本文讨论的是使用Sentinel搭建Redis高可用服务。

If all redis and sentinel instances were deployed in same host, you just build a fake redis-sentinel High-Availability environment1.

1 准备 #

1.1 linux主机 #

本文使用centOS7,需安装gcc:

1yum install gcc
2# or on ubuntu
3apt-get install gcc

1.2 Redis 源码 #

本文使用 v4.0.0.11,版本号应大于2.8.0。

可以使用如下命令来获取指定版本的redis:

1wget http://download.redis.io/releases/redis-4.0.11.tar.gz

1.3 了解linux防火墙的基本知识 #

centOS7和centOS6使用不同的防火墙机制,前者使用firewall,后者使用iptables

1.4 master,slave和sentinel #

如果只想搭建一个单机(standalone)实例2来学习redis的数据结构,只需要阅读安装redis实例就好。

多个standalone加之合适的配置便组成了master-slave结构,一般而言,此时已经具备了「主从复制」的能力。

所谓Sentinel,并不是所谓「新技术」名词,只是一个用来做特定事情3的redis实例而已,故此我们也可以将其称作「服务」。如果需要搭建Sentinel服务,你需要先具备master-slave结构,也就是说,你至少需要搭建2个redis实例,并且将其中一台配置为另一台的slave。

了解更多关于redis-sentinel的相关内容,请参考 redis哨兵与高可用架构

redis的主从模式和哨兵模式

2 安装配置Redis #

接下来会依次安装Redis并且配置多个Redis实例

2.1 编译源码 #

 1  tar -zxf redis-4.0.11.tar.gz
 2  # compile source code
 3  cd redis-4.0.11
 4  # redis was recommended to install in /usr/local/redis
 5  mkdir /usr/local/redis
 6  make install PREFIX=/usr/local/redis
 7  # ---
 8  # if all operations are right, you will see the output below:
 9  [root@shell ~]# cd /usr/local/redis ; ll
10  total 68
11  #the redis executable binary file folder
12  drwxr-xr-x 2 root root  4096 Aug  4 15:19 bin         
13  # the (RDB)dump file of redis database, You can config where to save it later
14  -rw-r--r-- 1 root root    93 Aug  4 16:54 dump.rdb     
15  # the config file of a particular redis instance
16  -rw-r--r-- 1 root root 58905 Aug  7 13:56 redis.conf  
17  [root@shell redis]# cd /usr/local/redis/bin ; ll    
18  total 21876
19  # redis test tool
20  -rwxr-xr-x 1 root root 2452168 Aug  4 15:19 redis-benchmark   
21  # redis AOF persistent check tool
22  -rwxr-xr-x 1 root root 5775312 Aug  4 15:19 redis-check-aof   
23  # redis RBD persistent check tool
24  -rwxr-xr-x 1 root root 5775312 Aug  4 15:19 redis-check-rdb   
25  # launch a redis client
26  -rwxr-xr-x 2 root root 2618192 Aug  4 15:19 redis-cli         
27  # link to redis-server, launch a redis sentinel
28  lrwxrwxrwx 1 root root      12 Aug  4 15:19 redis-sentinel -> redis-server   server
29  #launch a redis server(instance)
30  -rwxr-xr-x 3 root root 5775312 Aug  4 15:19 redis-server  

两个ll命令显示了一个redis的全部内容。本文用到的几个文件分别是:

  • redis.conf: 配置文件,绝对的主角,它的戏谁都抢不走
  • redis-server: 用于启动redis缓存服务
  • redis-client:command-line client tool

2.2 其他配置项 #

如果上述操作没有问题这么简单也不会有问题,理论上,一个standalone实例已经安装完成了,可以通过「命令 配置文件」的方式启动redis服务:

1/usr/local/redis/bin/redis-server /usr/local/redis/redis.conf

但是为了方便启动服务,还需要做一些额外的操作:

1. 复制redis二进制程序到系统环境变量 #

1cd /usr/local/redis/bin/
2cp redis-server redis-cli redis-sentinel /usr/local/bin

如此,启动redis的时候便不需要指定程序路径; 此时,已经可以直接在终端运行redis-server

2. 将redis设置为开机启动: #

1# 安装完成后可以添加多个命令启动redis主从-哨兵系统
2echo "redis-server /usr/local/redis.conf" >> /etc/rc.local

3. 开放防火墙端口 #

若主机未开启防火墙,则无需操作

如果你的主机开启了防火墙,其他主机是无法连接上你的redis-server的,此时需要为其开放端口。

前面说到,centOS7和centOS6的防火墙机制不一样,需要分别处理。

若需知晓防火墙状态,请运行4

1systemctl status serviceName

centOS7 和centOS6的防火墙服务名分别为 firewalldiptables

对于centOS 7: #

 1# 查看开放端口
 2[root@shell ~]# firewall-cmd --list-all
 3public
 4  target: default
 5  icmp-block-inversion: no
 6  interfaces:
 7  sources:
 8  services: ssh dhcpv6-client http
 9  ports: 6379/tcp
10  protocols:
11  masquerade: no
12  forward-ports:
13  source-ports:
14  icmp-blocks:
15  rich rules:
16# 如果6379端口不在返回结果中,那么将6379添加到开放端口列表中
17[root@shell ~]# firewall-cmd --permanent --add-port=6379/tcp
18[root@shell ~]# firewall-cmd --reload

centOS 6 #

1# 添加规则
2iptables -I INPUT -p tcp -m tcp --dport 6379 -j ACCEPT
3# 保存规则
4service iptables save
5# 重启iptables
6service iptables restart

2.3 配置文件redis.conf #

在redis的 安装文件夹内,有一个系统预配置文件redis.conf,我们需要修改此配置文件以满足需求。

以下列出了(redis-standalone)常见配置列表4

 1# redis进程是否以守护进程的方式(后台)运行(不以守护进程的方式运行会占用一个终端)
 2daemonize yes
 3# 指定redis进程的PID文件存放位置
 4pidfile /var/run/redis.pid
 5# redis进程的端口号
 6port 6379
 7# 允许任何ipv4的主机连接;
 8bind 0.0.0.0
 9# 客户端闲置多长时间(s)后关闭连接,默认此参数为0即关闭此功能
10timeout 300
11# redis日志级别,可用的级别有debug.verbose.notice.warning
12loglevel verbose
13# log文件输出位置,如果进程以守护进程的方式运行,此处又将输出文件设置为stdout的话,
14# 就会将日志信息输出到/dev/null里面去了
15logfile /var/log/redis/redis_6379.log
16# 设置数据库的数量,默认为0可以使用select <dbid>命令在连接上指定数据库id
17databases 16
18# 保存db到磁盘,可配置多条,表示不同级别的数据改动
19# 如下配置表示至少有一个key-value发生改动时,900s之后将其保存到磁盘;
20# 如果至少有10个key-value发生改动,那么300s后将其保存到磁盘;
21save 900 1
22save 300 10
23# 指定存储至本地数据库时是否压缩文件,默认为yes即启用存储
24rdbcompression yes
25# 指定本地数据库文件名
26dbfilename dump.db
27# 指定本地数据文件存放位置,以下配置表示保存在redis安装目录
28dir ./
29# 指定当本机为slave服务,配置为master的IP及端口,在redis启动的时候他会自动跟master进行数据同步
30slaveof <masterip> <masterport>
31# 当master设置了密码保护时,slave服务连接master的密码
32masterauth <master-password>
33# 设置redis连接密码,如果配置了连接密码,客户端在连接redis是需要通过AUTH<password>命令
34# 提供密码,默认关闭
35requirepass password
36# 设置同一时间最大客户连接数,默认无限制。redis可以同时连接的客户端数为redis程序可以打开的最大
37# 文件描述符,如果设置 maxclients 0,表示不作限制。当客户端连接数到达限制时,Redis会关闭新的
38# 连接并向客户端返回 max number of clients reached 错误信息
39maxclients 128
40# 指定Redis最大内存限制,Redis在启动时会把数据加载到内存中,达到最大内存后,Redis会先尝试清除
41# 已到期或即将到期的Key。当此方法处理后,仍然到达最大内存设置,将无法再进行写入操作,但仍然可以
42# 进行读取操作。Redis新的vm机制,会把Key存放内存,Value会存放在swap区
43maxmemory <bytes>
44# 指定是否在每次更新操作后进行日志记录,Redis在默认情况下是异步的把数据写入磁盘,如果不开启,可
45# 能会在断电时导致一段时间内的数据丢失。因为redis本身同步数据文件是按上面save条件来同步的,所以
46# 有的数据会在一段时间内只存在于内存中。默认为no。
47appendonly no
48# 指定跟新日志文件名默认为appendonly.aof
49appendfilename appendonly.aof
50# 指定更新日志的条件,有三个可选参数 - no:表示等操作系统进行数据缓存同步到磁盘(快),always:表示每次
51# 更新操作后手动调用fsync()将数据写到磁盘(慢,安全), everysec:表示每秒同步一次(折衷,默认值);
52appendfsync everysec

⚠️注意:关于bind指令的描述可以配置指定ip来允许指定连接,多个ip使用空格分隔,关于bind的意义,参考 redis配置外网访问

3 启动redis #

redis.conf文件配置无差的话,即可指定配置文件启动redis服务:

1redis-server /usr/local/redis/redis.conf

启动日志:

27552:C 04 Aug 16:12:58.912 # oO0OoO0OoO0Oo Redis is starting oO0OoO0OoO0Oo
27552:C 04 Aug 16:12:58.912 # Redis version=4.0.11, bits=64, commit=00000000,
 modified=0, pid=27552, just started
27552:C 04 Aug 16:12:58.912 # Configuration loaded
                _._                                                  
           _.-``__ ''-._                                             
      _.-``    `.  `_.  ''-._           Redis 4.0.11 (00000000/0) 64 bit
  .-`` .-```.  ```\/    _.,_ ''-._                                   
 (    '      ,       .-`  | `,    )     Running in standalone mode
 |`-._`-...-` __...-.``-._|'` _.-'|     Port: 6379
 |    `-._   `._    /     _.-'    |     PID: 27553
  `-._    `-._  `-./  _.-'    _.-'                                   
 |`-._`-._    `-.__.-'    _.-'_.-'|                                  
 |    `-._`-._        _.-'_.-'    |           http://redis.io        
  `-._    `-._`-.__.-'_.-'    _.-'                                   
 |`-._`-._    `-.__.-'    _.-'_.-'|                                  
 |    `-._`-._        _.-'_.-'    |                                  
  `-._    `-._`-.__.-'_.-'    _.-'                                   
      `-._    `-.__.-'    _.-'                                       
          `-._        _.-'                                           
              `-.__.-'                                               

27553:M 04 Aug 16:12:58.915 # WARNING: The TCP backlog setting of 511 cannot
be enforced because /proc/sys/net/core/somaxconn is set to the lower value of 128.
27553:M 04 Aug 16:12:58.916 # Server initialized
27553:M 04 Aug 16:12:58.916 # WARNING overcommit_memory is set to 0! Background
save may fail under low memory condition. To fix this issue add
'vm.overcommit_memory = 1' to /etc/sysctl.conf and then reboot or run the
command 'sysctl vm.overcommit_memory=1' for this to take effect.
27553:M 04 Aug 16:12:58.916 # WARNING you have Transparent Huge Pages (THP)
 support enabled in your kernel. This will create latency and memory usage
 issues with Redis. To fix this issue run the command
 'echo never > /sys/kernel/mm/transparent_hugepage/enabled' as root, and add it
  to your /etc/rc.local in order to retain the setting after a reboot.
  Redis must be restarted after THP is disabled.
27553:M 04 Aug 16:12:58.916 * Ready to accept connections

可以看到,一个standalon已经运行成功,但是有3个WARNING[^V5]:

 1WARNING: The TCP backlog setting of 511 cannot be enforced because
 2 /proc/sys/net/core/somaxconn is set to the lower value of 128.
 3# solution
 4[root@shell ~]# echo 511 >/proc/sys/net/core/somaxconn
 5[root@shell ~]# echo "net.core.somaxconn = 551" >> /etc/sysctl.conf
 6
 7WARNING overcommit_memory is set to 0! Background save may fail under low
 8memory condition. To fix this issue add 'vm.overcommit_memory = 1'
 9to /etc/sysctl.conf and then reboot or run the command
10'sysctl vm.overcommit_memory=1' for this to take effect.
11#solution
12[root@shell ~]# echo 1 > /proc/sys/vm/overcommit_memory
13[root@shell ~]# echo "vm.overcommit_memory=1" >> /etc/sysctl.conf
14
15WARNING you have Transparent Huge Pages (THP) support enabled in your kernel.
16This will create latency and memory usage issues with Redis. To fix this issue
17 run the command 'echo never > /sys/kernel/mm/transparent_hugepage/enabled' as
18 root, and add it to your /etc/rc.local in order to retain the setting after a
19  reboot. Redis must be restarted after THP is disabled.
20#solution
21[root@shell ~]# echo never > /sys/kernel/mm/transparent_hugepage/enabled
22[root@shell ~]# vi /etc/rc.local
23if test -f /sys/kernel/mm/transparent_hugepage/enabled; then
24   echo never > /sys/kernel/mm/transparent_hugepage/enabled
25fi
26if test -f /sys/kernel/mm/transparent_hugepage/defrag; then
27   echo never > /sys/kernel/mm/transparent_hugepage/defrag
28fi    

4 使用redis-cli #

redis服务启动成功之后,便可以通过redis-cli与服务进行交互。

 1# 连接redis-server,若-h和-p参数缺省,则默认连接localhost:6379
 2redis-cli -h 127.0.0.1 -p 6379
 3127.0.0.1:6379>
 4# 若redis-server requirepass设置了密码,那么需要认证
 5127.0.0.1:6379> auth yourpassword
 6OK
 7# ping-PONG说明redis服务正常
 8127.0.0.1:6379> ping
 9127.0.0.1:6379> PONG
10# 获取帮助
11127.0.0.1:6379> help
12redis-cli 4.0.11
13To get help about Redis commands type:
14      "help @<group>" to get a list of commands in <group>
15      "help <command>" for help on <command>
16      "help <tab>" to get a list of possible help topics
17      "quit" to exit
18
19To set redis-cli preferences:
20      ":set hints" enable online hints
21      ":set nohints" disable online hints
22Set your preferences in ~/.redisclirc
23127.0.0.1:6379> help shutdown
24
25  SHUTDOWN [NOSAVE|SAVE]
26  summary: Synchronously save the dataset to disk and then shut down the server
27  since: 1.0.0
28  group: server
29
30127.0.0.1:6379>
31# 退出客户端
32127.0.0.1:6379> exit

5 关闭redis-server #

⚠️不要使用kill -9 pid关闭redis server,这样会可能会丢失数据完整性

1#关闭redis-server 可选参数nosave|save意为关闭服务之前是否保存数据到磁盘
2127.0.0.1:6379> shutdown [nosave|save]

6 艺术就是复制 #

以下配置是基于一台服务器的演示,如果要部署高可用环境,需要在不同的服务器上安装redis并作如下配置

经过上述操作,一个redis-standalone服务就配置好了,如果要将redis系统高可用,只需要「复制」就好了。

前面说过,redis-server是通过可执行文件 + 配置文件的方式启动,可执行文件已经解压得到,那么只需要复制配置文件就可以了。

以下是本次slave和sentinel的配置:

RoleAddressPort
Masterlocalhost6379
Slavelocalhost16379, 26379
Sentinellocalhost6380, 16380, 26380
1# current workDir
2cd /usr/local
3# 创建文件夹存放slave和sentinel配置文件
4mkdir redis-slave  redis-sentinel
5cp -r redis/redis.conf redis-slave
6cp -r redis/redis.conf redis-sentinel
7# slave配置文件
8mv redis-slave/redis.conf redis-slave/slave-16379.conf

6.1 配置redis-salve #

slave的配置大抵和standalone一致,需要注意配置几个地方:

  • logfile的保存地址配置自行配置
  • masterauthrequirepass配置master的密码
  • slaveof指明了其是哪个「主」的「从」
  • slave-read-only指明从服务器只读
 1vim redis-slave/slave-16379.conf
 2<<<
 3    daemonize yes
 4    pidfile /var/run/redis-16379.pid
 5    logfile /var/log/redis/redis-16379.log
 6    port 16379
 7    bind 0.0.0.0
 8    timeout 300
 9    databases 16
10    dbfilename dump-16379.db
11    dir ./
12    masterauth yourpassword
13    requirepass yourpassword
14    slave-read-only yes
15    slaveof 127.0.0.1 6379
1# 再多配一个slave
2cp redis-slave/slave-16379.conf redis-slave/slave-26379.conf

同样地,只需要更改部分配置内容(端口,文件名)就可以了。

6.1.1 salve启动日志 #

以下是配置成功的slave启动日志:

30463:C 05 Aug 11:33:34.536 # oO0OoO0OoO0Oo Redis is starting oO0OoO0OoO0Oo
30463:C 05 Aug 11:33:34.537 # Redis version=4.0.11, bits=64, commit=00000000,
modified=0, pid=30463, just started
30463:C 05 Aug 11:33:34.537 # Configuration loaded
                _._                                                  
           _.-``__ ''-._                                             
      _.-``    `.  `_.  ''-._           Redis 4.0.11 (00000000/0) 64 bit
  .-`` .-```.  ```\/    _.,_ ''-._                                   
 (    '      ,       .-`  | `,    )     Running in standalone mode
 |`-._`-...-` __...-.``-._|'` _.-'|     Port: 26379
 |    `-._   `._    /     _.-'    |     PID: 30464
  `-._    `-._  `-./  _.-'    _.-'                                   
 |`-._`-._    `-.__.-'    _.-'_.-'|                                  
 |    `-._`-._        _.-'_.-'    |           http://redis.io        
  `-._    `-._`-.__.-'_.-'    _.-'                                   
 |`-._`-._    `-.__.-'    _.-'_.-'|                                  
 |    `-._`-._        _.-'_.-'    |                                  
  `-._    `-._`-.__.-'_.-'    _.-'                                   
      `-._    `-.__.-'    _.-'                                       
          `-._        _.-'                                      
              `-.__.-'                                               

30464:S 05 Aug 11:33:34.539 # Server initialized
30464:S 05 Aug 11:33:34.539 * Ready to accept connections
# 注意以下输出:
30464:S 05 Aug 11:33:34.539 * Connecting to MASTER 127.0.0.1:6379
30464:S 05 Aug 11:33:34.539 * MASTER <-> SLAVE sync started
30464:S 05 Aug 11:33:34.539 * Non blocking connect for SYNC fired the event.
30464:S 05 Aug 11:33:34.539 * Master replied to PING, replication can continue...
30464:S 05 Aug 11:33:34.539 * Partial resynchronization not possible
 (no cached master)
30464:S 05 Aug 11:33:34.540 * Full resync from master:
4e99dfc708f2035b3b39f34796434de5889f667b:308
30464:S 05 Aug 11:33:34.543 * MASTER <-> SLAVE sync: receiving 177 bytes from master
30464:S 05 Aug 11:33:34.543 * MASTER <-> SLAVE sync: Flushing old data
30464:S 05 Aug 11:33:34.543 * MASTER <-> SLAVE sync: Loading DB in memory
30464:S 05 Aug 11:33:34.543 * MASTER <-> SLAVE sync: Finished with success

slave的启动日志有几个信息值得关注:

  • redis启动警告信息消除,说明我们之前的配置生效了;
  • slave server 初始化成功之后,便开始连接master;
  • master 连接成功之后,便开始从主数据库同步数据;
  • 之后,从数据库一直监听机制主数据库的改动并同步数据

6.1.2 验证主从数据同步 #

可以通过在主数据库写入数据,通过从服务器读取数据来验证主从关系是否正常。

 1[root@shell ~]# redis-cli -h localhost -p 6379
 2localhost:6379> auth yourpassword
 3OK
 4localhost:16379> get count
 5"6"
 6localhost:16379> decr count
 7(integer) 5
 8localhost:16379> exit
 9[root@ ~]# redis-cli -h localhost -p 16379
10localhost:6379> auth yourpassword
11OK
12localhost:6379> get count
13"5"
14localhost:6379> incr count
15(error) READONLY You can\'t write against a read only slave.

可以看到,主服务器将count值自减1之后,从服务器获取的count值也是自减后的值;同时,如果在从服务器上对count进行自增操作,会得到一条

(error) READONLY You can't write against a read only slave.

的错误消息,说明

  • 端口16379的redis服务是slave;

  • 我们配置的从服务器只读生效了

以上,即可完成配置经典的一主多备的redis服务部署。

6.2 配置redis-sentinel #

slave的配置一样,复制配置文件,少许改动即可,以下列出了sentinel的异于slave的配置项5

 1# 哨兵sentinel监控的redis主节点的
 2## quorum:当这些quorum个数sentinel哨兵认为master主节点失联 那么这时 客观上认为主节点失联了  
 3# sentinel monitor <master-name> <ip> <port> <quorum>  
 4sentinel monitor master 127.0.0.1 6379 2
 5
 6# 当在Redis实例中开启了requirepass <foobared>,所有连接Redis实例的客户端都要提供密码
 7# sentinel auth-pass <master-name> <password>  
 8sentinel auth-pass master yourpassword  
 9
10# 指定主节点应答哨兵sentinel的最大时间间隔,超过这个时间,哨兵主观上认为主节点下线,默认30秒  
11# sentinel down-after-milliseconds <master-name> <milliseconds>
12sentinel down-after-milliseconds master 30000  
13
14# 指定了在发生failover主备切换时,最多可以有多少个slave同时对新的master进行同步。
15# 这个数字越小,完成failover所需的时间就越长;反之,但是如果这个数字越大,就意味着越多的
16# slave因为replication而不可用。可以通过将这个值设为1,来保证每次只有一个slave,处于不能
17# 处理命令请求的状态。
18# sentinel parallel-syncs <master-name> <numslaves>
19sentinel parallel-syncs master 1  
20
21# 故障转移的超时时间failover-timeout,默认三分钟,可以用在以下这些方面:
22## 1. 同一个sentinel对同一个master两次failover之间的间隔时间。  
23## 2. 当一个slave从一个错误的master那里同步数据时开始,直到slave被纠正为从正确的master
24#   那里同步数据时结束。  
25## 3. 当想要取消一个正在进行的failover时所需要的时间。
26## 4.当进行failover时,配置所有slaves指向新的master所需的最大时间。不过,即使过了这个超时,
27#   slaves依然会被正确配置为指向master,但是就不按parallel-syncs所配置的规则来同步数据了
28# sentinel failover-timeout <master-name> <milliseconds>  
29sentinel failover-timeout master 180000
 1# sentinel配置文件
 2mv redis-sentinel/redis.conf redis-sentinel/sentinel-6380.conf
 3vim redis-sentinel/sentinel-6380.conf
 4<<<
 5protected-mode no
 6bind 0.0.0.0
 7port 16380
 8daemonize yes
 9sentinel monitor master 127.0.0.1 6379 2
10sentinel down-after-milliseconds master 5000
11sentinel failover-timeout master 180000
12sentinel parallel-syncs master 1
13sentinel auth-pass master yourpassword
14logfile /var/log/redis/sentinel-16380.log

同理,可以再配置其他2个sentinel服务。

6.2.1 sentinel启动日志 #

启动sentinel6

1redis-sentinel /usr/local/redis-sentinel/sentinel-6380.conf
2# 或者
3redis-server /usr/local/redis-sentinel/sentinel-6380.conf --sentinel

以下是配置成功的sentinel启动日志其一

8550:X 05 Aug 14:29:38.696 # oO0OoO0OoO0Oo Redis is starting oO0OoO0OoO0Oo
8550:X 05 Aug 14:29:38.696 # Redis version=4.0.11, bits=64, commit=00000000,
 modified=0, pid=8550, just started
8550:X 05 Aug 14:29:38.696 # Configuration loaded
                _._                                                  
           _.-``__ ''-._                                             
      _.-``    `.  `_.  ''-._           Redis 4.0.11 (00000000/0) 64 bit
  .-`` .-```.  ```\/    _.,_ ''-._                                   
 (    '      ,       .-`  | `,    )     Running in sentinel mode
 |`-._`-...-` __...-.``-._|'` _.-'|     Port: 6380
 |    `-._   `._    /     _.-'    |     PID: 8551
  `-._    `-._  `-./  _.-'    _.-'                                   
 |`-._`-._    `-.__.-'    _.-'_.-'|                                  
 |    `-._`-._        _.-'_.-'    |           http://redis.io        
  `-._    `-._`-.__.-'_.-'    _.-'                                   
 |`-._`-._    `-.__.-'    _.-'_.-'|                                  
 |    `-._`-._        _.-'_.-'    |                                  
  `-._    `-._`-.__.-'_.-'    _.-'                                   
      `-._    `-.__.-'    _.-'                                       
          `-._        _.-'                                           
              `-.__.-'                                               

8551:X 05 Aug 14:29:38.702 # Sentinel ID is
c3776869c9bc3998e45158d3933d8e7b7c60ea84
8551:X 05 Aug 14:29:38.702 # +monitor master master 127.0.0.1 6379 quorum 2

通过观查启动日志,我们可以看到:

  • 此实例的启动模式为sentinel mode,端口为6380
  • sentinel已经成功监控master端口6379了

全部哨兵系统搭建起来并运行之后,再去查看sentinel的配置文件,会有如下自动配置的内容:

# Generated by CONFIG REWRITE
sentinel auth-pass master yourpassword
sentinel config-epoch master 1
sentinel leader-epoch master 1
sentinel known-slave master 127.0.0.1 16379
sentinel known-slave master 127.0.0.1 26379
sentinel known-sentinel master 127.0.0.1 26380 e615ce
sentinel known-sentinel master 127.0.0.1 6380 dcc9d7
sentinel current-epoch 1

上面的配置列出了

  • 主服务器的密码
  • 以及当前世代(每发生一次主备切换称为一次世代,epoch加1)
  • 当前所有从服务器的地址和端口信息
  • 当前所以其他已知哨兵的端口和id信息

6.2.2 使用redis-cli查看系统信息 #

sentinel哨兵系统搭建起来之后,可以任一通过客户端查看系统内的实例信息。

 1127.0.0.1:16380> sentinel master master
 2 1) "name"
 3 2) "master"
 4 3) "ip"
 5 4) "127.0.0.1"
 6 5) "port"
 7 6) "6379"
 8 7) "runid"
 9 8) "dfefe0ba7435f7c2c193698f17b7e46f7450d5ce"
10 9) "flags"
1110) "master"
12...
13127.0.0.1:16380> sentinel slaves master
141)  1) "name"
15    2) "127.0.0.1:16379"
16    3) "ip"
17    4) "127.0.0.1"
18    5) "port"
19    6) "16379"
20    7) "runid"
21    8) "fdda882f98724c46359a4deb9390b6ae4de13320"
22    9) "flags"
23   10) "slave"
24 ...
252)  1) "name"
26    2) "127.0.0.1:26379"
27    3) "ip"
28    4) "127.0.0.1"
29    5) "port"
30    6) "26379"
31    7) "runid"
32    8) "4a2c286c0c99c3a1202eec142599193a85671f6c"
33    9) "flags"
34   10) "slave"
35...

6.2.3 模拟主备切换 #

哨兵的存在就是为了解决master-slave系统中由于master宕机引起的系统瘫痪问题。

在哨兵系统中,一旦哨兵发现当前master宕机,哨兵会在余下的slaves中选举一个「继任」为新一代的master,从而保证系统的高可用。

现在我们通过主动关闭当前master服务的方式来模拟master宕机,看看哨兵会做什么:

 1# 关闭master服务
 2redis-cli -p 6379
 3127.0.0.1:6379> auth yourpassword
 4OK
 5127.0.0.1:6379> shutdown save
 6127.0.0.1:6379> exit
 7# 查看sentinel日志
 8less /var/log/redis/sentinel-6380.log
 9<<<
1029649:X 23 Aug 17:14:02.326 # +sdown master master 127.0.0.1 6379
1129649:X 23 Aug 17:14:02.389 # +new-epoch 1
1229649:X 23 Aug 17:14:02.391 # +vote-for-leader 503d5371452f8e110df0f12c236da3e51b55b03a 1
1329649:X 23 Aug 17:14:03.444 # +odown master master 127.0.0.1 6379 #quorum 3/2
1429649:X 23 Aug 17:14:03.444 # Next failover delay: I will not start a failover before Fri Aug 23 17:14:38 2019
1529649:X 23 Aug 17:14:03.488 # +config-update-from sentinel 503d5371452f8e110df0f12c236da3e51b55b03a 172.16.16.203 16380 @ master 127.0.0.1 6379
1629649:X 23 Aug 17:14:03.488 # +switch-master master 127.0.0.1 6379 127.0.0.1 26379
1729649:X 23 Aug 17:14:03.488 * +slave slave 127.0.0.1:16379 127.0.0.1 16379 @ master 127.0.0.1 26379
1829649:X 23 Aug 17:14:03.488 * +slave slave 127.0.0.1:6379 127.0.0.1 6379 @ master 127.0.0.1 26379
1929649:X 23 Aug 17:14:08.536 # +sdown slave 127.0.0.1:6379 127.0.0.1 6379 @ master 127.0.0.1 26379
2029649:X 23 Aug 17:15:42.868 # -sdown slave 127.0.0.1:6379 127.0.0.1 6379 @ master 127.0.0.1 26379
2129649:X 23 Aug 17:15:52.888 * +convert-to-slave slave 127.0.0.1:6379 127.0.0.1 6379 @ master 127.0.0.1 26379

通过24行sentinel日志,我们可以看到的信息有哪些呢?

  • master主观下线7
  • 系统进入新世代;
  • 3/2投票认为master下线,master客观下线8
  • 切换主服务器:从6379切换为26379;
  • 同时6379和16379切换为26379的从节点

此时,我们如果查看redis的配置文件,会发现原6379的主服务器配置文件多了一行

slaveof 127.0.0.1 26379

同时,1637926379端口的服务的slaveof配置项也作了相应修改。

7 结束语 #

至此,基于sentinel的redis高可用集群就搭建完成了。虽然篇幅较长,实际上搭建一个这样的系统的逻辑是比较简单的。

主要易于混淆的是6不个redis实例的配置,细心点就好了。

想用好这个高可用系统,你可能还需要了解更多关于sentinel的内容。


  1. 本文是在所有服务均配置完成之后所作的记录,并非同步记录,部分操作可能存在错误 ↩︎

  2. 下文会多次提到实例这个概念,它在本文中指一个运行的Redis数据库服务 ↩︎

  3. 监控master状态,如果宕机,则执行主备切换 ↩︎

  4. 搭建redis单机服务 ↩︎ ↩︎

  5. redis哨兵与高可用 ↩︎

  6. redis-server man page ↩︎

  7. 仅当前哨兵接收不到master的心跳,称为主观下线 ↩︎

  8. 经过投票之后,满足配置个数的哨兵认为master下线,则master被认为客观下线,触发主备切换 ↩︎