(二)redis主从原理及流程——高可用

Sentinel(哨兵)的来由
书接上文,我们学习了redis的replication的原理,我们这一章来讨论一下redis主从策略的高可用性。这个哨兵的插件是我们redis里面集成了的(部署简单略),哨兵会监控主从的各个节点状态,当主节点被视为不可用时,那么,哨兵之间或进行“投票协商”进行判刑master的死亡,并且从slave中选举出新的master。这就是哨兵在redis主从结构中的重要作用。





Redis 2.8版开始正式提供名为Sentinel的主从切换方案,Sentinel用于管理多个Redis服务器实例,主要负责三个方面的任务:
    1. 监控(Monitoring): Sentinel 会不断地检查你的主服务器和从服务器是否运作正常。
    2. 提醒(Notification): 当被监控的某个 Redis 服务器出现问题时, Sentinel 可以通过 API 向管理员或者其他应用程序发送通知。
    3. 自动故障迁移(Automatic failover): 当一个主服务器不能正常工作时, Sentinel 会开始一次自动故障迁移操作, 它会将失效主服务器的其中一个从服务器升级为新的主服务器, 并让失效主服务器的其他从服务器改为复制新的主服务器; 当客户端试图连接失效的主服务器时, 集群也会向客户端返回新主服务器的地址, 使得集群可以使用新主服务器代替失效服务器。

Redis Sentinel 是一个分布式系统, 你可以在一个架构中运行多个 Sentinel 进程(progress), 这些进程使用流言协议(gossip protocols)来接收关于主服务器是否下线的信息, 并使用投票协议(agreement protocols)来决定是否执行自动故障迁移, 以及选择哪个从服务器作为新的主服务器。

一般集群数量为基数策略,原因是有一个值quorum(sentinel集群认为master宕机的数量),这个值用来跟majority来比较的,当quorum>=majority认为master节点宕机。majority就是我们所谓的集群基数标准(1主2从:2,1主3从:2)。这也能实现集群利用率最大化。

启动Sentinel
使用--sentinel参数启动,并必须指定一个对应的配置文件,系统会使用配置文件来保存 Sentinel 的当前状态, 并在 Sentinel 重启时通过载入配置文件来进行状态还原。
/src/ redis-sentinel sentinel.conf
使用TCP端口26379,可以使用redis-cli或其他任何客户端与其通讯。
如果启动 Sentinel 时没有指定相应的配置文件, 或者指定的配置文件不可写(not writable), 那么 Sentinel 会拒绝启动。
配置Sentinel
Sentinel.conf详解



##sentinel实例之间的通讯端口  
##redis-0  
port 26379  
##sentinel需要监控的master信息:<mastername> <masterIP> <masterPort> <quorum>  
##<quorum>应该小于集群中slave的个数,只有当至少<quorum>个sentinel实例提交"master失效"  
##才会认为master为O_DWON("客观"失效)  
sentinel monitor def_master 127.0.0.1 6379 2  
  
sentinel auth-pass def_master 012_345^678-90  
  
##master被当前sentinel实例认定为“失效”的间隔时间  
##如果当前sentinel与master直接的通讯中,在指定时间内没有响应或者响应错误代码,那么  
##当前sentinel就认为master失效(SDOWN,“主观”失效)  
##<mastername> <millseconds>  
##默认为30秒  
sentinel down-after-milliseconds def_master 30000  
  
##当前sentinel实例是否允许实施“failover”(故障转移)  
##no表示当前sentinel为“观察者”(只参与"投票".不参与实施failover),  
##全局中至少有一个为yes  
sentinel can-failover def_master yes  
  
##当新master产生时,同时进行“slaveof”到新master并进行“SYNC”的slave个数。  
##默认为1,建议保持默认值  
##在salve执行salveof与同步时,将会终止客户端请求。  
##此值较大,意味着“集群”终止客户端请求的时间总和和较大。  
##此值较小,意味着“集群”在故障转移期间,多个salve向客户端提供服务时仍然使用旧数据。  
sentinel parallel-syncs def_master 1  
  
##failover过期时间,当failover开始后,在此时间内仍然没有触发任何failover操作,  
##当前sentinel将会认为此次failoer失败。  
sentinel failover-timeout def_master 900000  
  
##当failover时,可以指定一个“通知”脚本用来告知系统管理员,当前集群的情况。  
##脚本被允许执行的最大时间为60秒,如果超时,脚本将会被终止(KILL)  
##脚本执行的结果:  
## 1    -> 稍后重试,最大重试次数为10;   
## 2    -> 执行结束,无需重试  
##sentinel notification-script mymaster /var/redis/notify.sh  
  
##failover之后重配置客户端,执行脚本时会传递大量参数,请参考相关文档  
# sentinel client-reconfig-script <master-name> <script-path>  
坑点:

min-slaves-to-write 3

min-slaves-max-lag 10

至多有3个slave延迟同步不能超过10秒,如果一旦触发master不会再接收请求(可以在client端做处理,比如延时队列,持久化磁盘等)

主观下线和客观下线
    1. 主观下线(Subjectively Down, 简称 SDOWN)指的是单个 Sentinel 实例对服务器做出的下线判断。
    2. 客观下线(Objectively Down, 简称 ODOWN)指的是多个 Sentinel 实例在对同一个服务器做出 SDOWN 判断, 并且通过 SENTINEL is-master-down-by-addr 命令互相交流之后, 得出的服务器下线判断。
