本文永久地址:http://www.javashuo.com/article/p-yobvqtmc-e.htmlhtml
Redis官方文档 https://redis.io/topics/sentinel#redis-sentinel-documentationgit
Redis Sentinel(Sentinel)用于为Redis提供高可用性,这就意味着使用sentinel能建立一个故障时不须要人工当即参与修复的环境。此外,sentinel还能实现其余的功能,如监控,提醒,为客户端提供配置( monitoring, notifications and acts as a configuration provider for clients.)。github
·监控(Monitoring):sentinel会不间断地检查Redis master和Redis slave是否正常运行redis
·提醒(Notification):当其中一个被监控的Redis实例出现问题,sentinel能经过API或其余程序通知管理员算法
·自动故障转移(Automatic failover):当Redis master故障不能正常工做时,sentinel会故障切换进程,将一个slave提高为master,另外的Redis slave将更新配置使用新的master,此后有新链接时,会链接到新的Redis masterdocker
·配置提供者(Configuration provider):Redis充当客户端服务发现的权威来源:客户端链接到sentinel,以请求当前可靠的Redis master地址,若发生故障转移,sentinels将报告新地址数组
Redis sentinel是一个分布式系统,能够在一个架构中运行多个sentinel进程,优点以下:缓存
· 当多个sentinels肯定master再也不可用,就进行故障检测,这下降了误报的可能性安全
· 当在不一样服务器上运行多个sentinel进程,而后将sentinel作集群,即便其中一个故障,也能够进行热切换,下降对客户端的影响,从而提高了系统健壮性服务器
· Redis客户端可链接任意sentinel来使用Redis集群
Sentinel当前版本被称为sentinel 2,它是使用更强大和更简单的预测算法(在本文档中进行了解释)重写了最初的Sentinel实现。自Redis 2.8版本,Redis sentinel发布了稳定版本。Redis Sentinel版本1与Redis 2.6一块儿发布,但已弃用,不建议使用
Sentinel 程序是redis编译安装完成后src目录下的“redis-sentinel”文件
使用redis-sentinel启动:
redis-sentinel sentinel.conf
使用redis-server以sentinel模式启动:
redis-server sentinel.conf --sentinel
· Sentinel运行默认侦听端口26379
· 运行sentinel必须指定配置文件,由于系统使用此文件来保存当前状态,一遍重启sentinel时从新加载。指定的配置文件有问题或不指定配置文件,sentinel会拒绝启动;
· 至少三个sentinel实例才能提高系统健壮性,由于自动故障转移时,必须有剩余大多数sentinels存活,且sentinels间能互相通讯
· 三个sentinel实例应放在相对独立的虚拟机,甚至物理机,甚至不一样区域
· 因为Redis使用异步复制,sentinel+Redis不能保证故障期间保留已确认的写入,但可配置sentinel容许丢失有限的写入。另外还有一些安全性较低的部署方式
· 使用的客户端要支持sentinel,大多数热门的都支持sentinel,但不是所有
· 没有彻底健壮的HA设置,因此要常常在测试环境中测试
· sentinel在docker、端口映射或网络地址转换的环境中配置要格外当心: 在从新映射端口的状况下,真实端口可能与转发的端口不一样,会破坏Sentinel自动发现其余的sentinel进程和master的slave列表。
Redis安装完成会生成Redis根目录下的sentinel.conf配置文件,最小配置以下:
bind 0.0.0.0 #侦听地址
port 26379 #默认侦听端口
dir /tmp #sentinel工做目录
sentinel monitor mymaster 127.0.0.1 6379 2
sentinel down-after-milliseconds mymaster 60000
sentinel failover-timeout mymaster 180000
sentinel parallel-syncs mymaster 1
sentinel monitor resque 192.168.1.3 6380 4
sentinel down-after-milliseconds resque 10000
sentinel failover-timeout resque 180000
sentinel parallel-syncs resque 5
仅须指定masters去监控,每一个不一样的master都应该有不一样的名称 ,因为slave是自动发现的,因此不必指定,且sentinel会自动更新全部slave的状态,信息等到配置文件,以便在从新启动时保留信息。每次进行故障转移,slave被提高为master时,每当有新sentinel被发现时,配置都会被重写。
上面两组示例配置主要监控两组redis实例,每一个实例由一个master和未知数量的从节点组成,一组实例集合调用“mymaster”,另外一组调用“resque”
Sentinel monitor语法:
sentinel monitor <master-group-name> <ip> <port> <quorum>
· master-group-name:Redis master实例名称
· ip,port:master IP、master PORT
· quorum:将master判断为失效至少须要N个Sentinel赞成,仅用于检测master链接失败。如redis集群中有5个sentinel实例,若这里的票数是2,master挂掉,表示有2个sentinel认为master挂掉才能被认为是真正的挂掉,此时会触发自动故障转移。其中sentinel集群中各个sentinel也能经过gossip协议互相通讯。这意味着在故障期间,若大多数sentinel进程间没法互相通讯,自动故障转移将不会被触发(aka no failover in the minority partition)。
那上述例子第一组Redis实例监控的master叫“mymaster”,链接地址为127.0.0.1:6379,当sentinel集群中有2个实例认为mymaster挂掉时,自动进行故障转移。
上述最小配置中其它选项几乎老是下面形式:
sentinel <option_name> <master_name> <option_value>
用于配置如下参数:
· down-after-milliseconds
若服务器在给定的毫秒数以内, 没有返回Sentinel发送的PING命令的回复,或者返回一个错误, 那么Sentinel将这个服务器标记为主观下线(subjectively down,简称SDOWN)。
不过只有一个Sentinel将服务器标记为主观下线并不必定会引发服务器的自动故障迁移:只有在足够数量的Sentinel都将一个服务器标记为主观下线以后, 服务器才会被标记为客观下线(objectively down,简称ODOWN),这时自动故障迁移才会执行。
将服务器标记为客观下线所需的Sentinel数量由对master的配置决定
· parallel-sync
选项指定了在执行故障转移时,最多能够有多少个slave同时对新的master进行异步复制(并发数量),这个数字越小,完成故障转移所需的时间就越长(数字越小,同时能进行复制的slave越少)。
若slave被设置为容许使用过时数据集或未更新的数据集(参见redis.conf中对slave-serve-stale-data选项的说明),那么架构上可能不但愿全部的slave与新master同一时间进行异步复制,由于尽管slave与master间的复制过程绝大部分步骤不会阻塞slave,但slave在载入master发来的RDB文件时,仍然会形成slave在一小段时间内不能处理命令,若是所有slave一块儿对新master进行异步复制,那么会形成全部slave在短期内所有不可用的状况。
固然可设置该值为1来保证每次只有一个slave与新 master进行异步复制,且不能处理命令。
· failover-timeout
故障转移的超时时间 failover-timeout(默认三分钟)能够用在如下这些方面:
· 同一个sentinel对同一个master两次failover之间的间隔时间。
· 当一个slave从一个错误的master那里异步复制数据开始计算时间,直到slave被纠正为向正确的master那里复制数据时。
· 当想要取消一个正在进行的failover所须要的时间。
· 当进行failover时,配置全部slaves指向新的master所需的最大时间。不过,即便过了这个超时,slaves依然会被正确配置为指向master,可是就不按parallel-syncs所配置的规则来了
当在Redis实例中开启了requirepass foobared 受权密码 这样全部链接Redis实例的客户端都要提供密码
设置哨兵sentinel 链接主从的密码 注意必须为主从设置同样的验证密码
sentinel auth-pass <master-name> <password>
sentinel auth-pass mymaster MySUPER--secret-0123passw0rd
本文档剩余的内容将对Sentinel系统的其余选项进行介绍, 示例配置文件sentinel.conf也对相关的选项进行了完整的注释。
到目前为止,已经了解了sentinel基本信息,接下来将经过一系列示例来说解架构中须要多少sentinel进程,如何放置sentinel进程。首先是一些说明:
· Masters表示为:M一、M二、M3...Mn
· Slaves表示为:R一、R二、R3...Rn(R stands for replica)
· Sentinels表示为:S一、S二、S3...Sn
· Clientis表示为:C一、C二、C3...Cn
· 当一个实例因Sentinel动做而改变角色时,咱们把它放在方括号内,因此[M1]表示因为Sentinel干预而成为master的实例
要注意的是,至少三个sentinel实例才能提高系统健壮性,由于自动故障转移时,必须有剩余大多数sentinels存活,且sentinels间能互相通讯
· 此种架构中,若master M1故障,2个sentinel彻底能够就故障打成一致,而后受权自动进行故障切换,此时仍然正常的R1将被提高为master [M1]
· 但,若M1所在的系统故障宕机,S1也会中止工做,另外一系统中运行的sentinel将没法受权故障转移,所以整个Redis集群将没法使用
要注意,多数sentinel存活是必要的,主要应对不一样的故障转移场景,而后将最新的配置信息发到至其余全部的sentinels。且,在没有任何投票协商的状况下,进行自动故障转移是很是危险的:
上图中,两系统网络链接出现问题,会产生两个彻底同样的master(假设S2未经投票协商自动进行故障切换),外部客户端会无休止的向两边写入同时数据,自此M1与[M1]得到的数据可能会有差别,当网络恢复正常时,Redis实例将没法判断哪份数据是正确的。此为脑裂。所以,至少在三个独立的系统中配置三个sentinel,以此解决脑裂的问题
基于3个独立系统,每一个系统都运行一个redis进程和sentinel进程
若master M1故障,S2和S3会就故障达成一致,发起投票,提高一个slave为新master,且自动切换故障,所以客户端能继续请求Redis集群
Sentinel和redis进程一样也是异步复制,当M1所在系统网络出现问题,断开与R2,R3的链接。假设为主写从读架构,那么在M1上确认了的写入请求将没法复制到slave(或者被提高为master的slave),以下图:
此时,旧的master M1被网络隔离,所以slave R2被提高为master M2,然而与旧masterM1链接的客户端(如C1)将会继续写入旧数据。当链接恢复正常后,且旧master M1将更新配置,成为新master的slave,且丢弃全部数据集,重新master更新数据,如此便丢弃了链接断开期间客户端写入到M1的数据
使用Redis复制功能选项能缓解此问题,该功能容许在master检测到再也不能将写入操做复制到指定数量的slave时中止写入操做。
min-slaves-to-write 1
min-slaves-max-lag 10
最少与1个slave正常通讯且延迟小于10s才能接收客户端写入操做(复制是异步的,所以不能写入实际上意味着slave已断开链接,或者未发送超过指定max-lag秒数的异步确认)。
使用此配置,上例中Redis 旧master M1将在10s后不可用。
但,此配置是一把双刃剑,当两个slave关掉或者挂掉,master将中止接收写入请求,整个架构将变得只读。
有时只有两个服务器可用于运行Redis实例,一主一从。例二中的配置在这个场景中不可用,所以咱们将sentinel放在客户端系统上:
此架构中,sentinel与客户端同样,若大多数客户端均可以访问master,那就没毛病。C一、C二、C3在这里表示通用客户端,如rails应用程序或者一个应用程序服务器。
若M1和S1所在服务器系统挂掉,将开始故障切换,但不一样的网络区域将会致使不一样的行为,如客户端和Redis服务器间的网络断开,则sentinel将没法提高slave为新的master,此时Redismaster和Redis slave都将不可用。
注意:若C3与M1是运行在同一系统 (hardly possible with the network described above, but more likely possible with different layouts, or because of failures at the software layer),有一个相似于例二中所描述的问题,区别在于不会产生脑裂,因为只有一主一从,且配置了min-slaves-to-write和min-slaves-max-lag,此时,master必需要能同时接受write/read请求,不然master与slave断开链接达到必定时间后,master将变的不可写,只可读。
So this is a valid setup but the setup in the Example 2 has advantages such as the HA system of Redis running in the same boxes as Redis itself which may be simpler to manage, and the ability to put a bound on the amount of time amasterinto the minority partition can receive writes.
若客户端服务器不足3个,那如今所描述的配置在例三中就不在适用了,此处咱们要混合配置,以下:
与例三环境相似,但此处在四个系统都运行了sentinel,若master M1系统挂掉,其余三个sentinel将执行故障切换。理论上能够移除C二、S4,且设置quorum为2,然而此时应用层就会没有高可用了
Docker使用端口映射技术:docker容器中运行的程序使用的端口可能会与暴露的端口不一样,这对于在同一服务器中同时使用相同端口运行多个容器颇有用。
NAT技术中也可能存在端口映射,甚至是IP。
从新映射IP或端口会产生两个问题:
· sentinel的自动发现再也不工做,由于sentinel经过hello包通告给其余sentinel本身的侦听信息(端口+IP)。Sentinel是没法识别IP或端口是否被从新映射的,所以错误的通告信息用于sentinel间链接会失败。
· Redis master命令“INFO”输出slave的链接信息,该链接信息用于master用于检测远程链接,端口或地址是slave自身广播过来的,然而这个端口多是错,没法用于master与slave间通讯,就像上面一点那样。
在docker环境下,sentinel使用master“INFO”输出信息自动检测slave,检测到的slave将不可达,且sentinel没法为master进行故障切换,由于从sentinel和master的角度看,没有一个slave是正常的。Sentinel也没法监控这组运行在docker中的master实例,除非配置docker为1:1的端口映射。
对于第一个问题,若场景需求要在网络映射环境下运行Redis实例或者sentinel实例,你可使用如下两个sentinel配置来强制sentinel公布一个IP和端口:
sentinel announce-ip <ip>
sentinel announce-port <port>
请注意,Docker可以在主机联网模式下运行(请查看--net=host选项以获取更多信息)。这应该不会形成任何问题,由于在此设置中不会从新映射端口。
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会将此服务器标记为主观下线(SDOWN)
服务器对PING命令的有效回复能够是三种中的一种:
· 返回+PONG
· 返回-LOADING错误
· 返回-MASTERDOWN错误
除此三种外的回复或者指定时间内没有回复,sentinel都会标记该服务器回复无效(non-vaild)
注意,一个服务器必须在“master-down-after-milliseconds”周期时间(毫秒)返回无效回复才会被sentinel标记为主观下线,如若“master-down-after-milliseconds”为30000ms(30s),只要服务器在每29秒以内返回至少一次有效回复,此服务器就会被认为处于正常状态。
从主观下线状态切换到客观下线状态并无使用严格的法定人数算法(strong quorum algorithm),而是使用了流言协议:若是Sentinel在给定的时间范围内, 从其余Sentinel那里接收到了足够数量的master下线报告, 那么Sentinel就会将master的状态从主观下线改变为客观下线。 若是以后其余Sentinel再也不报告master已下线, 那么客观下线状态就会被移除
客观下线条件只适用于master:对于任何其余类型的Redis实例,Sentinel在将它们判断为下线前不须要进行协商,因此slave或者其余Sentinel永远不会达到客观下线条件
分为两部分,第一部分选出sentinel leader,第二部分进行故障转移:
一、sentinel集群中的一个sentinel发现master疑似下线,标记该master的状态为主观下线(SDOWN)【sentinel节点会每1s向master发送PING消息,若一个服务器没有在“master-down-after-milliseconds”选项指定时间内,对向他发送“PING”的sentinel返回一个有效回复(valid reply),那么sentinel会将此服务器标记为主观下线(SDOWN)】
二、选出sentinel leader。该sentinel查看本身有无投给其余sentinel节点票,若已经投过,那么在两倍故障转移超时时间内不会成为leader,则转换身份为follower;没有投过票则申请成为leader(Candidate)。【Sentinel集群正常运行时,每一个节点epoch(版本号,具体是什么翻看本文章上下文)相同,当须要故障转移时会在sentinel集群中选出leader,由leader发起并执行故障转移操做。Sentinel采用Raft协议实现了Sentinel间选举Leader的算法(不过也不彻底同样,具体参看http://weizijun.cn/2015/04/30/Raft协议实战之Redis%20Sentinel的选举Leader源码解析/),Sentinel集群故障转移完成后,全部Sentinel又会恢复平等。Leader仅仅是故障转移操做才会出现的角色】
三、Candidate(申请成为leader的sentinel节点)此时更新故障转移状态为“start”,使当前epoch自增1(进入新的选举周期),给本身投一票以及向其余sentinel节点请求投票等
四、Candidate不断统计本身的票数,当达到一半且超过它配置的quorum的票数,那么它就成为Leader(若在一个选举时间内,Candidate没有得到超过一半且超过它配置的quorum的票数,这次选举失败,那么在设定的故障迁移超时时间的两倍以后, 从新尝试当选)
五、sentinel leader迭代全部的sentinel follower节点,检测是否须要将该master标记为客观下线(ODOWN)状态,是则继续,不然取消选举投票
六、选出合适的slave,sentinel leader使用如下流程来选择合适的slave:
a、 ·在故障master属下的slave当中, 那些被标记为主观下线、已断线、或者最后一次回复PING命令的时间大于五秒钟的slave都会被淘汰
·在故障master属下的slave当中, 那些与失效master链接断开的时长超过 down-after 选项指定的时长十倍的slave都会被淘汰
b、选择“slave-priority”(slave优先级)最高的slave,存在则选取该slave成为新master,存在相同优先级则继续向下
c、复制偏移量(replication offset,即复制数据最完整)最大的那个slave做为新master,存在相同复制偏移量则继续向下
d、选择“run_id”(“INFO SERVER”查看)最小的slave
七、sentinel leader向被选中的slave发送命令“SLAVEOF NO ONE”,提高选中的slave为master
八、经过发布与订阅功能,将更新后的配置传播给全部其余Sentinel, 其余Sentinel对它们本身的配置进行更新
九、向已下线master的slave发送“SLAVEOF”命令,让它们重新master复制数据
十、当全部slave都已经开始复制新master时,sentinel leader 终止此次故障迁移操做,全部Sentinel又会恢复平等身份
每当一个 Redis 实例被从新配置(reconfigured) —— 不管是被设置成master、slave、又或者被设置成其余master的slave ——Sentinel都会向被从新配置的实例发送一个 CONFIG REWRITE 命令, 从而确保这些配置会持久化在硬盘里。
Redis实例有配置参数“slave-priority”,此参数在“INFO”中也能查询,sentinel使用此配置从slave来挑选故障切换后的新master:
· “slave-priority”设置为0的slave,不能升级为master
· 优先级小的salve会优先考虑提高为master。如master有2个slave(S1,S2),优先级S1为10,S2为100,若master故障且S1,S2均可用,则S1将是新master首选
当一个sentinel leader实例准备进行故障转移,因为master处于ODOWN状态,且sentinel leader从已知的大多数sentinel实例收到故障转移受权,此时一个合适的slave就要被选举出来。slave选举考量如下几项:
· 与master断开时间
· slave优先级
· 复制偏移量
· 运行ID
一个Slave若被发现与master断开链接的时间超过master配置的超时时间(down-after-milliseconds选项)的十倍,加上从正在执行故障转移的sentinel leader角度看master不可用的时间,将被认为是不合适的且会被跳过。
即slave若不可用时间超过如下时间,会被认为是不适合成为master的节点:
(down-after-milliseconds * 10) + milliseconds_since_master_is_in_SDOWN_state
经过了以上测试的slave会继续进行如下筛选:
一、而后按照slave配置文件中“slave-priority”的大小进行排序,数字小且不为0的slave将被选择为新master
二、若“slave-priority”相同,则检查slave的复制偏移量,偏移量大(从旧master接收到更多的数据)的会被选择为新master
三、若多个slave有相同的优先级和复制偏移量,则则选择“run_id”(INFO SERVER能够查看到)小的slave成为新master
在Redis集群中,如有合适的机器做为slave,强烈建议将其优先级数配置小一点,使其优先级高一些。另外,复制偏移量相同的状况并很多见,且全部的redis实例均可以运行在默认“run_id”上,想一想多么可怕...
· 每一个Sentinel以每秒钟一次的频率向它所知的master、slave以及其余Sentinel实例发送一个PING命令。
· 若是一个实例(instance)距离最后一次有效回复PING命令的时间超过 down-after-milliseconds 选项所指定的值, 那么这个实例会被Sentinel标记为主观下线。 一个有效回复能够是:+PONG、-LOADING或-MASTERDOWN
· 若是一个master被标记为主观下线, 那么正在监控这个master的全部Sentinel要以每秒一次的频率确认master的确进入了主观下线状态
· 若是一个master被标记为主观下线, 而且有足够数量的Sentinel(至少要达到配置文件指定的数量)在指定的时间范围内赞成这一判断, 那么这个master被标记为客观下线
· 在通常状况下, 每一个Sentinel会以每 10 秒一次的频率向它已知的全部master和slave发送 INFO 命令。 当一个master被Sentinel标记为客观下线时,Sentinel向下线master的全部slave发送INFO命令的频率会从10秒一次改成每秒一次
· 当没有足够数量的Sentinel赞成master已经下线master的客观下线状态就会被移除。 当master从新向Sentinel的PING命令返回有效回复时, master的主管下线状态就会被移除
当Lua脚本运行时间超过配置的Lua脚本时限时,Redis实例将返回“-BUSY”错误,在触发故障切换前,Redis尝试发送一个“SCRIPT KILL”命令尝试杀死脚本执行进程,若脚本只读(the script was read-only),命令将执行成功。若该实例在尝试后仍处于错误状态,实例将进行故障切换
接下来,将逐步介绍全部关于sentinel API,配置和语义。同时,本节也将会介绍如何配置3个sentinel实例并与之交互。
此处假设3个实例运行在端口5000,5001,5002,且有redis集群一主一从,分别运行在端口6379,6380,而后这些端口所有侦听在一个机器的127.0.0.1回环地址
3个sentinel配置相似:
port 5000
sentinel monitor mymaster 127.0.0.1 6379 2
sentinel down-after-milliseconds mymaster 5000
sentinel failover-timeout mymaster 60000
sentinel parallel-syncs mymaster 1
其余两个sentinel配置修改端口为5001,5002便可
以上:
· Master实例组定义为mymaster。依据不一样的master实例组名称,sentinel能同时监控不一样的Redis主从集群
· quorum设置为2,sentinel monitor配置指令的最后一个参数值
· down-after-milliseconds值为5000ms,即5s,所以只要在这段时间没有收到master的ping回复,master就会被认定为链接失败
启动sentinel会收到Redis集群登陆消息:
+monitormastermymaster 127.0.0.1 6379 quorum 2
此为sentinel事件信息,也可以使用“发布/订阅”接收这类事件。在故障检测和故障转移期间,sentinel会生成并记录不一样的事件
查询sentinel中master的状态:
redis-cli -p 5000Sentinelmaster mymaster
1) "name"
2) "mymaster"
3) "ip"
4) "127.0.0.1"
5) "port"
6) "6379"
7) "runid"
8) "8f315c998236a332cb327e6c33e5efead00f14c9"
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) "368"
19) "last-ping-reply"
20) "368"
21) "down-after-milliseconds"
22) "30000"
23) "info-refresh"
24) "2704"
25) "role-reported"
26) "master"
27) "role-reported-time"
28) "1318596"
29) "config-epoch"
30) "2"
31) "num-slaves"
32) "1"
33) "num-other-sentinels"
34) "2"
35) "quorum"
36) "2"
37) "failover-timeout"
38) "180000"
39) "parallel-syncs"
40) "1"
一些关键信息:
· num-other-sentinels为2,表示sentinel检测到其他两个sentinel。在日志中也会看到+sentinel生成的事件
· flags只有master,若master挂掉,那能够在这看到s_down或o_down标记
· num-slaves为1,表示sentinel检测到有一个slave链接到master
sentinel查看slave信息
sentinel slaves mymaster
查看sentinel信息
sentinel sentinels mymaster
获取当前master的地址
SENTINEL get-master-addr-by-name mymaster
故障转移测试
此时,sentinel测试环境已部署好,能够暂时关闭master并检查配置是否发生改变,可让master暂停300s:
redis-cli -p 6379 DEBUG sleep 300
此命令将master休眠300s,模拟了master故障没法链接的状况。此时查看sentinel日志,能看到相关操做:
· 每一个sentinel检测到master +sdown事件
· 事件后来升级到+odown,意味着多个sentinel确认master不可达
· sentinel投票支持将启动第一次故障转移尝试的sentinel
· 开始故障转移
· ...
此时再次查询master地址信息,会获得不一样的回复:
127.0.0.1:5000>Sentinelget-master-addr-by-name mymaster
1) "127.0.0.1"
2) "6380
当master增长安全性被配置为须要客户端密码进行链接时,slave也要知道该密码,以便master与slave用于异步复制协议的主从链接。
使用如下指令配置密码:
· requirepass在master中配置,配置后可确保不处理未验证客户端的请求
· masterauth在slave配置,以便slave与master进行身份验证,正常的复制数据
当使用sentinel模式时,架构中并不仅有一个master,那么依据sentinel机制,故障转移后,slave会改变角色成为新master,旧master恢复正常后会成为新master的slave,所以上述配置要在全部Redis集群中实例配置,不管是master仍是slave。
然而,在少数状况下,咱们可能须要谋个slave节点不须要验证就可被客户端读取数据,能够经过设置此slave优先级为0,来避免该slave升级为master,且仅配置“masterauth”,此时就可实现未经身份验证的客户端读取数据
为了使sentinel能正常链接到配置了“requirepass”的Redis实例,sentinel必须配置“sentinel auth-pass”指令,格式以下:
sentinel auth-pass <master-group-name> <pass>
Sentinel须要明确的客户端支持,除非系统配置为执行将全部请求透明重定向到新的主实例(虚拟IP或其余相似系统)的脚本。Sentinel客户端指南中介绍了客户端库实现的主题
Sentinel提供一个API来检查其状态,检查受监控master和slave的运行状态,订阅以得到特定通知,并在运行时更改sentinel配置
默认sentinel侦听在TCP端口26379(6379是Redis master和Redis slave端口),sentinel使用redis协议通讯,所以可以使用redis-cli与sentinel进行交互
能够直接从sentinel的监控信息中查看Redis实例状态,也能查询到其余sentinel的信息等,同时,使用PUB/SUB可 从sentinel接收推送通知,如故障转移或进入错误状态的实例,均可以进行推送。
如下是命令列表,但不包括修改sentinel配置的命令(稍后介绍)
PING #返回PONG
SENTINEL masters #显示全部被监控的master集齐状态
SENTINELmaster<master name> #显示指定的master的状态信息
SENTINEL slaves <master name> #显示指定的master的slave状态信息
SENTINEL sentinels <master name> #显示指定master的sentinel状态信息
SENTINEL get-master-addr-by-name <master name> #显示指定名称master的IP和PORT,若master正在进行故障切换或被中止,则返回被提高为master的slave的IP和PORT
SENTINEL reset <pattern> #重置全部包含关键字的master。 “pattern”参数是一个全局风格的模式。重置进程会清除master全部先前保存的状态(包括正在进行故障切换),且删除已发现并与master关联的每一个slave及其状态
SENTINEL failover <master name> #手动强制故障切换,当master失效时,在不询问其余Sentinel意见的状况下, 强制开始一次自动故障迁移(不过发起故障转移的Sentinel会向其余Sentinel发送一个新的配置,其余Sentinel会根据这个配置进行相应的更新)
SENTINEL ckquorum <master name> #检查当前sentinel的配置可否达到故障切换master所需的数量,执行此命令也会检测其余大多数sentinel是否正常(检测是否在线,以及是否能受权故障切换)。此命令应在sentinel中用于检测sentinel部署是否正常
SENTINEL flushconfig #强制sentinel将运行时配置写入磁盘,包括当前sentinel状态。通常,sentinel每次在其状态改变时都会重写配置(在sentinel状态信息被持久化到磁盘后重启)。然而,有时会出现配置文件丢失的状况,如操做失误,磁盘故障,软件包升级或配置管理器而致使配置文件丢失。此时,强制sentinel重写配置文件就很必要了,也很方便(老的配置文件丢失不会影响该命令的执行)
从Redis 2.8.4版开始,sentinel提供一个API来添加、删除或更改master的配置。注意:如有多个sentinel,你应该手动把全部的改变同步到其余Redis sentinel实例中,意思是更改单个sentinel配置,不会自动将更改同步到网络中的sentinels。
如下是sentinel用于更新sentinel实例配置的命令列表:
SENTINEL MONITOR <name> <ip> <port> <quorum> #此命令通知sentinel开始监控一个新的master,且指定其名称,ip,port,quorum,与sentinel.conf配置文件里“sentinel monitor”指令语法相似,不一样的是你不能使用主机名代替IP,只能使用IPv4或IPv6地址
SENTINEL REMOVE <name> #移除指定master:这个master将从sentinel监控列表移除,将从sentinel的内部状态信息中彻底清除,sentinel,masters也没法列出该master
SENTINEL SET <name> <option> <value> #与“CONFIG SET”命令类似,用于改变特定master的配置参数。指定多“option/value”对是能够的(单对也是能够的);sentinel.conf里全部可配置参数均可以使用SET命令进行配置。
如下是SENTINEL SET命令的一个示例,用于修改所down-after-milliseconds调用的主设备的配置objects-cache:
SENTINEL SET objects-cache-master down-after-milliseconds 1000
如前所述,sentinel SET可用来所设置全部配置文件中可配置的配置参数,此外,他能在不从新添加master(先SENTINEL REMOVE再SENTINEL MONITOR)的状况下,修改quorum:
SENTINEL SET objects-cache-master quorum 5
请注意,因为SENTINEL MASTER以简单解析格式(做为字段/值对数组)提供全部配置参数,所以没有等效的GET命令
基于sentinel自动发现机制,添加一个新sentinel是很是简单的。你须要仅仅是启动新的sentinel,配置危机监控当前全部活动的master,10s内sentinel将得到其余sentinel列表及被监控master的全部slave信息
若要添加多个sentinel
建议一个一个添加,等待其余sentinels已经能和新sentinel通讯,再添加下一个。新增sentinel有可能失败,一个一个添加sentinel能有效保证大多数sentinel都是正常的(若一次性添加的sentinel数量大于现有sentinel数量,而且添加出现问题,可能会致使现有sentinel出现问题)。通常的每30s添加一个sentinel是比较常见的。
添加结束后,可用命令“SENTINELmastermastername”检查全部sentinel是否已经彻底获取到全部master的信息
删除sentinel比较复杂
即便被删除的sentinel很长时间没法访问,sentinels不会彻底清除已经添加过的sentinels信息,由于要尽可能减小其余sentinel的配置版本的更新,删除sentinel也有可能引发故障转移
所以为了移除一个sentinel,在没有网络隔离的状况下应遵循如下步骤:
一、中止要删除的sentinel进程
二、执行命令“SENTINEL RESET *”,向全部其余sentinel实例发送命令重置状态信息(*表示重置全部master,也能够指定master名称)。信息会一个一个的更新,大概须要30s
三、执行命令“SENTINELmastermastername”检查每一个sentinel显示的sentinel数量是否一致
删除旧的master或没法没法访问的slave
Sentinel不会彻底清除指定master的slave,即便slave长时间没法访问。在故障转移后,一旦旧master再次可用,会自动成为新master(旧slave)的slave,此时,新master和新slave会组成新的复制架构。
若想从sentinel监控的master/slave列表里永久删除一个slave(多是旧master),在中止slave进程后,你须要向全部sentinel发送命令“SENTINEL RESET mastername”,重置mastername全部状态信息
客户端能够将sentinel看作一个只提供了订阅功能的Redis服务器,不能使用PUBLISH命令向这个服务器发送信息,但可以使用“SUBSCRIBE”命令或“PSUBSCRIBE”命令,经过订阅给定的频道来获取相应的事件提醒。
一个频道能接收和此频道名称相同的事件,如名为+sdown的频道就可接收全部实例进入主观下线(SDOWN)状态的事件
经过执行“PSUBSCRIBE *”命令能接收全部事件信息。
如下是能利用此API接收的频道和消息格式的列表。第一个英文单词是频道/事件的名称,其他是数据格式。
注意,当格式中包含“instance details”时,表示频道所返回信息中包含了如下用于识别目标实例的内容:、
<instance-type> <name> <ip> <port> @ <master-name> <master-ip> <master-port>
“@”字符串后的内容指定master(即@到最后部分,此部分是可选的),仅在“@”字符以前的内容指定的实例不是master时使用。
· +reset-master <instance details> #master已被重置
· +slave <instance details> #一个新slave已被sentinel识别并关联
· +failover-state-reconf-slaves <instance details> #故障转移状态切换到了reconf-slaves状态
· +failover-detected <instance details> #另外一个sentinel开始了一次故障转移操做,或一个slave转换成了master
· +slave-reconf-sent <instance details> #领头(leader)的sentinel向实例发送了命令“SLAVEOF”,为实例从新设置新的Redis master
· +slave-reconf-inprog <instance details> #实例正在将本身设置为master的slave,但相应的同步过程仍未完成
· +slave-reconf-done <instance details> #slave已成功完成对新master的同步
· -dup-sentinel <instance details> #对给定master进行监控的一个或多个sentinel已经由于重复出现而被移除(当sentinel实例重启时会出现此种状况)
· +sentinel <instance details> #master有新sentinel被识别并添加
· +sdown <instance details> #指定实例现处于主观下线Subjectively Down状态
· -sdown <instance details> #指定实例现再也不处于主观下线状态
· +odown <instance details> #指定实例现处于客观下线(Objectively Down)状态
· -odown <instance details> #指定实例现再也不处于客观下线状态
· +new-epoch <instance details> #Slot的版本号或者消息的版本号已被更新。节点如何判断收到的集群消息是较新的。Redis中使用版本号机制来判断消息的新旧,版本号越高表示消息越新。在Redis中这种版本号被称做configEpoch,每一个节点都有一个configEpoch,它是一个64位的整数。其实configEpoch更应该被称做是Slot的版本号,或者某个Slot与节点映射关系的版本号。怎么理解呢?咱们从消息冲突的角度看这个问题,由于configEpoch就是为了解决消息冲突的嘛。如上文所说集群中每一个节点都会维护一份集群状态快照。快照中每一个Slot都有一个与之对应的节点,每一个节点都有一个configEpoch,因此直观上configEpoch就像是Slot的版本号。当某一个节点负责的Slot有变化的时候,节点会更新本身的configEpoch,并随着集群心跳传播该消息,集群消息是一系列Slot、节点与configEpoch组成的三元组。当新的集群消息传播到其它节点的时候,节点会对比节点自己与集群消息中对应Slot的configEpoch来决定是否更新本地集群状态快照,从这层意义上看configEpoch也更适合被称做Slot的版本号或者消息的版本号。
· +try-failover <instance details> #正在进行新的故障转移,正处于等待多数选举状态
· +elected-leader <instance details> #赢得指定版本的选举,能够进行故障迁移
· +failover-state-select-slave <instance details> #故障转移操做现处于“select-slave”状态,sentinel正在寻找一个能被提高为master的slave
· no-good-slave <instance details> #sentinel未找到合适的slave去升级。Sentinel会在一段时间后重试,可是在这种状况下,可能会改变状态机并终止故障切换
· selected-slave <instance details> #sentinel找到合适的slave去提高
· failover-state-send-slaveof-noone <instance details> #sentinel正在讲指定的slave提高为master,等待功能升级完成
· failover-end-for-timeout <instance details> #故障转移因超时而停止,不过最终全部slave都会开始复制新master(slaves will eventually be configured to replicate with the newmasteranyway)
· failover-end <instance details> #故障转移操做顺利完成,全部slave开始重新master复制数据
· switch-master <master name> <oldip> <oldport> <newip> <newport> #master链接配置变动,外部客户端都关心的信息
· +tilt #进入tilt模式
· -tilt #退出tilt模式
哨兵与其余哨兵保持联系,以便互相检查对方的可用性,并进行信息交换。无须为运行的每一个Sentinel分别设置其余Sentinel的地址, 由于Sentinel能够经过发布与订阅功能来自动发现正在监控相同master的其余Sentinel, 这一功能是经过向频道 sentinel:hello 发送信息来实现的。
与此相似, 你也没必要手动列出master属下的全部slave, 由于Sentinel能够经过询问master来得到全部slave的信息。
· 每一个Sentinel会以每两秒一次的频率, 经过发布与订阅功能,向被它监控的全部master和slave的 sentinel:hello 频道发送一条信息,信息中包含了Sentinel的 IP 地址、端口号和运行 ID (runid)。
· 每一个Sentinel都订阅了被它监控的全部master和slave的 sentinel:hello 频道, 查找以前未出现过的Sentinel(looking for unknown sentinels)。当一个Sentinel发现一个新的Sentinel时, 它会将新的Sentinel添加到一个列表中, 这个列表保存了Sentinel已知的, 监控同一个master的全部其余Sentinel。
· Sentinel 发送的信息中还包括完整的master当前配置(configuration)。 若是一个Sentinel包含的master配置比另外一个Sentinel发送的配置要旧, 那么这个Sentinel会当即升级到新配置上。
· 在将一个新Sentinel添加到监控master的列表上面以前,Sentinel会先检查列表中是否已经包含了和要添加的Sentinel拥有相同运行 ID 或者相同地址(包括 IP 地址和端口号)的Sentinel, 若是是的话,Sentinel会先移除列表中已有的那些拥有相同运行 ID 或者相同地址的Sentinel,而后再添加新Sentinel。
即便没有自动故障迁移操做在进行,sentinel总会尝试将当前配置应用到被监控的实例上,特别是:
· 依据当前配置,若一个slave被提高为master,那他会成为旧master原有slave的复制对象,链接了错误master的slave会被从新配置,以便能从正确的master获取数据
· 旧master挂掉从新上线后,会被配置为新master的slave
不过, 在以上这些条件知足以后,sentinel在对实例进行从新配置以前仍然会等待一段足够长的时间, 确保能够接收到其余sentinel发来的配置更新, 从而避免自身由于保存了过时的配置而对实例进行了没必要要的从新配置
Quorum
如前所述,每一个被sentinel监控的master都配置了quorum,指定须要对master的不可达性或故障达成一致的sentinel数量,以便触发故障转移。另外,网络问题致使架构间产生网络分区,此时故障转移毫不会在只有小部分的Sentinels存在的网络分区中执行,只会在大部分sentinels存在的网络分区中执行
简单的说就是:
· quorum:为了将master标记为ODOWN,须要发现并确认错误的sentinel数量
· 故障转移在ODOWN状态被触发
· 一旦故障转移被触发,尝试进行故障转移的sentinel会请求大多数sentinel的受权(在quorum为大多数的状况下)
如,架构中有5个sentinel 实例,quorum为2,那么至少2个sentinel确认master不可达后,故障转移才会被触发,而后能执行故障转移的只有其中一个sentinel。
若quorum为5,则全部sentinel都必须就master故障达成一致,且执行故障转移的sentinel leader要获得全部sentinel的受权才能进行故障转移。
这意味着quorum可有两种方式调整sentinel:
· 若quorum设置为小于部署的大多数sentinel的数量,此时sentinel对master故障更加敏感,且一旦少数的sentinel没法和master通讯就会触发故障转移
· 若quorum设置为大于部署的大多数sentinel的数量,此时只有大多数sentinel都确认master故障时,sentinel leader才能开始故障转移
为了开始故障转移,Sentinels leader须要从大多数sentinel获得受权,缘由:
当一个Sentinel leader被受权,它会为故障转移后的新master得到一个惟一性的epoch,用来标记故障转移完成后sentinels的新配置版本号,另外,只有确认了master故障的大多数sentinel才能得到这个版本号。这意味着,每次故障转移的配置都会更新一个独一无二的版本号,这很重要,后面会解释为何这么重要。
此外Sentinels有机制:若一个sentinel为故障转移一个新master而投票给其余sentinel,它将等待一段时间再次尝试故障转移这个master,在sentinel.conf中可配置这个延迟时间failover-timeout。这意味着Sentinels在相同的时间内不会尝试故障转移相同的master,第一次请求受权成功后会尝试,失败则另外一个sentinel将会在一段时间后尝试,类推。
Redis Sentinel保证了活性(liveness)特色:若是大多数Sentinels 可以互相通讯,master故障,最后必定会有一个sentinel会被受权开始故障转移。
Redis Sentinel一样也保证了安全(safety)特色:一次故障转移中,每一个Sentinel故障转移同一个master将使用不一样的epoch版本号,失败后由另外的sentinel会从新生成惟一的epoch版本号,而后发起故障转移;而第一次生成的epoch版本号由于没有故障转移成功而丢弃,生成的配置也不是最终配置也会被丢弃
一旦sentinel leader 故障转移成功,他将开始广播新的配置,以便其余sentinels更新新master的信息。
为了确认故障转移是否成功,sentinel须要能发送命令“SLAVEOF NO ONE”给全部参与选举的slave,稍后,切换为新master的信息能在“INFO”输出中显示。
此时,即便slave正在更新配置,故障转移也被断定为成功,且全部Sentinels须要开始报告新的配置。
Sentinel leader传播新配置的缘由是每一个sentinel每次进行已受权的故障转移时,都会产生不一样的惟一的配置版本号,最终全部sentinel会共享一个配置版本号。
每一个sentinel使用redis 订阅/发布功能向全部的master/slave连续地广播其监控的master的版本,同时全部的sentinel也会等待来自其余sentinel广播的消息。
配置在__sentinel__:hello发布/订阅频道中被广播。
每份配置都有不一样的版本号,而大的版本号老是赛过小的版本号,版本号越大,越接近最终的配置版本,越有广播的意义。
如,初始配置时,全部sentinels都持有版本号为1的配置,即mymaster的配置为192.168.1.50:6379,一段时间后发生故障转移,生成配置版本号2,若转移成功,他将广播新的配置,即192.168.1.51:9000,其余sentinel实例收到这个配置的广播会更新的本身的配置,由于此配置有更高的版本号。
也就是说,sentinel有第二个活性特色:一个能互相通讯的sentinel集群,在故障转移时,都会尝试更新版本更高的配置。
通常若网络故障产生网络分区,每一个分区的sentinel都会尝试收敛到更高版本的配置,没有网络分区时,全部sentinel都会更新配置
Redis sentinel配置保证最终一致性,产生网络分区时,每一个分区都会尝试收敛到更高版本的可用配置。
使用sentinel时,有三种角色:
· Redis实例
· Sentinel实例
· Client
为定义整个架构系统的行为,咱们要考虑到上述三种角色,如下网络中有3个节点,每节点运行一个Redis实例和sentinel实例:
在此系统的初始状态中,Redis3是master,Redis2和Redis3是slave。此时网络故障形成旧master与其余节点隔离,sentinel 1和 2开始一轮故障转移,提高redis1为新master。
此时,Sentinel的机制保证了sentinel 1和 2持有master的最新配置,然而sentinel 3在隔离分区中仍然持有旧的配置,咱们知道sentinel 3会在网络恢复时获取新的配置,但如有客户端在网络故障时访问旧master,会发生什么?
此时客户端仍然能在Redis3(旧master)中写入,当网络恢复,Redis3将变成Redis1的slave,并清除在网络故障期间写入的全部数据。
依据数据需求,或者配置需求,你可能想或不想数据丢失的状况发生:
· 若你使用Redis做为缓存服务器,Client B仍然可向旧master写入数据是很方便的,即便数据最终会丢失
· 若你使用Redis做为存储服务器,这就很不友好了,此时为了阻止这个问题须要对系统进行配置
因为Redis是异步复制的,这种状况下没法彻底避免数据丢失,但可以使用如下配置限制Redis3和Redis1之间数据的一致性问题:
min-slaves-to-write 1
min-slaves-max-lag 10(秒)
当master配置以上选项,若它不能向至少一个slave写入数据,将会中止接受写入请求。因为是异步复制,不能写意味着slave已断开链接,或未发送异步确认超过max-lag秒数
所以上例中,redis3将在10s后不可用,网络恢复后,sentinel 3将会整合到新架构中,客户端B能从新获取有效配置并继续请求。
总之,Redis+Sentinel造成的架构系统具备最终一致性(a whole are a an eventually consistent system where the merge function is last failover wins),且旧master的数据会被丢弃,而后重新mastar从新获取数据,所以总有一个节点会丢失部分已经写入的数据。 This is due to Redis asynchronous replication and the discarding nature of the "virtual" merge function of the system。但这sentinel自己没有限制,若你使用强一致性的方法协调故障转移,问题一样会出现。
只有两种方法避免丢失已确认的写入:
· 使用同步复制(以及使用一个合适的一致性算法来运行复制行为)
· 使用具备最终一致性的系统,能合并相同对象的不一样版本
Redis如今不能使用上面的任何系统,是目前的发展目标。但是有一个代理实现解决方案2在Redis存储之上,如SoundCloud Roshi,或者Netflix Dynomite。
Sentinel状态信息持久化到sentinel.conf中,如每次接收一个新配置文件或者建立一个新配置文件(sentinel leader完成),配置都会和配置版本号(epoch)一块儿持久化到磁盘。很明显,即便即便sentinel进程重启也能保证配置不丢失
Redis sentinel严重依赖系统时间:为了确认实例是否可用,他会记录最后一次回复PING的时间,并和当前时间比较推断距离最后一次回复过去了多久。
然而,若系统时间发生非正常改变,或者系统很是繁忙,或进程因为某些缘由阻塞,sentinel可能会出现一些问题
TITL模式是一种特殊的“保护”模式,sentinel能在发生一些意料以外问题时,进入这个模式,下降对系统的依赖。Sentinel定时器中断正常状况下每秒10次调用,因此能猜想在定时器中断的两次调用之间或多或少会有100毫秒的时间。
Sentinel所作的就是记录以前的中断调用时间,并和当前调用时间对比:
· 若是两次调用时间之间的差距为负值, 或者很是大(超过 2 秒钟), 那么 Sentinel 进入 TILT 模式。
· 若是 Sentinel 已经进入 TILT 模式, 那么 Sentinel 延迟退出 TILT 模式的时间。
当处于TITL模式,sentinel或持续监控全部状态,但:
· 中止处理请求
· 当有实例向这个Sentinel发送“SENTINEL is-master-down-by-addr”命令时,Sentinel返回负值: 由于这个Sentinel所进行的下线判断已经再也不准确。
若是 TILT 能够正常维持30秒钟, 那么Sentinel退出TILT模式。