zoukankan      html  css  js  c++  java
  • redis-07 redis 集群与扩容

    Redis集群主从同步了解吗?

      主从复制,是指将一台 Redis 服务器的数据,复制到其他的 Redis 服务器。前者称为 主节点(master),后者称为 从节点(slave)。且数据的复制是 单向 的,只能由主节点到从节点。

      Redis 主从复制支持 主从同步从从同步 两种,后者是 Redis 后续版本新增的功能,以减轻主节点的同步负担。

     主从复制主要作用

    • 数据冗余: 主从复制实现了数据的热备份,是持久化之外的一种数据冗余方式。
    • 故障恢复: 当主节点出现问题时,可以由从节点提供服务,实现快速的故障恢复 (实际上是一种服务的冗余)
    • 负载均衡: 在主从复制的基础上,配合读写分离,可以由主节点提供写服务,由从节点提供读服务 (即写 Redis 数据时应用连接主节点,读 Redis 数据时应用连接从节点),分担服务器负载。尤其是在写少读多的场景下,通过多个从节点分担读负载,可以大大提高 Redis 服务器的并发量。
    • 高可用基石: 除了上述作用以外,主从复制还是哨兵和集群能够实施的 基础,因此说主从复制是 Redis 高可用的基础。

     实现原理  

      

      主要的步骤都 浓缩 在了上图中,其实也可以 简化成三个阶段:准备阶段-数据同步阶段-命令传播阶段

    Redis 哨兵模式了解吗?

      

      上图 展示了一个典型的哨兵架构图,它由两部分组成,哨兵节点和数据节点

        哨兵节点: 哨兵系统由一个或多个哨兵节点组成,哨兵节点是特殊的 Redis 节点,不存储数据;

        数据节点: 主节点和从节点都是数据节点;

      在复制的基础上,哨兵实现了 自动化的故障恢复 功能,下方是官方对于哨兵功能的描述:

        监控(Monitoring): 哨兵会不断地检查主节点和从节点是否运作正常。

        自动故障转移(Automatic failover):主节点 不能正常工作时,哨兵会开始 自动故障转移操作,它会将失效主节点的其中一个 从节点升级为新的主节点,并让其他从节点改为复制新的主节点。

        配置提供者(Configuration provider): 客户端在初始化时,通过连接哨兵来获得当前 Redis 服务的主节点地址。

        通知(Notification): 哨兵可以将故障转移的结果发送给客户端。

      其中,监控和自动故障转移功能,使得哨兵可以及时发现主节点故障并完成转移。而配置提供者和通知功能,则需要在与客户端的交互中才能体现。

     新主节点是怎么挑选出来的?

      故障转移操作的第一步 要做的就是在已下线主服务器属下的所有从服务器中,挑选出一个状态良好、数据完整的从服务器,然后向这个从服务器发送 slaveof no one 命令,将这个从服务器转换为主服务器。但是这个从服务器是怎么样被挑选出来的呢?

      简单来说 Sentinel 使用以下规则来选择新的主服务器:

        1. 在失效主服务器属下的从服务器当中, 那些被标记为:主观下线、已断线、或者最后一次回复 PING 命令的时间 > 5s 的从服务器都会被 淘汰

        2. 在失效主服务器属下的从服务器当中, 那些与失效主服务器连接断开的时长超过 down-after 选项指定的时长十倍的从服务器都会被 淘汰

        3. 在 经历了以上两轮淘汰之后 剩下来的从服务器中, 有两个决策条件:

          <1. 我们选出 复制偏移量(replication offset)最大 的那个 从服务器 作为新的主服务器;

          <2. 如果复制偏移量不可用,或者从服务器的复制偏移量相同,那么 带有最小运行 ID 的那个从服务器成为新的主服务器。

    Redis集群使用过吗?原理?

      

      上图 展示了 Redis Cluster 典型的架构图,集群中的每一个 Redis 节点都 互相两两相连,客户端任意 直连 到集群中的 任意一台,就可以对其他 Redis 节点进行 读写 的操作。

     基本原理

        

      Redis 集群中内置了 16384 个哈希槽。当客户端连接到 Redis 集群之后,会同时得到一份关于这个 集群的配置信息,当客户端具体对某一个 key 值进行操作时,会计算出它的一个 Hash 值,然后把结果对 16384 求余数,这样每个 key 都会对应一个编号在 0-16383 之间的哈希槽,Redis 会根据节点数量 大致均等 的将哈希槽映射到不同的节点。

      再结合集群的配置信息就能够知道这个 key 值应该存储在哪一个具体的 Redis 节点中,如果不属于自己管,那么就会使用一个特殊的 MOVED 命令来进行一个跳转,告诉客户端去连接这个节点以获取数据:

    GET x
    -MOVED 3999 127.0.0.1:6381

      MOVED 指令第一个参数 3999key 对应的槽位编号,后面是目标节点地址,MOVED 命令前面有一个减号,表示这是一个错误的消息。客户端在收到 MOVED 指令后,就立即纠正本地的 槽位映射表,那么下一次再访问 key 时就能够到正确的地方去获取了。

     集群的主要作用

    • 数据分区: 数据分区 (或称数据分片) 是集群最核心的功能。集群将数据分散到多个节点,一方面 突破了 Redis 单机内存大小的限制,存储容量大大增加另一方面 每个主节点都可以对外提供读服务和写服务,大大提高了集群的响应能力。Redis 单机内存大小受限问题,在介绍持久化和主从复制时都有提及,例如,如果单机内存太大,bgsavebgrewriteaoffork 操作可能导致主进程阻塞,主从环境下主机切换时可能导致从节点长时间无法提供服务,全量复制阶段主节点的复制缓冲区可能溢出……(相关知识点可参考我的博客:redis-05 redis 持久化AOF&RDB
    • 高可用: 集群支持主从复制和主节点的 自动故障转移 (与哨兵类似),当任一节点发生故障时,集群仍然可以对外提供服务。对应底层通讯是什么才能保证相应的高可用呢?请往下看对应的节点之间的通信机制。

    集群中数据如何分区?以及新增或删除节点怎么进行数据迁移的?

      首先先将结论抛出来:Redis 采用方案三。这个我觉得应该也是 redis 大佬们经过多种方案对比后所采用的最合理的方案。

     方案一:哈希值%节点数

      哈希取余分区思路非常简单:计算 key 的 hash 值,然后对节点数量进行取余,从而决定数据映射到哪个节点上。

      不过该方案最大的问题是,当新增或删减节点时,节点数量发生变化,系统中所有的数据都需要 重新计算映射关系,引发大规模数据迁移。

     方案二:一致性哈希分区

      一致性哈希算法将 整个哈希值空间 组织成一个虚拟的圆环,范围是 [0 - 232 - 1],对于每一个数据,根据 key 计算 hash 值,得到数据在环上的位置,然后从此位置沿顺时针行走,找到的第一台服务器就是其应该映射到的服务器,具体原理图如下:

      

      与哈希取余分区相比,一致性哈希分区将 增减节点的影响限制在相邻节点。以上图为例,如果在 node1node2 之间增加 node5,则只有 node2 中的一部分数据会迁移到 node5;如果去掉 node2,则原 node2 中的数据只会迁移到 node4 中,只有 node4 会受影响。

      一致性哈希分区的主要问题在于,当 节点数量较少 时,增加或删减节点,对单个节点的影响可能很大,造成数据的严重不平衡。还是以上图为例,如果去掉 node2node4 中的数据由总数据的 1/4 左右变为 1/2 左右,与其他节点相比负载过高。

     方案三:带有虚拟节点的一致性哈希分区

      该方案在 一致性哈希分区的基础上引入了 虚拟节点 的概念。Redis 集群使用的便是该方案,其中的虚拟节点称为 槽(slot)。槽是介于数据和实际节点之间的虚拟概念,每个实际节点包含一定数量的槽,每个槽包含哈希值在一定范围内的数据。

      在使用了槽的一致性哈希分区中,槽是数据管理和迁移的基本单位 解耦 数据和实际节点 之间的关系,增加或删除节点对系统的影响很小。仍以上图为例,系统中有 4 个实际节点,假设为其分配 16 个槽 (0-15);

    • 槽 0-3 位于 node1;4-7 位于 node2;以此类推....

      如果此时删除 node2只需要将槽 4-7 重新分配即可,例如槽 4-5 分配给 node1槽 6 分配给 node3槽 7 分配给 node4;可以看出删除 node2 后,数据在其他节点的分布仍然较为均衡。

    节点之间的通信机制了解吗?

      集群的建立离不开节点之间的通信,集群之间的两两连接是通过了 CLUSTER MEET <ip> <port> 命令发送 MEET 消息完成的,下面我们展开详细说说。

     两个端口

      在 哨兵系统 中,节点分为 数据节点哨兵节点:前者存储数据,后者实现额外的控制功能。

      在 集群 中,没有数据节点与非数据节点之分:所有的节点都存储数据,也都参与集群状态的维护

      为此,集群中的每个节点,都提供了两个 TCP 端口:
      • 普通端口: 即普遍我们使用的端口 (如 6379 等)。普通端口主要用于为客户端提供服务 (与单机节点类似);但在节点间数据迁移时也会使用。
      • 集群端口: 端口号是普通端口 + 10000 (10000是固定值,无法改变),如 7000 节点的集群端口为 17000集群端口只用于节点之间的通信,如搭建集群、增减节点、故障转移等操作时节点间的通信;不要使用客户端连接集群接口。为了保证集群可以正常工作,在配置防火墙时,要同时开启普通端口和集群端口。

     Gossip 协议

      节点间通信,按照通信协议可以分为几种类型:单对单、广播、Gossip 协议等。重点是 广播 和 Gossip 的对比。

      • 广播是指向集群内所有节点发送消息。优点 是集群的收敛速度快 (集群收敛是指集群内所有节点获得的集群信息是一致的),缺点 是每条消息都要发送给所有节点,CPU、带宽等消耗较大。

      • Gossip 协议的特点是:在节点数量有限的网络中,每个节点都 “随机” 的与部分节点通信 (并不是真正的随机,而是根据特定的规则选择通信的节点),经过一番杂乱无章的通信,每个节点的状态很快会达到一致。Gossip 协议的 优点 有负载 (比广播) 低、去中心化、容错性高 (因为通信有冗余) 等;缺点 主要是集群的收敛速度慢。

     消息类型有哪些,你知道吗?

      集群中的节点采用 固定频率(每秒10次)定时任务 进行通信相关的工作:判断是否需要 发送消息 及 消息类型、确定接收节点、发送消息等。如果集群状态发生了变化,如增减节点、槽状态变更,通过节点间的通信,所有节点会很快得知整个集群的状态,使集群收敛。

      节点间发送的消息主要分为 5 种:meet 消息ping 消息pong 消息fail 消息publish 消息。不同的消息类型,通信协议、发送的频率和时机、接收节点的选择等是不同的:

    • MEET 消息: 在节点握手阶段,当节点收到客户端的 CLUSTER MEET 命令时,会向新加入的节点发送 MEET 消息,请求新节点加入到当前集群;新节点收到 MEET 消息后会回复一个 PONG 消息。

    • PING 消息: 集群里每个节点每秒钟会选择部分节点发送 PING 消息,接收者收到消息后会回复一个 PONG 消息。PING 消息的内容是自身节点和部分其他节点的状态信息,作用是彼此交换信息,以及检测节点是否在线。PING 消息使用 Gossip 协议发送,接收节点的选择兼顾了收敛速度和带宽成本,具体规则如下:(1)随机找 5 个节点,在其中选择最久没有通信的 1 个节点;(2)扫描节点列表,选择最近一次收到 PONG 消息时间大于 cluster_node_timeout / 2 的所有节点,防止这些节点长时间未更新。

    • PONG消息: PONG 消息封装了自身状态数据。可以分为两种:第一种 是在接到 MEET/PING 消息后回复的 PONG 消息;第二种 是指节点向集群广播 PONG 消息,这样其他节点可以获知该节点的最新信息,例如故障恢复后新的主节点会广播 PONG 消息。

    • FAIL 消息: 当一个主节点判断另一个主节点进入 FAIL 状态时,会向集群广播这一 FAIL 消息;接收节点会将这一 FAIL 消息保存起来,便于后续的判断。

    • PUBLISH 消息: 节点收到 PUBLISH 命令后,会先执行该命令,然后向集群广播这一消息,接收节点也会执行该 PUBLISH 命令。

      
     
  • 相关阅读:
    禁止root远程登录解决办法
    小肥羊
    高级英语
    通用做饭general
    2021/03/10,创新与毁灭
    pandaExpressRound2
    2021/03/08,经历建立的你
    系统与细节
    报税
    事业portfolio
  • 原文地址:https://www.cnblogs.com/liang1101/p/12920585.html
Copyright © 2011-2022 走看看