客观下线条件只适用于主服务器: 对于任何其他类型的 Redis 实例, Sentinel 在将它们判断为下线前不需要进行协商, 所以从服务器或者其他 Sentinel 永远不会达到客观下线条件。
只要一个 Sentinel 发现某个主服务器进入了客观下线状态, 这个 Sentinel 就可能会被其他 Sentinel 推选出, 并对失效的主服务器执行自动故障迁移操作。
每个Sentinel实例都执行的定时任务
    1. 每个 Sentinel 以每秒钟一次的频率向它所知的主服务器、从服务器以及其他 Sentinel 实例发送一个 PING 命令。
    2. 如果一个实例(instance)距离最后一次有效回复 PING 命令的时间超过 down-after-milliseconds 选项所指定的值, 那么这个实例会被 Sentinel 标记为主观下线。 一个有效回复可以是: +PONG 、 -LOADING 或者 -MASTERDOWN 。
    3. 如果一个主服务器被标记为主观下线, 那么正在监视这个主服务器的所有 Sentinel 要以每秒一次的频率确认主服务器的确进入了主观下线状态。
    4. 如果一个主服务器被标记为主观下线, 并且有足够数量的 Sentinel (至少要达到配置文件指定的数量)在指定的时间范围内同意这一判断, 那么这个主服务器被标记为客观下线。
    5. 在一般情况下, 每个 Sentinel 会以每 10 秒一次的频率向它已知的所有主服务器和从服务器发送 INFO 命令。 当一个主服务器被 Sentinel 标记为客观下线时, Sentinel 向下线主服务器的所有从服务器发送 INFO 命令的频率会从 10 秒一次改为每秒一次。
    6. 当没有足够数量的 Sentinel 同意主服务器已经下线, 主服务器的客观下线状态就会被移除。 当主服务器重新向 Sentinel 的 PING 命令返回有效回复时, 主服务器的主管下线状态就会被移除。
Sentinel API
有两种方式可以与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 get-master-addr-by-name <master name>获取当前的主服务器IP地址和端口号,以及SENTINEL slaves <master name>获取所有的Slaves信息
    发布与订阅信息
    客户端可以将 Sentinel 看作是一个只提供了订阅功能的 Redis 服务器: 你不可以使用 PUBLISH 命令向这个服务器发送信息, 但你可以用 SUBSCRIBE 命令或者 PSUBSCRIBE 命令, 通过订阅给定的频道来获取相应的事件提醒。
   一个频道能够接收和这个频道的名字相同的事件。 比如说, 名为 +sdown 的频道就可以接收所有实例进入主观下线(SDOWN)状态的事件。
   通过执行 PSUBSCRIBE * 命令可以接收所有事件信息。
        +switch-master <master name> <oldip> <oldport> <newip> <newport> :配置变更,主服务器的 IP 和地址已经改变。 这是绝大多数外部用户都关心的信息。
    可以看出,我们使用Sentinel命令和发布订阅两种机制就能很好的实现和客户端的集成整合:
    使用get-master-addr-by-name和slaves指令可以获取当前的Master和Slaves的地址和信息;而当发生故障转移时,即Master发生切换,可以通过订阅的+switch-master事件获得最新的Master信息。
    *PS:更多Sentinel的可订阅事件参见官方文档。
sentinel.conf中的notification-script
    在sentinel.conf中可以配置多个sentinel notification-script <master name> <shell script-path>, 如sentinel notification-script mymaster ./check.sh
    这个是在群集failover时会触发执行指定的脚本。脚本的执行结果若为1,即稍后重试(最大重试次数为10);若为2,则执行结束。并且脚本最大执行时间为60秒,超时会被终止执行。
    PS:目前会存在该脚本被执行多次的问题,查找资料有人解释是:
        脚本分为两个级别, SENTINEL_LEADER 和 SENTINEL_OBSERVER ,前者仅由领头 Sentinel 执行(一个 Sentinel),而后者由监视同一个 master 的所有 Sentinel 执行(多个 Sentinel)。
sdown和odown
各个sentinel之间通过命令SENTINEL is_master_down_by_addr来获得其它sentinel对master的检测结果。
从sentinel的角度来看,如果发送了PING心跳后,在一定时间内没有收到合法的回复,就达到了SDOWN的条件。这个时间在配置中通过is-master-down-after-milliseconds参数配置。
当足够多的sentinal认为master宕机了,就从sdown切换成了odown。这个足够多的数量就是quonum。也就是 sdown(主观宕机)*quonum = odown(客观宕机)
sentinel是靠redis的pub/sub实现通讯的_sentinel_:hello channel
配置纠正:slave切换matser,需要哨兵去更新其他slave的matser配置



*master选举算法:
1,排除不适合选举成master的slave【down-after-milliseconds*10+milliseconds_since_master_is_in_SDOWN_state(master的宕机时长)】
2, slave-priority越小优先级越高
3,replica offset,slave 复制了数据越多,offset越靠后,优先级越高
4,选一个run id比较小的slave

说明:本文转自blog.csdn.net,用于学习交流分享,仅代表原文作者观点。如有疑问,请联系我们删除~