zoukankan      html  css  js  c++  java
  • redis学习(七)哨兵

    redis学习(七)哨兵


    哨兵

    Redis的主从复制模式下,一旦主节点由于故障不能提供服务,需要人工将从节点晋升为主节点,同时还要通知应用方更新主节点地址,对于很多应用场景这种故障处理的方式是无法接受的。



    高可用性

    当主节点出现故障时,Redis Sentinel能自动完成故障发现和故障转移,并通知应用方,从而实现真正的高可用。



    Redis Sentinel是一个分布式架构,其中包含若干个Sentinel节点和Redis数据节点,每个Sentinel节点会对数据节点和其余Sentinel节点进行监控,当它发现节点不可达时,会对节点做下线标识。

    如果被标识的是主节点,它还会和其他Sentinel节点进行“协商”,当大多数Sentinel节点都认为主节点不可达时,它们会选举出一个Sentinel节点来完成自动故障转移的工作,同时会将这个变化实时通知给Redis应用方。

    整个过程完全是自动的,不需要人工来介入,所以这套方案很有效地解决了Redis的高可用问题。


    这里的分布式是指:Redis数据节点、Sentinel节点集合、客户端分布在多个物理节点的架构。



    Redis Sentinel与Redis主从复制模式只是多了若干Sentinel节点,所以Redis Sentinel并没有针对Redis节点做了特殊处理。

    sentinel

    在以上的架构中,如果redis主数据节点发生了故障,那么多个sentinel节点对主节点的故障达成一致,选举出了新的主节点,其中的一个sentinel节点作为领导节点,负责故障的转义,负责通知客户端节点的变动,下线故障节点,副节点升级为新的节点。



    Redis Sentinel具有以下几个功能:
    监控:Sentinel节点会定期检测Redis数据节点、其余Sentinel节点是否可达。
    通知:Sentinel节点会将故障转移的结果通知给应用方。
    主节点故障转移:实现从节点晋升为主节点并维护后续正确的主从关系。
    配置提供者:在Redis Sentinel结构中,客户端在初始化的时候连接的是Sentinel节点集合,从中获取主节点信息。



    在进行启动时,可以使用ping命令检查是否启动成功,或者使用进程命令查看进程ps是否包含。

    info sentinel可以查看哨兵的信息



    Redis安装目录下有一个sentinel.conf,是默认的Sentinel节点配置文件。



    port和dir分别代表Sentinel节点的端口和工作目录。



    sentinel monitor

    sentinel monitor <master-name> <ip> <port> <quorum>

    Sentinel节点会定期监控主节点,所以从配置上必然也会有所体现,本配置说明Sentinel节点要监控的是一个名字叫做<master-name>,ip地址和端口为<ip><port>的主节点。<quorum>代表要判定主节点最终不可达所需要的票数。



    但实际上Sentinel节点会对所有节点进行监控,但是在Sentinel节点的配置中没有看到有关从节点和其余Sentinel节点的配置,那是因为Sentinel节点会从主节点中获取有关从节点以及其余Sentinel节点的相关信息



    当所有节点启动后,配置文件中的内容发生了变化,体现在三个方面:

    1. Sentinel节点自动发现了从节点、其余Sentinel节点。
    2. 去掉了默认配置,例如parallel-syncs、failover-timeout参数。
    3. 添加了配置纪元相关参数。


    自动发现从节点,添加相关配置 sentinel known-slave <master-name> <slave_id> <slave_port>表明了主节点的从节点的配置



    自动发现其他哨兵节点信息sentinel known-sentinel <master-name> <sentinel_id> <sentinel_port> hash



    sentinel down-after-milliseconds

    每个Sentinel节点都要通过定期发送ping命令来判断Redis数据节点和其余Sentinel节点是否可达,如果超过了down-after-milliseconds配置的时间且没有有效的回复,则判定节点不可达,<times>(单位为毫秒)就是超时时间。



    sentinel down-after-milliseconds <master-name> <times>

    down-after-milliseconds虽然以为参数,但实际上对Sentinel节点、主节点、从节点的失败判定同时有效。



    sentinel parallel-syncs

    sentinel parallel-syncs <master-name> <nums>

    当Sentinel节点集合对主节点故障判定达成一致时,Sentinel领导者节点会做故障转移操作,选出新的主节点,原来的从节点会向新的主节点发起复制操作,parallel-syncs就是用来限制在一次故障转移之后,每次向新的主节点发起复制操作的从节点个数。

    如果这个参数配置的比较大,那么多个从节点会向新的主节点同时发起复制操作,尽管复制操作通常不会阻塞主节点,但是同时向主节点发起复制,必然会对主节点所在的机器造成一定的网络和磁盘IO开销。



    sentinel failover-timeout <master-name> <times>

    ailover-timeout通常被解释成故障转移超时时间,但实际上它作用于故障转移的各个阶段。

    选出合适从节点,晋升选出的从节点为主节点

    命令其余的从节点复制新的主节点

    等待原主节点恢复后命令他去复制新的主节点

    如果这些节点的时间都超过了failover-timeout,表明故障转移失败



    sentinel auth-pass <master-name> <password>
    如果Sentinel监控的主节点配置了密码,sentinel auth-pass配置通过添加主节点的密码,防止Sentinel节点对主节点无法监控。



    sentinel notification-script <master-name> <script-path>
    sentinel notification-script的作用是在故障转移期间,当一些警告级别的Sentinel事件发生(指重要事件,例如-sdown:客观下线、-odown:主观下线)时,会触发对应路径的脚本,并向脚本发送相应的事件参数。



    sentinel client-reconfig-script <master-name> <script-path>
    sentinel client-reconfig-script的作用是在故障转移结束后,会触发对应路径的脚本,并向脚本发送故障转移结果的相关参数。





    如何监控多个主节点?

    配置方法也比较简单,只需要指定多个masterName来区分不同的主节点即可。

    sentinel monitor master-business-1 10.10.xx.1 6379 2  //第一个主节点
    sentinel down-after-milliseconds master-business-1 60000
    sentinel failover-timeout master-business-1 180000
    sentinel parallel-syncs master-business-1 1
    
    sentinel monitor master-business-2 10.16.xx.2 6380 2  //第二个主节点
    sentinel down-after-milliseconds master-business-2 10000
    sentinel failover-timeout master-business-2 180000
    sentinel parallel-syncs master-business-2 1
    
    graph TB subgraph sentinel监控节点集合,sentinel相互监控 s1(sentinel_1) s2(sentinel_2) s3(sentinel_3) s(sentinel...) end subgraph redis_1 r1(redis_1主节点)--copy-->r2(从节点1) r1(redis_1主节点)--copy-->r3(从节点2) end s1--监控-->r1 s1--监控-->r3 s1--监控-->r2 subgraph redis_2 r11(redis_1主节点)--copy-->r12(从节点1) r11(redis_1主节点)--copy-->r13(从节点2) end s1--监控-->r11 s1--监控-->r13 s1--监控-->r12




    动态调整

    sentinel set <param> <value>

    只在当前sentinel节点有效,一经修改立刻生效,不会重启之后生效,这需要注意。



    部署技巧

    Sentinel节点不应该部署在一台物理“机器”上。

    部署至少三个且奇数个的Sentinel节点。



    API

    命令行命令。

    sentinel masters

    等其余的API和配置项相同



    sentinel客户端连接

    Sentinel节点集合具备了监控、通知、自动故障转移、配置提供者若干功能,也就是说实际上最了解主节点信息的就是Sentinel节点集合,而各个主节点可以通过<master-name>进行标识的,所以,无论是哪种编程语言的
    客户端,如果需要正确地连接Redis Sentinel,必须有Sentinel节点集合和masterName两个参数。



    实现一个Redis Sentinel客户端的基本步骤:

    1. 遍历Sentinel节点集合获取一个可用的Sentinel节点,后面会介绍Sentinel节点之间可以共享数据,所以从任意一个Sentinel节点获取主节点信息都是可以的。
    2. 通过sentinel get-master-addr-by-name master-name这个API来获取对应主节点的相关信息
    3. 验证当前获取的“主节点”是真正的主节点,这样做的目的是为了防止故障转移期间主节点的变化
    4. 保持和Sentinel节点集合的“联系”,时刻获取关于主节点的相关“信息”




    Jedis针
    对Redis Sentinel给出了一个JedisSentinelPool,很显然这个连接池保存的连接还是针对主节点的。

    public JedisSentinelPool(String masterName, Set<String> sentinels,
    final GenericObjectPoolConfig poolConfig, final int connectionTimeout,
    final int soTimeout,
    final String password, final int database,
    final String clientName)
    /*
    masterName——主节点名。
    ·sentinels——Sentinel节点集合。
    ·poolConfig——common-pool连接池配置。
    ·connectTimeout——连接超时。
    ·soTimeout——读写超时。
    ·password——主节点密码。
    ·database——当前数据库索引。
    ·clientName——客户端名
    */
        
      /*
      为每一个Sentinel节点单独启动一个线程,利用Redis的发布订阅功
    能,每个线程订阅Sentinel节点上切换master的相关频道+switch-master。
      
      
      */
        Jedis sentinelJedis = new Jedis(sentinelHost, sentinelPort);
    // 客户端订阅Sentinel节点上"+switch-master"(切换主节点)频道
    sentinelJedis.subscribe(new JedisPubSub() {
    @Override
    public void onMessage(String channel, String message) {
    String[] switchMasterMsg = message.split(" ");
    if (switchMasterMsg.length > 3) {
    // 判断是否为当前masterName
    if (masterName.equals(switchMasterMsg[0])) {
    // 发现当前masterName发生switch,使用initPool重新初始化连接池
    initPool(toHostAndPort(switchMasterMsg[3], switchMasterMsg[4]));
    }
    }
    }
    }, "+switch-master");
    


    实现原理

    Redis Sentinel的基本实现原理,具体包含以下几个方面:
    Redis Sentinel的三个定时任务、主观下线和客观下线、Sentinel领导者选举、故障转移





    三个定时任务

    Redis Sentinel通过三个定时监控任务完成对各个节点发现和监控。

    每隔10秒,每个Sentinel节点会向主节点和从节点发送info命令获取最新的拓扑结构。

    graph TB t(每隔10s执行定时任务) s1((sentinel))--info-->m((master)) & l((salve1)) & ll((salve2))

    Sentinel节点通过info命令对结果进行解析就可以找到相应的从节点。



    每隔2秒,每个Sentinel节点会向Redis数据节点的__sentinel__:hello频道上发送该Sentinel节点对于主节点的判断以及当前Sentinel节点的信息,同时每个Sentinel节点也会订阅该频道,来了解其他Sentinel节点以及它们对主节点的判断。

    <Sentinel节点IP> <Sentinel节点端口> <Sentinel节点runId> <Sentinel节点配置版本> <主节点名字> <主节点Ip> <主节点端口> <主节点配置版本>

    graph LR s1((sentinel_1)) & s2((sentinel_1)) & s3((sentinel_1))--publish-->m(("__Sentinel__:hello<br/>master")) m--subscibe-->s1 & s2 & s3


    每隔1秒,每个Sentinel节点会向主节点、从节点、其余Sentinel节点发送一条ping命令做一次心跳检测,来确认这些节点当前是否可达。



    主观下线,客观下线


    主观下线,一个sentinel节点认为 主节点下线

    每个Sentinel节点会每隔1秒对主节点、从节点、其他Sentinel节点发送ping命令做心跳检测,当这些节点超过
    down-after-milliseconds没有进行有效回复,Sentinel节点就会对该节点做失败判定,这个行为叫做主观下线。



    客观下线,当超过quorum个数的sentinel节点认为主节点下线

    当Sentinel主观下线的节点是主节点时,该Sentinel节点会通过sentinel is-master-down-by-addr命令向其他Sentinel节点询问对主节点的判断,当超过<quorum>个数,Sentinel节点认为主节点确实有问题,这时该Sentinel节点会做出客观下线的决定。



    故障转移

    Redis使用了Raft算法实现领导者选举,因为Raft算法相对比较抽象和复杂。

    选举的过程非常快,基本上谁先完成客观下线,谁就是领导者。



    sentinel is-master-down-by-addr <ip> <port> <current_epoch> <runid>

    ip:主节点IP。
    port:主节点端口。
    current_epoch:当前配置纪元。
    runid:此参数有两种类型,不同类型决定了此API作用的不同。

    当runid等于“*”时,作用是Sentinel节点直接交换对主节点下线的判定。
    当runid等于当前Sentinel节点的runid时,作用是当前Sentinel节点希望目
    标Sentinel节点同意自己成为领导者的请求



    1 选出最好的从节点

    graph TD start[从节点列表选出一个新的节点]--过滤-->filtr["filter 主观下线,断线,<br/>5s内没有响应ping,<br/>与主节点失联超过down-after-milliseconds*10秒的节点"]-->c1{选出slave-priority最大的节点} c1--no-->选择完毕 c1--yes-->继续选择-->c2{选择复制偏移量最大的从节点} c2--yes-->选择完毕 c2--no-->选择runid最小的节点

    2 sentinel领导者会对选出的从节点执行slaveof no one

    3 Sentinel领导者节点会向剩余的从节点发送命令,让它们成为新主节点的从节点,复制规则和parallel-syncs参数有关

    4 Sentinel节点集合会将原来的主节点更新为从节点,并保持着对其关注,当其恢复后命令它去复制新的主节点



    开发与运维的问题

    模拟故障的方法有很多



    强制杀掉对应节点的进程号,或者使用redis的debug sleep命令,或者使用shutdown命令。



    节点运维

    下线节点,在任意一个sentinel节点上执行sentinel failover <master name>



    添加节点

    添加从节点使用,slaveof{masterIp}{masterPort}的配置,使用redis-server启动即可,它将被Sentinel节点自动发现



    添加Sentinel节点

    添加sentinel monitor主节点的配置,使用redis-sentinel启动即可,它将被其余Sentinel节点自动发现



    Sentinel节点只支持如下命令:ping、sentinel、subscribe、unsubscribe、psubscribe、punsubscribe、publish、info、role、client、shutdown。



    sentinel下的读写分离框架图

    graph TB subgraph sentinel集合 s1[sentinel1] s2[sentinel2] s.[sentinel...] end master(master) s1--monitor-->master subgraph slave节点资源池 l1(slave1) l2(slave2) end s1--monitor-->l1 & l2 master--copy-->l1 & l2
  • 相关阅读:
    doT.js——前端javascript模板引擎问题备忘录
    (转)regex类(个人理解)
    ajax提交表单、ajax实现文件上传
    SQL添加表字段
    Elasticsearch使用总结
    有一张表里面有上百万的数据,在做查询的时候,如何优化?从数据库端,java端和查询语句上回答
    sql语句的字段转成Date
    Mybatis 示例之 foreach
    Eclipse不编译解决方案
    Java使用RSA加密解密及签名校验
  • 原文地址:https://www.cnblogs.com/lin7155/p/14385884.html
Copyright © 2011-2022 走看看