一:说明
前面我们已经配置了redis的主从配置(链接),这种主从架构有一个问题,当主master出现了故障了,怎么切换到从服务器上呢?
第一种:手动切换, 这种肯定会造成比较长一段时间的用户不能访问redis了,那有没有更好的办法呢?
第二种:redis官方的 redis-sentinel 哨兵高可用,可以自动切换到从服务器,把从服务器提升为主服务器,继续进行服务。
sentinel的作用
Redis的sentinel系统可以管理多个Redis实例,该系统主要有以下三个任务:
1) 监控 : sentinel会不断的检查你的主服务器和从服务器是否正常运行
2) 提醒:当被监控的某个Redis服务器出问题时,sentinel可以通过api向管理员或者其他应用程序发通知
3)自动转移故障:当一个主服务器不能正常工作时,sentinel会开始一次自动故障迁移操作,它会将失效主服务器的其中一个从服务器升级为主服务器,并让失效主服务器的其他从服务器改为复制新的主服务器;
当客户端试图连接失效的主服务器时,集群也会向客户端返回新的主服务器地址,使得集群可以用新主服务器代替失效的服务器。
关于sentinel
sentinel可以在redis编译后的src文档中找到,它是一个命名为redis-sentinel的程序
二:sentinel的配置
配置文件的格式:
sentinel 选项的名字 主Redis实例的名字 选项的值
Redis 源码中包含了一个名为 sentinel.conf 的文件, 这个文件是一个带有详细注释的 Sentinel 配置文件示例。
运行一个 Sentinel 配置示例如下:
port
sentinel monitor mymaster 127.0.0.1
sentinel down-after-milliseconds mymaster
sentinel failover-timeout mymaster
sentinel parallel-syncs mymaster
sentinel notification-script mymaster <script-path>
配置文件解释:
第一行配置指示 Sentinel 去监视一个名为 mymaster 的主redis实例, 这个主实例的 IP 地址为本机地址127.0.0.1 , 端口号为 6379 , 而将这个主服务器判断为失效至少需要 2 个 Sentinel 进程的同意,只要同意 Sentinel 的数量不达标,自动failover就不会执行。
同时,一个Sentinel都需要获得系统中大多数Sentinel进程的支持, 才能发起一次自动故障迁移, 并预留一个给定的配置纪元 (configuration Epoch ,一个配置纪元就是一个新主服务器配置的版本号)。
换句话说, 在只有少数(minority) Sentinel 进程正常运作的情况下, Sentinel 是不能执行自动故障迁移的。
各个选项的功能:
down-after-milliseconds
该选项指定了 Sentinel 认为Redis实例已经失效所需的毫秒数。
当实例超过该时间没有返回PING,或者直接返回错误, 那么 Sentinel 将这个实例标记为主观下线(subjectively down,简称 SDOWN )。
只有一个 Sentinel进程将实例标记为主观下线并不一定会引起实例的自动故障迁移: 只有在足够数量的 Sentinel 都将一个实例标记为主观下线之后,实例才会被标记为客观下线(objectively down, 简称 ODOWN ), 这时自动故障迁移才会执行。
parallel-syncs
该选项指定了在执行故障转移时, 最多可以有多少个从Redis实例在同步新的主实例, 在从Redis实例较多的情况下这个数字越小,同步的时间越长,完成故障转移所需的时间就越长。
尽管复制过程的绝大部分步骤都不会阻塞从实例, 但从redis实例在载入主实例发来的 RDB 文件时, 仍然会造成从实例在一段时间内不能处理命令请求: 如果全部从实例一起对新的主实例进行同步, 那么就可能会造成所有从Redis实例在短时间内全部不可用的情况出现。
所以从实例被设置为允许使用过期数据集(参见对 redis.conf 文件中对 slave-serve-stale-data 选项),可以缓解所有从实例都在同一时间向新的主实例发送同步请求的负担。你可以通过将这个值设为 1 来保证每次只有一个从Redis实例处于不能处理命令请求的同步状态。
failover-timeout
如果在该时间(ms)内未能完成failover操作,则认为该failover失败。
notification-script
指定sentinel检测到该监控的redis实例指向的实例异常时,调用的报警脚本。该配置项可选,但是很常用。
三:主观下线和客观下线
前面说过, Redis 的 Sentinel 中关于下线(down)有两个不同的概念:
主观下线(Subjectively Down, 简称 SDOWN)指的是单个 Sentinel 实例对服务器做出的下线判断。
客观下线(Objectively Down, 简称 ODOWN)指的是多个 Sentinel 实例在对同一个服务器做出 SDOWN 判断, 并且通过 SENTINEL is-master-down-by-addr 命令互相交流之后, 得出的服务器下线判断。 (一个 Sentinel 可以通过向另一个 Sentinel 发送 SENTINEL is-master-down-by-addr 命令来询问对方是否认为给定的服务器已下线。)
如果一个服务器没有在 master-down-after-milliseconds 选项所指定的时间内, 对向它发送 PING 命令的 Sentinel 返回一个有效回复(valid reply), 那么 Sentinel 就会将这个服务器标记为主观下线。
服务器对 PING 命令的有效回复可以是以下三种回复的其中一种:
返回 +PONG 。
返回 -LOADING 错误。
返回 -MASTERDOWN 错误。
如果服务器返回除以上三种回复之外的其他回复, 又或者在指定时间内没有回复 PING 命令, 那么 Sentinel 认为服务器返回的回复无效(non-valid)
注意, 一个服务器必须在 master-down-after-milliseconds 毫秒内, 一直返回无效回复才会被 Sentinel 标记为主观下线。
举个例子, 如果 master-down-after-milliseconds 选项的值为 30000 毫秒(30 秒), 那么只要服务器能在每 29 秒之内返回至少一次有效回复, 这个服务器就仍然会被认为是处于正常状态的。
四:每个 Sentinel 都需要定期执行的任务
- 每个 Sentinel 以每秒钟一次的频率向它所知的主服务器、从服务器以及其他 Sentinel 实例发送一个 PING 命令。
- 如果一个实例(instance)距离最后一次有效回复 PING 命令的时间超过 down-after-milliseconds 选项所指定的值, 那么这个实例会被 Sentinel 标记为主观下线。 一个有效回复可以是: +PONG 、 -LOADING 或者 -MASTERDOWN 。
- 如果一个主服务器被标记为主观下线, 那么正在监视这个主服务器的所有 Sentinel 要以每秒一次的频率确认主服务器的确进入了主观下线状态。
- 如果一个主服务器被标记为主观下线, 并且有足够数量的 Sentinel (至少要达到配置文件指定的数量)在指定的时间范围内同意这一判断, 那么这个主服务器被标记为客观下线。
- 在一般情况下, 每个 Sentinel 会以每 10 秒一次的频率向它已知的所有主服务器和从服务器发送 INFO 命令。 当一个主服务器被 Sentinel 标记为客观下线时, Sentinel 向下线主服务器的所有从服务器发送 INFO 命令的频率会从 10 秒一次改为每秒一次。
- 当没有足够数量的 Sentinel 同意主服务器已经下线, 主服务器的客观下线状态就会被移除。 当主服务器重新向 Sentinel 的 PING命令返回有效回复时, 主服务器的主管下线状态就会被移除。
五:自动发现 Sentinel 和从服务器
一个 Sentinel 可以与其他多个 Sentinel 进行连接, 各个 Sentinel 之间可以互相检查对方的可用性, 并进行信息交换。
你无须为运行的每个 Sentinel 分别设置其他 Sentinel 的地址, 因为 Sentinel 可以通过发布与订阅功能来自动发现正在监视相同主服务器的其他 Sentinel , 这一功能是通过向频道 __sentinel__:hello 发送信息来实现的。
与此类似, 你也不必手动列出主服务器属下的所有从服务器, 因为 Sentinel 可以通过询问主服务器来获得所有从服务器的信息。
- 每个 Sentinel 会以每两秒一次的频率, 通过发布与订阅功能, 向被它监视的所有主服务器和从服务器的 __sentinel__:hello 频道发送一条信息, 信息中包含了 Sentinel 的 IP 地址、端口号和运行 ID (runid)
- 每个 Sentinel 都订阅了被它监视的所有主服务器和从服务器的 __sentinel__:hello 频道, 查找之前未出现过的 sentinel (looking for unknown sentinels)。 当一个 Sentinel 发现一个新的 Sentinel 时, 它会将新的 Sentinel 添加到一个列表中, 这个列表保存了 Sentinel 已知的, 监视同一个主服务器的所有其他 Sentinel
- Sentinel 发送的信息中还包括完整的主服务器当前配置(configuration)。 如果一个 Sentinel 包含的主服务器配置比另一个 Sentinel 发送的配置要旧, 那么这个 Sentinel 会立即升级到新配置上。
- 在将一个新 Sentinel 添加到监视主服务器的列表上面之前, Sentinel 会先检查列表中是否已经包含了和要添加的 Sentinel 拥有相同运行 ID 或者相同地址(包括 IP 地址和端口号)的 Sentinel , 如果是的话, Sentinel 会先移除列表中已有的那些拥有相同运行 ID 或者相同地址的 Sentinel , 然后再添加新 Sentinel
六:Sentinel API
在默认情况下, Sentinel 使用 TCP 端口 26379 (普通 Redis 服务器使用的是 6379 )。
Sentinel 接受 Redis 协议格式的命令请求, 所以你可以使用 redis-cli 或者任何其他 Redis 客户端来与 Sentinel 进行通讯。
有两种方式可以和 Sentinel 进行通讯:
- 第一种方法是通过直接发送命令来查询被监视 Redis 服务器的当前状态, 以及 Sentinel 所知道的关于其他 Sentinel 的信息, 诸如此类。
- 另一种方法是使用发布与订阅功能, 通过接收 Sentinel 发送的通知: 当执行故障转移操作, 或者某个被监视的服务器被判断为主观下线或者客观下线时, Sentinel 就会发送相应的信息
Sentinel 命令
以下列出的是 Sentinel 接受的命令:
- PING :返回 PONG 。
- SENTINEL masters :列出所有被监视的主服务器,以及这些主服务器的当前状态。
- SENTINEL slaves <master name> :列出给定主服务器的所有从服务器,以及这些从服务器的当前状态。
- SENTINEL get-master-addr-by-name <master name> : 返回给定名字的主服务器的 IP 地址和端口号。 如果这个主服务器正在执行故障转移操作, 或者针对这个主服务器的故障转移操作已经完成, 那么这个命令返回新的主服务器的 IP 地址和端口号。
- SENTINEL reset <pattern> : 重置所有名字和给定模式 pattern 相匹配的主服务器。 pattern 参数是一个 Glob 风格的模式。 重置操作清除主服务器目前的所有状态, 包括正在执行中的故障转移, 并移除目前已经发现和关联的, 主服务器的所有从服务器和 Sentinel 。
- SENTINEL failover <master name> : 当主服务器失效时, 在不询问其他 Sentinel 意见的情况下, 强制开始一次自动故障迁移 (不过发起故障转移的 Sentinel 会向其他 Sentinel 发送一个新的配置,其他 Sentinel 会根据这个配置进行相应的更新)
七:配置sentinel实例
1:前面文章的主从配置
链接 http://www.cnblogs.com/starlion/p/9071003.html 接着继续配置redis sentinel
a)修改前面的主从配置文件
这3个配置文件在ip为 192.168.0.109 虚拟机上
首先: 把 master slave1 slave2 目录下面的redis.conf配置文件里的 bind 修改为 0.0.0.0
其次:把slave1 slave2目录下的redis.conf配文件里的 slaveof 修改为 slaveof 192.168.0.109 1000
然后重启3个redis实例
b) 配置sentinel文件
我们把sentinel配置在 192.168.0.110 的虚拟机上
打开redis的安装目录,在目录下就有一个sentinel.conf的配置文件,这个就是配置sentinel的魔板文件
我们配置3个sentinel文件,文件名分别为 sentinel1.conf sentinel2.conf sentinel3.conf
# vi /user/local/redis/sentinel1.conf
protected-mode no
logfile "/var/log/sentinel.log"
port
sentinel monitor mymaster 192.168.0.109
sentinel down-after-milliseconds mymaster
sentinel config-epoch mymaster
# vi /user/local/redis/sentinel2.conf
protected-mode no
logfile "/var/log/sentinel.log"
port
sentinel monitor mymaster 192.168.0.109
sentinel down-after-milliseconds mymaster
sentinel config-epoch mymaster
# vi /user/local/redis/sentinel3.conf
protected-mode no
logfile "/var/log/sentinel.log"
port
sentinel monitor mymaster 192.168.0.109
sentinel down-after-milliseconds mymaster
sentinel config-epoch mymaster
c) 启动sentinel
nohup ./bin/redis-sentinel ./sentinel1.conf &
nohup ./bin/redis-sentinel ./sentinel2.conf &
nohup ./bin/redis-sentinel ./sentinel3.conf &
2. 连接sentinel
在默认情况下,Sentinel 使用TCP端口26379(普通 Redis 服务器使用的是 6379)。Sentinel 接受 Redis 协议格式的命令请求, 所以你可以使用 redis-cli 或者任何其他 Redis 客户端来与 Sentinel 进行通讯。
有两种方式可以和 Sentinel 进行通讯:
第一种方法是通过直接发送命令来查询被监视 Redis 服务器的当前状态, 以及进行主动转移等操作。这些命令包括:
a). PING :返回 PONG
[root@localhost]# ./redis-cli -p
127.0.0.1:> ping
PONG
b). SENTINEL masters :列出所有被监视的主Redis服务实例,以及这些主服务实例的当前状态。SENTINEL slaves :列出给定主服务实例的所有从实例,以及这些从实例的当前状态
127.0.0.1:> sentinel masters
) ) "name"
) "mymaster"
) "ip"
) "192.168.0.109"
) "port"
) ""
) "runid"
) "2ee92794d04b4dcb25f684a9aecd356eb346d80d"
) "flags"
) "master"
... ......
) "quorum"
) ""
) "failover-timeout"
) ""
) "parallel-syncs"
) ""
) "notification-script" 127.0.0.1:> sentinel slaves mymaster
) ) "name"
) "192.168.0.109:2000"
) "ip"
) "192.168.0.109"
) "port"
) ""
) "runid"
) "4d590175947961683240d7077a4d34e657f072c0"
... ...
) ""
) "slave-priority"
) ""
) "slave-repl-offset"
) ""
) ) "name"
) "192.168.0.109:3000"
) "ip"
) "192.168.0.109"
) "port"
) ""
) "runid"
... ...
) "master-host"
) "192.168.0.109"
) "master-port"
) ""
) "slave-priority"
) ""
) "slave-repl-offset"
) ""
c). SENTINEL get-master-addr-by-name : 返回给定名字的主实例的 IP 地址和端口号。 如果这个主实例正在执行故障转移操作, 或者针对这个主实例的故障转移操作已经完成, 那么这个命令返回新的主服务器的 IP 地址和端口号。
127.0.0.1:> sentinel get-master-addr-by-name mymaster
) "192.168.0.109"
) ""
d). SENTINEL failover :进行一次主动的failover。即在不询问其他 Sentinel 意见的情况下, 强制开始一次自动故障迁移 。发起故障转移的 Sentinel 会向其他 Sentinel 发送一个新的配置,其他 Sentinel 会根据这个配置进行相应的更新
127.0.0.1:> sentinel failover mymaster
OK
e). SENTINEL reset : 重置所有名字和给定模式 pattern 相匹配的主服务器。 pattern 参数是一个 Glob 风格的模式。 重置操作清除该sentinel的所保存的所有状态信息,并进行一次重新的发现过程。
127.0.0.1:> sentinel reset myredis
(integer)
第二种方法是使用发布与订阅功能, 通过接收 Sentinel 发送的通知: 当执行故障转移操作, 或者某个被监视的实例被判断为主观下线或者客观下线时, Sentinel 就会发送相应的信息。
一个频道能够接收和这个频道的名字相同的事件。 比如说, 名为 +sdown 的频道就可以接收所有实例进入主观下线(SDOWN)状态的事件。
通过执行 PSUBSCRIBE * 命令可以接收所有事件信息。例如:
127.0.0.1:> PSUBSCRIBE *
Reading messages... (press Ctrl-C to quit)
) "psubscribe"
) "*"
) (integer)
被动failover测试
查看当前的主redis ip和端口是多少
[root@localhost]# ./redis-cli -p -h 192.168.0.109
192.168.0.109:> info replication
# Replication
role:slave
master_host:192.168.0.109
master_port:
master ip 192.168.0.109
port 2000
关掉 2000 的这个redis实例,等 down-after-millisenonds后,查看/var/log/sentinel.log 日志,
::25.531 * +switch-master mymaster 192.168.0.109 192.168.0.109
20::25.532 * +slave slave 192.168.0.109: 192.168.0.109 @ mymaster 192.168.0.109
20::25.532 * +slave slave 192.168.0.109: 192.168.0.109 @ mymaster 192.168.0.109
20::39.531 * +sdown slave 192.168.0.109: 192.168.0.109 @ mymaster 192.168.0.109
20::39.535 * +sdown slave 192.168.0.109: 192.168.0.109 @ mymaster 192.168.0.109
20::40.573 * +sdown slave 192.168.0.109: 192.168.0.109 @ mymaster 192.168.0.109
看日志,这时候master 是 3000,登录上 3000 服务器,看看端口3000的redis实例是不是master
[root@localhost]# ./redis-cli -p -h 192.168.0.109
192.168.0.109:> info replication
# Replication
role:master
connected_slaves:
slave0:ip=192.168.0.109,port=,state=online,offset=,lag=
我们启动redis实例,它会自动作为slave连上 3000 这台master redis实例
查看日志: vi /usr/local/redis/slave1/redis.log, 是否连上master,可以看到下面的日志连上了
::01.127 * Connecting to MASTER 192.168.0.109:
::01.128 * MASTER <-> SLAVE sync started
::01.128 * Non blocking connect for SYNC fired the event.
::01.129 * Master replied to PING, replication can continue...
::01.130 * Partial resynchronization not possible (no cached master)
::01.153 * Full resync from master: 4d590175947961683240d7077a4d34e657f072c0:
::01.188 * MASTER <-> SLAVE sync: receiving bytes from master
::01.189 * MASTER <-> SLAVE sync: Flushing old data
::01.189 * MASTER <-> SLAVE sync: Loading DB in memory
::01.190 * MASTER <-> SLAVE sync: Finished with success
连上2000的客户端,看看情况:
[root@localhost]# ./redis-cli -p -h 192.168.0.109
192.168.0.109:> info replication
# Replication
role:slave
master_host:192.168.0.109
master_port:
2000这台实例是一个slave,说明成功连上了
测试成功。最后需要注意的是,sentinel集群自身也需要多数机制,也就是2个sentinel进程时,挂掉一个另一个就不可用了。
参考:
http://debugo.com/redis-sentinel/
https://redis.io/topics/sentinel
http://redisdoc.com/topic/sentinel.html