前言
Redis 的 主从复制 模式下,一旦 主节点 由于故障不能提供服务,需要手动将 从节点 晋升为 主节点,同时还要通知 客户端 更新 主节点地址,这种故障处理方式从一定程度上是无法接受的。Redis 2.8 以后提供了 Redis Sentinel 哨兵机制 来解决这个问题。
在 Web 服务器中,高可用 是指服务器可以 正常访问 的时间,衡量的标准是在 多长时间 内可以提供正常服务(99.9%、99.99%、99.999% 等等)。在 Redis 层面,高可用 的含义要宽泛一些,除了保证提供 正常服务(如 主从分离、快速容灾技术 等),还需要考虑 数据容量扩展、数据安全 等等。
在 Redis 中,实现 高可用 的技术主要包括 持久化、复制、哨兵 和 集群,下面简单说明它们的作用,以及解决了什么样的问题:
Redis Sentinel 是 Redis 高可用 的实现方案。Sentinel 是一个管理多个 Redis 实例的工具,它可以实现对 Redis 的 监控、通知、自动故障转移。下面先对 Redis Sentinel 的 基本概念 进行简单的介绍。
基本名词说明:
如图所示,Redis 的 主从复制模式 和 Sentinel 高可用架构 的示意图:
Redis 主从复制 可将 主节点 数据同步给 从节点,从节点此时有两个作用:
主从复制 同时存在以下几个问题:
4.1. Redis Sentinel的架构
4.2. Redis Sentinel的主要功能
Sentinel 的主要功能包括 主节点存活检测、主从运行情况检测、自动故障转移 (failover)、主从切换。Redis 的 Sentinel 最小配置是 一主一从。
Redis 的 Sentinel 系统可以用来管理多个 Redis 服务器,该系统可以执行以下四个任务:
Sentinel 会不断的检查 主服务器 和 从服务器 是否正常运行。
当被监控的某个 Redis 服务器出现问题,Sentinel 通过 API 脚本 向 管理员 或者其他的 应用程序 发送通知。
当 主节点 不能正常工作时,Sentinel 会开始一次 自动的 故障转移操作,它会将与 失效主节点 是 主从关系 的其中一个 从节点 升级为新的 主节点,并且将其他的 从节点 指向 新的主节点。
在 Redis Sentinel 模式下,客户端应用 在初始化时连接的是 Sentinel 节点集合,从中获取 主节点 的信息。
4.3. 主观下线和客观下线
默认情况下,每个 Sentinel 节点会以 每秒一次 的频率对 Redis 节点和 其它 的 Sentinel 节点发送 PING 命令,并通过节点的 回复 来判断节点是否在线。
主观下线 适用于所有 主节点 和 从节点。如果在 down-after-milliseconds 毫秒内,Sentinel 没有收到 目标节点 的有效回复,则会判定 该节点 为 主观下线。
客观下线 只适用于 主节点。如果 主节点 出现故障,Sentinel 节点会通过 sentinel is-master-down-by-addr命令,向其它 Sentinel 节点询问对该节点的 状态判断。如果超过 个数的节点判定 主节点 不可达,则该 Sentinel 节点会判断 主节点 为 客观下线。
4.4. Sentinel的通信命令
Sentinel 节点连接一个 Redis 实例的时候,会创建 cmd 和 pub/sub 两个 连接。Sentinel 通过 cmd 连接给 Redis发送命令,通过 pub/sub 连接到 Redis 实例上的其他 Sentinel 实例。
Sentinel 与 Redis 主节点 和 从节点 交互的命令,主要包括:
Sentinel 与 Sentinel 交互的命令,主要包括:
4.5. Redis Sentinel的工作原理
每个 Sentinel 节点都需要 定期执行 以下任务:
注意:一个有效的 PING 回复可以是:+PONG、-LOADING 或者 -MASTERDOWN。如果 服务器 返回除以上三种回复之外的其他回复,又或者在 指定时间 内没有回复 PING 命令, 那么 Sentinel 认为服务器返回的回复 无效(non-valid)。
5.1. Redis Sentinel的部署须知
5.2. Redis Sentinel的配置文件
# 哨兵sentinel实例运行的端口,默认26379 port 26379# 哨兵sentinel的工作目录dir ./# 哨兵sentinel监控的redis主节点的 ## ip:主机ip地址## port:哨兵端口号## master-name:可以自己命名的主节点名字(只能由字母A-z、数字0-9 、这三个字符".-_"组成。)## quorum:当这些quorum个数sentinel哨兵认为master主节点失联 那么这时 客观上认为主节点失联了 # sentinel monitor sentinel monitor mymaster 127.0.0.1 6379 2# 当在Redis实例中开启了requirepass ,所有连接Redis实例的客户端都要提供密码。# sentinel auth-pass sentinel auth-pass mymaster 123456 # 指定主节点应答哨兵sentinel的最大时间间隔,超过这个时间,哨兵主观上认为主节点下线,默认30秒 # sentinel down-after-milliseconds sentinel down-after-milliseconds mymaster 30000 # 指定了在发生failover主备切换时,最多可以有多少个slave同时对新的master进行同步。这个数字越小,完成failover所需的时间就越长;反之,但是如果这个数字越大,就意味着越多的slave因为replication而不可用。可以通过将这个值设为1,来保证每次只有一个slave,处于不能处理命令请求的状态。# sentinel parallel-syncs sentinel parallel-syncs mymaster 1 # 故障转移的超时时间failover-timeout,默认三分钟,可以用在以下这些方面:## 1. 同一个sentinel对同一个master两次failover之间的间隔时间。 ## 2. 当一个slave从一个错误的master那里同步数据时开始,直到slave被纠正为从正确的master那里同步数据时结束。 ## 3. 当想要取消一个正在进行的failover时所需要的时间。## 4.当进行failover时,配置所有slaves指向新的master所需的最大时间。不过,即使过了这个超时,slaves依然会被正确配置为指向master,但是就不按parallel-syncs所配置的规则来同步数据了# sentinel failover-timeout sentinel failover-timeout mymaster 180000# 当sentinel有任何警告级别的事件发生时(比如说redis实例的主观失效和客观失效等等),将会去调用这个脚本。一个脚本的最大执行时间为60s,如果超过这个时间,脚本将会被一个SIGKILL信号终止,之后重新执行。# 对于脚本的运行结果有以下规则: ## 1. 若脚本执行后返回1,那么该脚本稍后将会被再次执行,重复次数目前默认为10。## 2. 若脚本执行后返回2,或者比2更高的一个返回值,脚本将不会重复执行。 ## 3. 如果脚本在执行过程中由于收到系统中断信号被终止了,则同返回值为1时的行为相同。# sentinel notification-script sentinel notification-script mymaster /var/redis/notify.sh# 这个脚本应该是通用的,能被多次调用,不是针对性的。# sentinel client-reconfig-script sentinel client-reconfig-script mymaster /var/redis/reconfig.sh
5.3. Redis Sentinel的节点规划
5.4. Redis Sentinel的配置搭建
5.4.1. Redis-Server的配置管理
分别拷贝三份 redis.conf 文件到 /usr/local/redis-sentinel 目录下面。三个配置文件分别对应 master、slave1 和 slave2 三个 Redis 节点的 启动配置。
$ sudo cp /usr/local/redis-4.0.11/redis.conf /usr/local/redis-sentinel/redis-16379.conf$ sudo cp /usr/local/redis-4.0.11/redis.conf /usr/local/redis-sentinel/redis-26379.conf$ sudo cp /usr/local/redis-4.0.11/redis.conf /usr/local/redis-sentinel/redis-36379.conf
分别修改三份配置文件如下:
daemonize yespidfile /var/run/redis-16379.pidlogfile /var/log/redis/redis-16379.logport 16379bind 0.0.0.0timeout 300databases 16dbfilename dump-16379.dbdir ./redis-workdirmasterauth 123456requirepass 123456
daemonize yespidfile /var/run/redis-26379.pidlogfile /var/log/redis/redis-26379.logport 26379bind 0.0.0.0timeout 300databases 16dbfilename dump-26379.dbdir ./redis-workdirmasterauth 123456requirepass 123456slaveof 127.0.0.1 16379
daemonize yespidfile /var/run/redis-36379.pidlogfile /var/log/redis/redis-36379.logport 36379bind 0.0.0.0timeout 300databases 16dbfilename dump-36379.dbdir ./redis-workdirmasterauth 123456requirepass 123456slaveof 127.0.0.1 16379
如果要做 自动故障转移,建议所有的 redis.conf 都设置 masterauth。因为 自动故障 只会重写 主从关系,即 slaveof,不会自动写入 masterauth。如果 Redis 原本没有设置密码,则可以忽略。
5.4.2. Redis-Server启动验证
按顺序分别启动 16379,26379 和 36379 三个 Redis 节点,启动命令和启动日志如下:
Redis 的启动命令:
$ sudo redis-server /usr/local/redis-sentinel/redis-16379.conf$ sudo redis-server /usr/local/redis-sentinel/redis-26379.conf$ sudo redis-server /usr/local/redis-sentinel/redis-36379.conf
查看 Redis 的启动进程:
$ ps -ef | grep redis-server 0 7127 1 0 2:16下午 ?? 0:01.84 redis-server 0.0.0.0:16379 0 7133 1 0 2:16下午 ?? 0:01.73 redis-server 0.0.0.0:26379 0 7137 1 0 2:16下午 ?? 0:01.70 redis-server 0.0.0.0:36379
查看 Redis 的启动日志:
$ cat /var/log/redis/redis-16379.log 7126:C 22 Aug 14:16:38.907 # oO0OoO0OoO0Oo Redis is starting oO0OoO0OoO0Oo7126:C 22 Aug 14:16:38.908 # Redis version=4.0.11, bits=64, commit=00000000, modified=0, pid=7126, just started7126:C 22 Aug 14:16:38.908 # Configuration loaded7127:M 22 Aug 14:16:38.910 * Increased maximum number of open files to 10032 (it was originally set to 256).7127:M 22 Aug 14:16:38.912 * Running mode=standalone, port=16379.7127:M 22 Aug 14:16:38.913 # Server initialized7127:M 22 Aug 14:16:38.913 * Ready to accept connections7127:M 22 Aug 14:16:48.416 * Slave 127.0.0.1:26379 asks for synchronization7127:M 22 Aug 14:16:48.416 * Full resync requested by slave 127.0.0.1:263797127:M 22 Aug 14:16:48.416 * Starting BGSAVE for SYNC with target: disk7127:M 22 Aug 14:16:48.416 * Background saving started by pid 71347134:C 22 Aug 14:16:48.433 * DB saved on disk7127:M 22 Aug 14:16:48.487 * Background saving terminated with success7127:M 22 Aug 14:16:48.494 * Synchronization with slave 127.0.0.1:26379 succeeded7127:M 22 Aug 14:16:51.848 * Slave 127.0.0.1:36379 asks for synchronization7127:M 22 Aug 14:16:51.849 * Full resync requested by slave 127.0.0.1:363797127:M 22 Aug 14:16:51.849 * Starting BGSAVE for SYNC with target: disk7127:M 22 Aug 14:16:51.850 * Background saving started by pid 71387138:C 22 Aug 14:16:51.862 * DB saved on disk7127:M 22 Aug 14:16:51.919 * Background saving terminated with success7127:M 22 Aug 14:16:51.923 * Synchronization with slave 127.0.0.1:36379 succeeded
以下两行日志日志表明,redis-16379 作为 Redis 的 主节点,redis-26379 和 redis-36379 作为 从节点,从 主节点 同步数据。
7127:M 22 Aug 14:16:48.416 * Slave 127.0.0.1:26379 asks for synchronization7127:M 22 Aug 14:16:51.848 * Slave 127.0.0.1:36379 asks for synchronization
$ cat /var/log/redis/redis-26379.log 7132:C 22 Aug 14:16:48.407 # oO0OoO0OoO0Oo Redis is starting oO0OoO0OoO0Oo7132:C 22 Aug 14:16:48.408 # Redis version=4.0.11, bits=64, commit=00000000, modified=0, pid=7132, just started7132:C 22 Aug 14:16:48.408 # Configuration loaded7133:S 22 Aug 14:16:48.410 * Increased maximum number of open files to 10032 (it was originally set to 256).7133:S 22 Aug 14:16:48.412 * Running mode=standalone, port=26379.7133:S 22 Aug 14:16:48.413 # Server initialized7133:S 22 Aug 14:16:48.413 * Ready to accept connections7133:S 22 Aug 14:16:48.413 * Connecting to MASTER 127.0.0.1:163797133:S 22 Aug 14:16:48.413 * MASTER SLAVE sync started7133:S 22 Aug 14:16:48.414 * Non blocking connect for SYNC fired the event.7133:S 22 Aug 14:16:48.414 * Master replied to PING, replication can continue...7133:S 22 Aug 14:16:48.415 * Partial resynchronization not possible (no cached master)7133:S 22 Aug 14:16:48.417 * Full resync from master: 211d3b4eceaa3af4fe5c77d22adf06e1218e0e7b:07133:S 22 Aug 14:16:48.494 * MASTER SLAVE sync: receiving 176 bytes from master7133:S 22 Aug 14:16:48.495 * MASTER SLAVE sync: Flushing old data7133:S 22 Aug 14:16:48.496 * MASTER SLAVE sync: Loading DB in memory7133:S 22 Aug 14:16:48.498 * MASTER SLAVE sync: Finished with success
$ cat /var/log/redis/redis-36379.log 7136:C 22 Aug 14:16:51.839 # oO0OoO0OoO0Oo Redis is starting oO0OoO0OoO0Oo7136:C 22 Aug 14:16:51.840 # Redis version=4.0.11, bits=64, commit=00000000, modified=0, pid=7136, just started7136:C 22 Aug 14:16:51.841 # Configuration loaded7137:S 22 Aug 14:16:51.843 * Increased maximum number of open files to 10032 (it was originally set to 256).7137:S 22 Aug 14:16:51.845 * Running mode=standalone, port=36379.7137:S 22 Aug 14:16:51.845 # Server initialized7137:S 22 Aug 14:16:51.846 * Ready to accept connections7137:S 22 Aug 14:16:51.846 * Connecting to MASTER 127.0.0.1:163797137:S 22 Aug 14:16:51.847 * MASTER SLAVE sync started7137:S 22 Aug 14:16:51.847 * Non blocking connect for SYNC fired the event.7137:S 22 Aug 14:16:51.847 * Master replied to PING, replication can continue...7137:S 22 Aug 14:16:51.848 * Partial resynchronization not possible (no cached master)7137:S 22 Aug 14:16:51.850 * Full resync from master: 211d3b4eceaa3af4fe5c77d22adf06e1218e0e7b:147137:S 22 Aug 14:16:51.923 * MASTER SLAVE sync: receiving 176 bytes from master7137:S 22 Aug 14:16:51.923 * MASTER SLAVE sync: Flushing old data7137:S 22 Aug 14:16:51.924 * MASTER SLAVE sync: Loading DB in memory7137:S 22 Aug 14:16:51.927 * MASTER SLAVE sync: Finished with success
5.4.3. Sentinel的配置管理
分别拷贝三份 redis-sentinel.conf 文件到 /usr/local/redis-sentinel 目录下面。三个配置文件分别对应 master、slave1 和 slave2 三个 Redis 节点的 哨兵配置。
$ sudo cp /usr/local/redis-4.0.11/sentinel.conf /usr/local/redis-sentinel/sentinel-16380.conf$ sudo cp /usr/local/redis-4.0.11/sentinel.conf /usr/local/redis-sentinel/sentinel-26380.conf$ sudo cp /usr/local/redis-4.0.11/sentinel.conf /usr/local/redis-sentinel/sentinel-36380.conf
protected-mode nobind 0.0.0.0port 16380daemonize yessentinel monitor master 127.0.0.1 16379 2sentinel down-after-milliseconds master 5000sentinel failover-timeout master 180000sentinel parallel-syncs master 1sentinel auth-pass master 123456logfile /var/log/redis/sentinel-16380.log
protected-mode nobind 0.0.0.0port 26380daemonize yessentinel monitor master 127.0.0.1 16379 2sentinel down-after-milliseconds master 5000sentinel failover-timeout master 180000sentinel parallel-syncs master 1sentinel auth-pass master 123456logfile /var/log/redis/sentinel-26380.log
protected-mode nobind 0.0.0.0port 36380daemonize yessentinel monitor master 127.0.0.1 16379 2sentinel down-after-milliseconds master 5000sentinel failover-timeout master 180000sentinel parallel-syncs master 1sentinel auth-pass master 123456logfile /var/log/redis/sentinel-36380.log
5.4.4. Sentinel启动验证
按顺序分别启动 16380,26380 和 36380 三个 Sentinel 节点,启动命令和启动日志如下:
$ sudo redis-sentinel /usr/local/redis-sentinel/sentinel-16380.conf$ sudo redis-sentinel /usr/local/redis-sentinel/sentinel-26380.conf$ sudo redis-sentinel /usr/local/redis-sentinel/sentinel-36380.conf
查看 Sentinel 的启动进程:
$ ps -ef | grep redis-sentinel 0 7954 1 0 3:30下午 ?? 0:00.05 redis-sentinel 0.0.0.0:16380 [sentinel] 0 7957 1 0 3:30下午 ?? 0:00.05 redis-sentinel 0.0.0.0:26380 [sentinel] 0 7960 1 0 3:30下午 ?? 0:00.04 redis-sentinel 0.0.0.0:36380 [sentinel]
查看 Sentinel 的启动日志:
$ cat /var/log/redis/sentinel-16380.log 7953:X 22 Aug 15:30:27.245 # oO0OoO0OoO0Oo Redis is starting oO0OoO0OoO0Oo7953:X 22 Aug 15:30:27.245 # Redis version=4.0.11, bits=64, commit=00000000, modified=0, pid=7953, just started7953:X 22 Aug 15:30:27.245 # Configuration loaded7954:X 22 Aug 15:30:27.247 * Increased maximum number of open files to 10032 (it was originally set to 256).7954:X 22 Aug 15:30:27.249 * Running mode=sentinel, port=16380.7954:X 22 Aug 15:30:27.250 # Sentinel ID is 69d05b86a82102a8919231fd3c2d1f21ce86e0007954:X 22 Aug 15:30:27.250 # +monitor master master 127.0.0.1 16379 quorum 27954:X 22 Aug 15:30:32.286 # +sdown sentinel fd166dc66425dc1d9e2670e1f17cb94fe05f5fc7 127.0.0.1 36380 @ master 127.0.0.1 163797954:X 22 Aug 15:30:34.588 # -sdown sentinel fd166dc66425dc1d9e2670e1f17cb94fe05f5fc7 127.0.0.1 36380 @ master 127.0.0.1 16379
sentinel-16380 节点的 Sentinel ID 为 69d05b86a82102a8919231fd3c2d1f21ce86e000,并通过 Sentinel ID 把自身加入 sentinel 集群中。
$ cat /var/log/redis/sentinel-26380.log 7956:X 22 Aug 15:30:30.900 # oO0OoO0OoO0Oo Redis is starting oO0OoO0OoO0Oo7956:X 22 Aug 15:30:30.901 # Redis version=4.0.11, bits=64, commit=00000000, modified=0, pid=7956, just started7956:X 22 Aug 15:30:30.901 # Configuration loaded7957:X 22 Aug 15:30:30.904 * Increased maximum number of open files to 10032 (it was originally set to 256).7957:X 22 Aug 15:30:30.905 * Running mode=sentinel, port=26380.7957:X 22 Aug 15:30:30.906 # Sentinel ID is 21e30244cda6a3d3f55200bcd904d0877574e5067957:X 22 Aug 15:30:30.906 # +monitor master master 127.0.0.1 16379 quorum 27957:X 22 Aug 15:30:30.907 * +slave slave 127.0.0.1:26379 127.0.0.1 26379 @ master 127.0.0.1 163797957:X 22 Aug 15:30:30.911 * +slave slave 127.0.0.1:36379 127.0.0.1 36379 @ master 127.0.0.1 163797957:X 22 Aug 15:30:36.311 * +sentinel sentinel fd166dc66425dc1d9e2670e1f17cb94fe05f5fc7 127.0.0.1 36380 @ master 127.0.0.1 16379
sentinel-26380 节点的 Sentinel ID 为 21e30244cda6a3d3f55200bcd904d0877574e506,并通过 Sentinel ID 把自身加入 sentinel 集群中。此时 sentinel 集群中已有 sentinel-16380 和 sentinel-26380 两个节点。
$ cat /var/log/redis/sentinel-36380.log 7959:X 22 Aug 15:30:34.273 # oO0OoO0OoO0Oo Redis is starting oO0OoO0OoO0Oo7959:X 22 Aug 15:30:34.274 # Redis version=4.0.11, bits=64, commit=00000000, modified=0, pid=7959, just started7959:X 22 Aug 15:30:34.274 # Configuration loaded7960:X 22 Aug 15:30:34.276 * Increased maximum number of open files to 10032 (it was originally set to 256).7960:X 22 Aug 15:30:34.277 * Running mode=sentinel, port=36380.7960:X 22 Aug 15:30:34.278 # Sentinel ID is fd166dc66425dc1d9e2670e1f17cb94fe05f5fc77960:X 22 Aug 15:30:34.278 # +monitor master master 127.0.0.1 16379 quorum 27960:X 22 Aug 15:30:34.279 * +slave slave 127.0.0.1:26379 127.0.0.1 26379 @ master 127.0.0.1 163797960:X 22 Aug 15:30:34.283 * +slave slave 127.0.0.1:36379 127.0.0.1 36379 @ master 127.0.0.1 163797960:X 22 Aug 15:30:34.993 * +sentinel sentinel 21e30244cda6a3d3f55200bcd904d0877574e506 127.0.0.1 26380 @ master 127.0.0.1 16379
sentinel-36380 节点的 Sentinel ID 为 fd166dc66425dc1d9e2670e1f17cb94fe05f5fc7,并通过 Sentinel ID 把自身加入 sentinel 集群中。此时 sentinel 集群中已有 sentinel-16380,sentinel-26380 和 sentinel-36380 三个节点。
5.4.5. Sentinel配置刷新
sentinel-16380.conf 文件新生成如下的配置项:
# Generated by CONFIG REWRITEdir "/usr/local/redis-sentinel"sentinel config-epoch master 0sentinel leader-epoch master 0sentinel known-slave master 127.0.0.1 36379sentinel known-slave master 127.0.0.1 26379sentinel known-sentinel master 127.0.0.1 26380 21e30244cda6a3d3f55200bcd904d0877574e506sentinel known-sentinel master 127.0.0.1 36380 fd166dc66425dc1d9e2670e1f17cb94fe05f5fc7sentinel current-epoch 0
可以注意到,sentinel-16380.conf 刷新写入了 Redis 主节点关联的所有 从节点 redis-26379 和 redis-36379,同时写入了其余两个 Sentinel 节点 sentinel-26380 和 sentinel-36380 的 IP 地址,端口号 和 Sentinel ID。
# Generated by CONFIG REWRITEdir "/usr/local/redis-sentinel"sentinel config-epoch master 0sentinel leader-epoch master 0sentinel known-slave master 127.0.0.1 26379sentinel known-slave master 127.0.0.1 36379sentinel known-sentinel master 127.0.0.1 36380 fd166dc66425dc1d9e2670e1f17cb94fe05f5fc7sentinel known-sentinel master 127.0.0.1 16380 69d05b86a82102a8919231fd3c2d1f21ce86e000sentinel current-epoch 0
可以注意到,sentinel-26380.conf 刷新写入了 Redis 主节点关联的所有 从节点 redis-26379 和 redis-36379,同时写入了其余两个 Sentinel 节点 sentinel-36380 和 sentinel-16380 的 IP 地址,端口号 和 Sentinel ID。
# Generated by CONFIG REWRITEdir "/usr/local/redis-sentinel"sentinel config-epoch master 0sentinel leader-epoch master 0sentinel known-slave master 127.0.0.1 36379sentinel known-slave master 127.0.0.1 26379sentinel known-sentinel master 127.0.0.1 16380 69d05b86a82102a8919231fd3c2d1f21ce86e000sentinel known-sentinel master 127.0.0.1 26380 21e30244cda6a3d3f55200bcd904d0877574e506sentinel current-epoch 0
可以注意到,sentinel-36380.conf 刷新写入了 Redis 主节点关联的所有 从节点 redis-26379 和 redis-36379,同时写入了其余两个 Sentinel 节点 sentinel-16380 和 sentinel-26380 的 IP 地址,端口号 和 Sentinel ID。
5.5. Sentinel时客户端命令
> PING sentinel
> SENTINEL masters
> SENTINEL master
> SENTINEL slaves
返回指定 主节点 的 IP 地址和 端口。如果正在进行 failover 或者 failover 已经完成,将会显示被提升为 主节点 的 从节点 的 IP 地址和 端口。
> SENTINEL get-master-addr-by-name
> SENTINEL reset
>SENTINEL failover
6.1. Redis CLI客户端跟踪
上面的日志显示,redis-16379 节点为 主节点,它的进程 ID 为 7127。为了模拟 Redis 主节点故障,强制杀掉这个进程。
$ kill -9 7127
使用 redis-cli 客户端命令进入 sentinel-16380 节点,查看 Redis 节点 的状态信息。
$ redis-cli -p 16380
127.0.0.1:16380> SENTINEL master master 1) "name" 2) "master" 3) "ip" 4) "127.0.0.1" 5) "port" 6) "26379" 7) "runid" 8) "b8ca3b468a95d1be5efe1f50c50636cafe48c59f" 9) "flags"10) "master"11) "link-pending-commands"12) "0"13) "link-refcount"14) "1"15) "last-ping-sent"16) "0"17) "last-ok-ping-reply"18) "588"19) "last-ping-reply"20) "588"21) "down-after-milliseconds"22) "5000"23) "info-refresh"24) "9913"25) "role-reported"26) "master"27) "role-reported-time"28) "663171"29) "config-epoch"30) "1"31) "num-slaves"32) "2"33) "num-other-sentinels"34) "2"35) "quorum"36) "2"37) "failover-timeout"38) "180000"39) "parallel-syncs"40) "1"
6.2. Redis Sentinel日志跟踪
查看任意 Sentinel 节点的日志如下:
7954:X 22 Aug 18:40:22.504 # +tilt #tilt mode entered7954:X 22 Aug 18:40:32.197 # +tilt #tilt mode entered7954:X 22 Aug 18:41:02.241 # -tilt #tilt mode exited7954:X 22 Aug 18:48:24.550 # +sdown master master 127.0.0.1 163797954:X 22 Aug 18:48:24.647 # +new-epoch 17954:X 22 Aug 18:48:24.651 # +vote-for-leader fd166dc66425dc1d9e2670e1f17cb94fe05f5fc7 17954:X 22 Aug 18:48:25.678 # +odown master master 127.0.0.1 16379 #quorum 3/27954:X 22 Aug 18:48:25.678 # Next failover delay: I will not start a failover before Wed Aug 22 18:54:24 20187954:X 22 Aug 18:48:25.709 # +config-update-from sentinel fd166dc66425dc1d9e2670e1f17cb94fe05f5fc7 127.0.0.1 36380 @ master 127.0.0.1 163797954:X 22 Aug 18:48:25.710 # +switch-master master 127.0.0.1 16379 127.0.0.1 263797954:X 22 Aug 18:48:25.710 * +slave slave 127.0.0.1:36379 127.0.0.1 36379 @ master 127.0.0.1 263797954:X 22 Aug 18:48:25.711 * +slave slave 127.0.0.1:16379 127.0.0.1 16379 @ master 127.0.0.1 263797954:X 22 Aug 18:48:30.738 # +sdown slave 127.0.0.1:16379 127.0.0.1 16379 @ master 127.0.0.1 263797954:X 22 Aug 19:38:23.479 # -sdown slave 127.0.0.1:16379 127.0.0.1 16379 @ master 127.0.0.1 26379
+sdown master master 127.0.0.1 16379
+new-epoch 1
+vote-for-leader fd166dc66425dc1d9e2670e1f17cb94fe05f5fc7 1
+odown master master 127.0.0.1 16379 #quorum 3/2
+switch-master master 127.0.0.1 16379 127.0.0.1 26379
7954:X 22 Aug 18:48:25.710 * +slave slave 127.0.0.1:36379 127.0.0.1 36379 @ master 127.0.0.1 263797954:X 22 Aug 18:48:25.711 * +slave slave 127.0.0.1:16379 127.0.0.1 16379 @ master 127.0.0.1 26379
6.3. Redis的配置文件
分别查看三个 redis 节点的配置文件,发生 主从切换 时 redis.conf 的配置会自动发生刷新。
daemonize yespidfile "/var/run/redis-16379.pid"logfile "/var/log/redis/redis-16379.log"port 16379bind 0.0.0.0timeout 300databases 16dbfilename "dump-16379.db"dir "/usr/local/redis-sentinel/redis-workdir"masterauth "123456"requirepass "123456"
daemonize yespidfile "/var/run/redis-26379.pid"logfile "/var/log/redis/redis-26379.log"port 26379bind 0.0.0.0timeout 300databases 16dbfilename "dump-26379.db"dir "/usr/local/redis-sentinel/redis-workdir"masterauth "123456"requirepass "123456"
daemonize yespidfile "/var/run/redis-36379.pid"logfile "/var/log/redis/redis-36379.log"port 36379bind 0.0.0.0timeout 300databases 16dbfilename "dump-36379.db"dir "/usr/local/redis-sentinel/redis-workdir"masterauth "123456"requirepass "123456"slaveof 127.0.0.1 26379
分析:redis-26379 节点 slaveof 配置被移除,晋升为 主节点。redis-16379 节点处于 宕机状态。redis-36379 的 slaveof 配置更新为 127.0.0.1 redis-26379,成为 redis-26379 的 从节点。
重启节点 redis-16379。待正常启动后,再次查看它的 redis.conf 文件,配置如下:
daemonize yespidfile "/var/run/redis-16379.pid"logfile "/var/log/redis/redis-16379.log"port 16379bind 0.0.0.0timeout 300databases 16dbfilename "dump-16379.db"dir "/usr/local/redis-sentinel/redis-workdir"masterauth "123456"requirepass "123456"# Generated by CONFIG REWRITEslaveof 127.0.0.1 26379
节点 redis-16379 的配置文件新增一行 slaveof 配置属性,指向 redis-26379,即成为 新的主节点 的 从节点。
本文首先对 Redis 实现高可用的几种模式做出了阐述,指出了 Redis 主从复制 的不足之处,进一步引入了 Redis Sentinel 哨兵模式 的相关概念,深入说明了 Redis Sentinel 的 具体功能,基本原理,高可用搭建 和 自动故障切换 验证等。
当然,Redis Sentinel 仅仅解决了 高可用 的问题,对于 主节点 单点写入和单节点无法扩容等问题,还需要引入 Redis Cluster 集群模式 予以解决。