6. Reids 哨兵,也许是大部分人学习的记录了

143 阅读4分钟

目的

解决redis的高可用问题,

主要通过监听主从服务器,在主服务器宕机的时候,选择一个最合适的从服务器作为主服务器,并在主服务器重启后,将其作为新主的从机

如何操作

  1. 使用redis-sentinel 或者reids-server --sentinel来启动sentinel
  2. 配置需要监听的主服务器ip和端口,可以同时配置多个主服务器
  3. 启动即可
  4. 不需要填写从机信息
  5. 不需要设置其它sentinel信息

sentinel

sentinel 本质上就是redis-server ,但是其redisCommand表包含的命令和普通的redis-server不同,只有subscribe,unsubscribe,ping,psubscribe,punsubscribe,info等查询,订阅相关的命令。

除了拥有redisService结构体信息外,还拥有redisSentinel结构体信息,里面存放在如下信息

struct redisSentinel{
    
    int epoch;//选主纪元,参考分布式一致性算法Rfat
    SentinelRedisInstance * master;//监听的主机列表
    
    
}

struct SentinelRedisInstance {
    char * run_id;
    char *ip;
    int port;
    char* name;
    SentinelRedisInstance *slaves;
    SentinelReidsInstance *sentinels;
    int flags;
    
    
}

学前问题

  1. 只配置了主机,如何获取从机信息?
  2. 可以多个Sentinel可以监听同一主机,那么Sentinel之间如何知晓对方?
  3. 如何判断主机是否真正下线?
  4. 如何选择从机作为主机?选择标准是什么?

具体过程

  1. 启动sentinel,同监视主机建立连接

  2. 以每10s一次的频率发送info给主机,获取主机信息,并从中获取从机信息。然后同才同从机建立连接。

    • 当发现新从机后,会建立对应的connection,并以同样的频率发送info命令,获取从机信息,包括从服务器优先级,复制偏移量等.并添加到对应主机的slaves列表中。
    # Server...run_id:32be0699dd27b410f7c90dada3a6fab17f97899f...
    # Replication
    role:slave
    master_host:127.0.0.1
    master_port:6379
    master_link_status:up
    slave_repl_offset:11887
    slave_priority:100
    # Other sections...
    
  3. 订阅主从服务的__sentinel__:hello频道,并以每2s的频率向订阅频道发送PUBLISH __sentinel__:hello "<s_ip>,<s_port>,<s_runid>,<s_epoch>,<m_name>,<m_ip>,<m_port>,<m_epoch>",其中s开头表示是sentinel自己本身的信息,m开头表示接收消息主机的信息.如此就可以知晓其它sentinel,并将其记录在对应mastersentinels列表。并同其它sentinel 建立连接(那就相当于两个sentinel各自和对方建立一个连接,而不能复用)

  4. 检测主观下线

    • 1s每次的频率向所有建立连接的实例发送ping命令来判断是否在线,
    • 当在down-after-milliseconds内连续收到无效的回复或者指定时间内没返回结果的化,就认为其主观下线,并修改对应SentinelRedisInstance中的flags,新增主观下线标识。
  5. 判断客观下线:

    1. sentinel认定某一实例主机为主观下线后,会向其它同样监听该实例的sentinel发送请求,让其判断是否下线,如果超过 一定数量的话(quorum参数配置),就认为其主观下线

    2. 请求命令为SENTINEL is-master-down-by-addr <ip> <port> <current_epoch> <runid> 其中ip和port 是 主机的ip,port , current_epoch是当前纪元。runid 则为* ,该命令也使用sentinel之间选主。此时runid则等于发送sentinel的runid

    3. 返回内容则为:

      1) <down_state>
      2) <leader_runid> 选主的时候填写,否则为*
      3) <leader_epoch> 选主的时候填写,否则为0
      
  6. 选择领头sentinel来进行故障切换

    • 使用Raft来选主

    • 每一个sentinel 都可以使用sentinel is-master-down-by-addr 发起选主请求。

      • 每一个收到该请求的sentinel
      • 首先判断请求纪元是否和自身纪元相等
      • 如果相等,则返回同意。同时本身纪元+1
      • 如果不相等,则返回不同意。
    • 当超过一半的sentienl同意后,请求的sentinel成为领头sentinel,执行选主操作,否则等待随机时间后,再次进行投票选择

  7. 故障切换

    • 剔除无效的从机

      • 以及客观下线的
      • 最近5s 回复sentinelinfo 请求的(存疑,info 默认是10s发送一次)
      • 于主机断开时间超过down-after-milliseconds*10毫秒的从服务器,保证从机不会过早的于主机断开
      • 从剩余的从机按优先级,复制量,runid(正序)选择候选主机
    • 向候选主机发送slaveof no one

    • 向其它从机发送slaveof newip newport

    • 当主机从新上线后,向其发送slaveof newip newport命令

学后问题

  1. 如果同时向多个主机发送ping?
  2. 如何监听已下线的主机重新上线?猜测使用serverCron
  3. 从机同步新的主机的时候,是不是全量同步?是,因为服务器id 都不相同