9.6、开发与运维中的问题

开发与运维中的问题

  1. 故障转移日志分析

    1. Redis Sentinel拓扑结构

      本次故障转移的分析直接使用9.2节的拓扑和配置进行说明,为了方便分析故障转移的过程,下表列出了每个节点的角色、ip、端口、进程号、runId。

      序号 角色 ip 端口 进程号 runId
      1 master 127.0.0.1 6379 19661 d5671ff4160ab3782d61079wbd62ff629aaaf601
      2 slave-1 127.0.0.1 6380 19667 d5671ff4160ab3782d61079wbd62ff629aaaf602
      3 slave-2 127.0.0.1 6381 19685 d5671ff4160ab3782d61079wbd62ff629aaaf603
      4 sentinel-1 127.0.0.1 26379 19697 d5671ff4160ab3782d61079wbd62ff629aaaf604
      5 sentinel-2 127.0.0.1 26380 19707 d5671ff4160ab3782d61079wbd62ff629aaaf605
      6 sentinel-3 127.0.0.1 26381 19713 d5671ff4160ab3782d61079wbd62ff629aaaf606

      因为故障转移涉及节点关系的变化,所以下面说明中用端口号代表节点。

    2. 开始故障转移测试

      模拟故障的方法有很多,比较典型的方法有以下几种:

      • 方法一:强制杀掉对应节点的进程号,这样可以模拟出宕机的效果。

      • 方法二:使用Redis的debug sleep命令,让节点进入睡眠状态,这样可以模拟阻塞的效果。

      • 方法三:使用Redis的shutdown命令,模拟正常的停掉Redis。

      本次我们使用方法一进行测试,因为从实际经验看,数百上千台机器偶尔宕机一两台是会不定期出现的,为了方便分析日志行为,这里记录一下操作的时间和命令。

      用kill -9使主节点的进程宕机,操作时间2016-07-24 09:40:35:

      $ kill -9 19661

    3. 观察效果

      6380节点晋升为主节点,6381节点成为6380节点的从节点。

    4. 故障转移分析

      相信故障转移的效果和预想的一样,这里重点分析相应节点的日志。

      (1)6379节点日志

      两个复制请求,分别来自端口为6380和6381的从节点:

      19661:M 24 Jul 09:22:16.907 * Slave 127.0.0.1:6380 asks for synchronization
      19661:M 24 Jul 09:22:16.907 * Full resync requested by slave 127.0.0.1:6380
      ...
      19661:M 24 Jul 09:22:16.919 * Synchronization with slave 127.0.0.1:6380 succeeded
      19661:M 24 Jul 09:22:23.396 * Slave 127.0.0.1:6381 asks for synchronization
      19661:M 24 Jul 09:22:23.396 * Full resync requested by slave 127.0.0.1:6381
      ...
      19661:M 24 Jul 09:22:23.432 * Synchronization with slave 127.0.0.1:6381 succeeded
      

      09:40:35做了kill -9操作,由于模拟的是宕机效果,所以6379节点没有看到任何日志(这点和shutdown操作不大相同)。

      (2)6380节点日志

      6380节点在09:40:35之后发现它与6379节点已经失联:

      19967:S 24 Jul 09:40:35.788 # Connection with master lost.
      19967:S 24 Jul 09:40:35.788 * Caching the disconnected master state.
      19967:S 24 Jul 09:40:35.974 * Connection to MASTER 127.0.0.1:6379
      19967:S 24 Jul 09:40:35.974 * MASTER <-> SLAVE sync started
      19967:S 24 Jul 09:40:35.975 # Error condition on socket for SYNC: Connection refused
      ...
      

      09:41:06时它接到Sentinel节点的命令:清理原来缓存的主节点状态,Sentinel节点将6380节点晋升为主节点,并重写配置:

      19667:M 24 Jul 09:41:06.161 * Discarding previously cached master state.
      19667:M 24 Jul 09:41:06.161 * MASTER MODE enabled (user request from 'id=7 addr=127.0.0.1:46759 fd=10 name=sentinel-7044753f-cmd age=1111 idle=0 flags=x db=0 sub=0 psub=0 multi=3 qbuf=0 qbuf-free=32768 obl=36 oll=0 omem=0 events=rw cmd=exec')
      19667:M 24 Jul 09:41:06.161 # CONFIG REWRITE executed with success.
      

      6381节点发来了复制请求:

      19667:M 24 Jul 09:41:07.499 * Slave 127.0.0.1:6381 asks for synchronization
      19667:M 24 Jul 09:41:07.499 * Full resync requested by slave 127.0.0.1:6381
      ...
      19667:M 24 Jul 09:41:07.548 * Background saving trminated with success
      19667:M 24 Jul 09:41:07.548 * Synchronization with slave 127.0.0.1:6381 succeeded
      

      (3)6381节点日志

      6381节点同样与6379节点失联:

      19685:S 24 Jul 09:40:35.788 # Connecting with master lost.
      19685:S 24 Jul 09:40:35.788 * Caching the disconneted master state.
      19685:S 24 Jul 09:40:35.425 * Connecting to MASTER 127.0.0.1:6379
      19685:S 24 Jul 09:40:35.425 *MASTER <-> SLAVE sync started
      19685:S 24 Jul 09:40:35.425 * Error condition on socket for SYNC: Connection refused
      ...
      

      后续操作如下:

       1)09:41:06时它接到Sentinel节点的命令,清理原来缓存的主节点状态,让它去复制新的主节点(6380节点)。
      
       2)向新的主节点(6380节点)发起复制操作。
      

      (4)sentinel-1节点日志

      09:41:05对6379节点作了主观下线(+sdown),注意这个时间正好是kill -9后的30秒,和down-after-milliseconds的配置是一直的。Sentinel节点更新自己的配置纪元(new-epoch):

      19697:X 24 Jul 09:41:05.850 # +sdown master mymaster 127.0.0.1 6379
      19697:X 24 Jul 09:41:05.928 # +new-epoch 1
      

      后续操作如下:

       1)投票给sentinel-3节点。
      
       2)更新状态:从sentinel-3节点(领导者)得知:故障转移后6380节点变为主节点,并发现了两个从节点6381和6379,并在30秒后对6379节点做了主观下线。
      

      (5)sentinel-2节点日志

      整个过程和sentinel-1节点是一样的,这里就不占用篇幅分析了。

      (6)sentinel-3节点日志

      从sentinel-1节点和sentinel-2节点的日志来看,sentinel-3节点是领导者,所以分析sentinel-3节点的日志至关重要。

      后续操作如下:

      1)达到客观下线的条件:

      19713:X 24 Jul 09:41:05.854 # +sdown master mymaster 127.0.0.1 6379
      19713:X 24 Jul 09:41:05.909 # +odown master mymaster 127.0.0.1 6379 #quorum 2/2
      19713:X 24 Jul 09:41:05.909 # +new-epoch 1
      

      2)sentinel-3节点被选为领导者:

      19713:X 24 Jul 09:41:05.854 # +try-failover master mymaster 127.0.0.1 6379
      19713:X 24 Jul 09:41:05.911 # +vote-for-leader d5671ff4160ab3782d61079wbd62ff629aaaf606 1
      19713:X 24 Jul 09:41:05.929 # 127.0.0.1:26379 voted for d5671ff4160ab3782d61079wbd62ff629aaaf606 1
      19713:X 24 Jul 09:41:05.929 # 127.0.0.1:26380 voted for d5671ff4160ab3782d61079wbd62ff629aaaf606 1
      19713:X 24 Jul 09:41:05.929 # +elected-leader master mymaster 127.0.0.1 6379
      

      3)故障转移。每一步都可以通过发布订阅来获取,对于每个字段的说明可以参考下表,寻找合适的从节点作为新的主节点:

      19713:X 24 Jul 09:41:06.001 # +failover-state-select-slave master mymaster 127.0.0.1 6379
      

      选出了合适的从节点(6380节点):

      19713:X 24 Jul 09:41:06.077 # +selected-slave slave 127.0.0.1:6380 127.0.0.1 6380 @ mymaster 127.0.0.1 6379
      

      命令6380节点执行slaveof no one,使其成为主节点:

      19713:X 24 Jul 09:41:06.077 # +failover-state-send-slaveof-noone slave 127.0.0.1:6380 127.0.0.1 6380 @ mymaster 127.0.0.1 6379
      

      等待6380节点晋升为主节点:

      19713:X 24 Jul 09:41:06.161 # +failover-state-wait-promotion slave 127.0.0.1:6380 127.0.0.1 6380 @ mymaster 127.0.0.1 6379
      

      确认6380节点已经晋升为主节点:

      19713:X 24 Jul 09:41:06.927 # +promoted-slave slave 127.0.0.1:6380 127.0.0.1 6380 @ mymaster 127.0.0.1 6379
      

      故障转移进入重新配置从节点阶段:

      19713:X 24 Jul 09:41:06.927 # +failover-state-reconfig-slaves master mymaster 127.0.0.1 6379
      

      命令6381节点复制新的主节点:

      19713:X 24 Jul 09:41:07.008 * +slave-reconfig-sent slave 127.0.0.1:6381 127.0.0.1 6381 @ mymaster 127.0.0.1 6379
      

      6381节点正在重新配置成为6380节点的从节点,但是同步过程尚未完成:

      19713:X 24 Jul 09:41:07.955 * +slave-reconfig-inprog slave 127.0.0.1:6381 127.0.0.1 6381 @ mymaster 127.0.0.1 6379
      

      6381节点完成对6380节点的同步:

      19713:X 24 Jul 09:41:07.955 * +slave-reconfig-done slave 127.0.0.1:6381 127.0.0.1 6381 @ mymaster 127.0.0.1 6379
      

      故障转移顺利完成:

      19713:X 24 Jul 09:41:08.045 # +failover-end master mymaster 127.0.0.1 6379
      

      故障转移成功后,发布主节点的切换消息:

      19713:X 24 Jul 09:41:07.008 * +switch-master mymaster 127.0.0.1 6379 127.0.0.1 6380
      

      下表记录了Redis Sentinel在故障转移一些重要的时间消息对应的频道。

      状态 说明
      +reset-master < instance dedatile > 主节点被重置
      +slave < instance dedatile > 一个新的从节点被发现并关联
      +failover-satte-reconf-slaves < instance dedatile > 故障转移进入reconf-slaves状态
      +slave-reconf-sent < instance dedatile > 领导者Sentinel节点命令其他从节点复制新的主节点
      +slave-reconf-improg < instance dedatile > 从节点正在重新配置主节点的slave,但是同步过程尚未完成
      +slave-reconf-done < instance dedatile > 其余从节点完成了和新主节点的同步
      +sentinel < instance dedatile > 一个新的Sentinel节点被发现并关联
      +sdown < instance dedatile > 添加对某个节点被主观下线
      -sdown < instance dedatile > 撤销对某个节点被主观下线
      +odown < instance dedatile > 添加对某个节点被客观下线
      -odown < instance dedatile > 撤销对某个节点被客观下线
      +new-epoch < instance dedatile > 当前纪元被更新
      +try-failover < instance dedatile > 故障转移开始
      +elected-leader < instance dedatile > 选出了故障转移的Sentinel节点
      +failover-state-select-slave < instance dedatile > 故障转移进入select-slave状态(寻找合适的从节点)
      no-good-slave < instance dedatile > 没有找到合适的从节点
      selected-slave < instance dedatile > 找到了合适的从节点
      failover-state-send-slaveof-noone < instance dedatile > 故障转移进入failover-state-send-slaveof-noone状态(对找到的节点执行slaveof no one)
      failover-end-for-timeout < instance dedatile > 故障转移由于超时而终止
      failover-end < instance dedatile > 故障转移顺利完成
      switch-master < master name > < oldop > < oldport > < newip > < newport > 更新主节点信息,这个是许多客户端重点关注的

      < instance dedatile >格式如下:

      <instance-type> <name> <ip> <port> @ <master-name> <master-ip> <master-port>

    5. 注意点

      部署各个节点的机器时间尽量要同步,否则日志的时序性会混乱,例如可以给机器添加NTP服务来同步时间。

  2. 节点运维

    1. 节点下线

      在介绍如何进行节点下线之前,首先需要弄清两个概念:临时下线和永久下线。

      • 临时下线:暂时将节点关掉,之后还会重新启动,继续提供服务。

      • 永久下线:将节点关掉后不再使用,需要做一些清理工作,如删除配置文件、持久化文件、日志文件。

      所以运维人员需要弄清楚本次下线操作是临时下线还是永久下线。

      通常来看,无论是主节点、从节点还是Sentinel节点,下线原因无外乎以下几种:

      • 节点所在的机器出现了不稳定或者即将过保被回收。

      • 节点所在的机器性能比较差或者内存比较小,无法支撑应用方的需求。

      • 节点自身出现服务不正常情况,需要快速处理。

      (1)主节点

       如果需要对主节点进行下线,比较合理的做法是选出一个“合适”(例如性能更高的机器)的从节点,使用sentinel failover功能将从节点晋升为主节点,sentinel failover已经在上一节介绍过了,只需要在任意可用的Sentinel节点执行如下操作即可:
      
       sentinel failover <master name>
      

      (2)从节点和Sentienl节点

       如果需要对从节点或者Sentinel节点进行下线,只需要确定好是临时还是永久下线后执行相应操作即可。如果使用了读写分离,下线从节点需要保证应用方可以感知从节点的下线变化,从而把读取请求路由到其他节点。
      
       需要注意的是,Sentinel节点依然会对这些下线节点进行定期监控,这是由Redis Sentinel的设计思路所决定的。
      
    2. 节点上线

      (1)添加从节点

      添加从节点的场景大致有如下几种:

      • 使用了读写分离,但现有的从节点无法支撑应用方的流量。

      • 主节点没有可用的从节点,无法支持故障转移。

      • 添加一个更强悍的从节点利用手动failover替换主节点。

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

      (2)添加Sentinel节点

      添加Sentinel节点的场景可以分为以下几种:

      • 当前Sentinel节点数量不够,无法达到Redis Sentinel健壮性要求或者无法达到票数。

      • 原Sentinel节点所在机器需要下线。

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

      (3)添加主节点

      因为Redis Sentinel中只能有一个主节点,所以不需要添加主节点,如果需要替换主节点,可以使用Sentinel failover手动故障转移。

    3. 节点配置

      有关Redis数据节点和Sentinel节点配置修改以及优化的方法,前面的张杰已经介绍过了,这里给出Sentinel节点配置时要注意的地方:

      • Sentinel节点配置尽可能一致,这样在判断节点故障时会更加准确。

      • Sentinel节点支持的命令非常有限,例如config命令是不支持的,而Sentinel节点也需要dir、loglevel之类的配置,所以尽量在一开始规划好,不过所幸Sentinel节点不存储数据,如果需要修改配置,重新启动即可。

  3. 高可用读写分离

    1. 从节点的作用

      从节点一般可以起到两个作用,第一,当主节点出现故障时,作为主节点的后备“顶”上来实现故障转移,Redis Sentinel已经实现了该功能的自动化,实现了真正的高可用。第二,扩展主节点的读能力,尤其是在读多写少的场景非常适用。

    2. Redis Sentinel读写分离设计思路

      Redis Sentinel在对各个节点的监控中,如果有对应事件的发生,都会发出相应的事件消息,其中和从节点变动的时间有以下几个:

      • +switch-master:切换主节点(原来的从节点晋升为主节点),说明减少了某个从节点。

      • +convert-to-slave:切换从节点(原来的主节点降级为从节点),说明添加了某个从节点。

      • +sdown:主观下线:说明某个从节点可能不能用(因为对从节点不会做客观下线),所以在实现客户端是可以采用自身策略来实现类似主观下线的功能。

      • +reboot:重新启动了某个节点,如果它的角色是slave,那么说明添加了某个从节点。

      所以在设计Redis Sentinel的从节点高可用时,只要能够实时掌握所有从节点的状态,把所有从节点看做一个资源池,无论是上线还是下线从节点,客户端都能及时感知到(将其从资源池中添加或者删除),这样从节点的高可用目标就达到了。

©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

友情链接更多精彩内容