集群原理

集群主要解决两个问题

  • 数据同步
  • 集群容错

    Navie方案

  • 简单粗暴

  • 部署多台一模一样的Redis服务,使用负载均衡分摊压力及监控服务状态

    优势

  • 容错简单,只要有一台存活,整个集群就可用

    不足

  • 为了保证数据一致,需要大量的数据同步

  • 影响性能和稳定性

    Redis集群方案

  • 基于分而治之的思想

  • 将Key按照某种规则划分成多个分区,将不同的分区存放在不同的节点上
  • 使用哈希算法(CRC16(key) mod 16383)将key映射到16384个slot上
  • 每个节点负责一定范围的slot,所有节点组成的集群覆盖了所有的slot
  • CRC16算法简化了扩缩容时数据分片和迁移的难度,节点只需要维护自身和slot的映射关系

    架构优化

  • slave节点冗余备份master节点,高峰时可以提供读能力

  • 由于key映射到slot的算法是固定公开的,客户端内部维护key到slot的映射关系,找到正确的节点,减少MOVED重定向
  • 节点通信公共Gossip协议实现最终一致性
  • 节点下线
    • 主观下线 pfail:节点A在cluster-node-timeout时间内和节点B的ping/pong消息失败,A主观标记B下线,并将状态消息传播给集群内其他节点
    • 客观下线 fail:当集群内多数master节点标记他为主观下线后,触发客观下线
  • 故障恢复

    • 一个持有slot的master节点客观下线后,集群会从slave中选出一个提升为master
    • 使用选举-投票的算法来挑选master
    • 一个slave必须必须获得多数的master节点的投票后才能被提升
    • 默认情况下如果有一个master节点不可用则整个集群则不可用,可以配置cluster-require-full-coverage为no,则某个master节点故障时则只影响他负责的slot,其他slot数据正常提供服务

      搭建集群

      启动新节点

  • 修改配置文件后以集群模式启动新节点

    1. # 开启集群模式
    2. cluster-enabled yes
    3. # 节点超时时间,单位毫秒
    4. cluster-node-timeout 15000
    5. # 集群节点信息文件
    6. cluster-config-file "nodes-6379.conf"

    发送meet消息

  • 使用客户端发起命令cluster IP PORT,节点会发送meet消息将IP和PORT加入集群

meet.png

分配slot

  • 加入集群后得到“空”集群,把slot分配给master
  • cluster add addslots {<a>...<b>} 将a-b的slot都分配给节点
  • cluster nodes 查看各个节点负责的slot,以及节点ID
  • cluster replicate <nodeId> 将该节点分配为指定的master节点的备份

    命令直接创建集群

    ```

    redis 5

    redis-cli —cluster create 127.0.0.1:7000 127.0.0.1:7001 \ 127.0.0.1:7002 127.0.0.1:7003 127.0.0.1:7004 127.0.0.1:7005 \ —cluster-replicas 1

旧版本

./redis-trib.rb create —replicas 1 127.0.0.1:7000 127.0.0.1:7001 \ 127.0.0.1:7002 127.0.0.1:7003 127.0.0.1:7004 127.0.0.1:7005 ```

集群伸缩

扩容

  • 扩容操作与创建集群操作类似,不同的在于最后一步是将slot从已有的节点迁移到新的节点
  • 启动新节点,同创建集群
  • 将新节点加入到集群:使用redis-cli --cluster add-node命令将新节点加入集群(内部meet消息)
  • 迁移slot和数据:使用redis-cli --cluster reshard进行slot迁移
  • 旧版本使用./redis-trib.rb命令

    收缩

  • 为了安全删除节点,Redis集群只能下线没有slot的节点

  • 迁移slot和数据:使用redis-cli --cluster reshard进行slot迁移
  • 下线节点:使用redis-cli --cluster del-node删除节点(内部forget消息)
  • 旧版本使用./redis-trib.rb命令

    持久化

    RDB

  • 即使设置了save ""视图关闭RDB,但还是可能会触发

  • 执行shutdown时,如果没有开启AOF,也会触发RDB持久化
  • 不管save如何配置,只要RDB文件存在,redis启动时就会去加载该文件

    AOF