单机,主从,哨兵,集群 —— Redis的四种模式

1,160 阅读7分钟

redis 是一款高性能的内存型数据库,广泛应用在当前的各类系统当中。

redis的部署模式主有四种:

  • 单机模式
  • 主从模式
  • 哨兵模式
  • 集群模式

单机模式

物理机上安装一个redis,然后以默认方式启动起来,其实就是单机模式。

这是最简单的部署方式,在不要求高可用的系统中,很多都是采用的这种部署方式

image.png

单机模式部署的优点:

  • 部署简单,0成本。
  • 成本低,没有备用节点,不需要其他的开支。
  • 高性能,单机不需要同步数据,数据天然一致性

同时,单机模式部署也有不少缺点:

  • 可靠性保证不是很好,单节点有宕机的风险。也存在数据丢失的风险。
  • 单机高性能受限于CPU的处理能力,redis是单线程的。

主从模式

类似于MySQL数据库的主从模式,redis的主从复制也是由主节点负责写入,然后复制到各个从节点;主从节点都提供读的能力。

image.png

redis默认情况下都是主节点,在启动时设置参数或者配置文件增加

slaveof <master-ip> <master-port> // 5.0之前
replicaof  <master-ip> <master-port> //5.0之后

可配置成从节点。

一个redis主节点可拥有0个到多个从节点,但从节点只能有1个主节点。

主从复制流程

主从复制指的是将一台Redis主服务器的数据,复制到其他的Redis从服务器;数据的复制是单向的,只能由主节点到从节点。

主从节点之间的第一次数据同步使用的是全量同步,全量同步的流程大致如图

image.png

  • 主从库间建立连接、协商同步: 从库向主库发起同步请求
  • 主库响应请求,返回FULLRESYNC响应命令带上两个参数:主库runID和主库目前的复制进度offset(每个redis启动时)
  • 主库执行bgsave命令,生成 RDB 文件,接着将文件发给从库。从库接收到 RDB 文件后,会先清空当前数据库,然后加载 RDB 文件。
  • 在主库将数据同步给从库的过程中,主库不会被阻塞,仍然可以正常接收请求。但是,这些请求中的写操作并没有记录到刚刚生成的 RDB 文件中。为了保证主从库的数据一致性,主库会在内存中用专门的 replication buffer,记录 RDB 文件生成后收到的所有写操作。当主库完成 RDB 文件发送后,就会把此时 replication buffer 中的修改操作发给从库,从库再重新执行这些操作。这样一来,主从库就实现同步了

对于断开重连后的从节点,2.8后的版本则是采用的增量同步的方式,减少数据量。

总结一下,主从部署模式的好处是:

  • 它可以扩展主节点的读能力,分担主节点读压力。
  • 主从复制还是哨兵模式和集群模式能够实施的基础,因此说主从复制是Redis高可用的基石。

但这种模式的坏处是

  • Redis 主从模式不具备自动容错和恢复功能,如果主节点宕机,Redis 集群将无法工作,此时需要人为干预,将从节点提升为主节点。
  • 如果主机宕机前有一部分数据未能及时同步到从机,即使切换主机后也会造成数据不一致的问题,从而降低了系统的可用性。
  • 因为只有一个主节点,所以其写入能力和存储能力都受到一定程度地限制。
  • 在进行数据全量同步时,若同步的数据量较大可能会造卡顿的现象

哨兵模式(sentinel)

哨兵模式的出现用于解决主从模式中无法自动升级主节点的问题,一个哨兵是一个节点,用于监控主从节点的健康,当主节点挂掉的时候,自动选择一个最优从节点升级为主节点。

image.png

客户端连接Redis,会首先连接Sentinel,通过Sentinel查询master地址,然后再连接master进行数据交互。当master挂了,客户端重新跟Sentinel要master地址,连接新的master。

哨兵模式解决了主从模式需要人工提升主节点的问题,但依然没有突破单机性能的限制。

集群模式

相比于主从模式和哨兵模式,cluster集群模式真正实现了Redis高可用,具有 高可用可扩展性分布式容错 等特性。

下图是集群模式的示意图

image.png

一个redis集群由多个Redis主从节点组成,每一个主从代表一个节点,每个节点负责一部分数据,他们之间通过一种特殊的二进制协议(Gossip)交互集群信息。

数据分片

Redis Cluster会将所有数据分片,分成16384个槽位。

对于来自client的数据,Redis Cluster对key值使用crc16算法进行hash,然后用取模除16384得到具体的槽位,每个节点负责其中一部分槽位。

比如有五套主从节点,每套节点复制的slot则如下所示 image.png

当客户端连接集群,会得到一份集群的槽位匹配信息,当客户端要查找key,可以直接定位到目标节点。

使用这种方式,每套节点存储的数据不同,减少了数据冗余带来的浪费,同时也横向扩展了性能,解决了单机性能的限制。

数据扩容/缩容

这种模式也很容易添加或者删除节点。

如果增加一个节点 6,就需要从节点 1 ~ 5 获得部分槽分配到节点 6 上。

如果想移除节点 1,需要将节点 1 中的槽移到节点 2 ~ 5 上,然后将没有任何槽的节点 1 从集群中移除即可。

添加和删除节点的本质其实是slot迁移,其步骤如下:

  1. 标识 slot 为中间过渡状态(如下图,从节点 A 迁出,则 A 上标slot 为 migrating 状态,迁入到节点 B,则 B上标记 slot 为 importing 状态)
  2. 按照 slot 里的 key 逐个迁移,同步阻塞迁移
    1. A 将 slot 里某个 key发送给 B
    2. B 收到数据后存入本地,回复 OK
    3. A 收到回复 OK 后,删除本地 key image.png

在数据迁移的过程中,redis不会停止服务;

但是在slot迁移过程中,该slot里的key部分在 A 节点,部分在 B 节点,因此 client 的请求处理会发生变化。

  1. client 先访问 slot 对应的旧节点
  2. 若数据还在旧节点,则旧节点正常处理
  3. 若数据已经不在旧节点了,旧节点向 client 返回ask B 重定向令
  4. client 先执行 ask B
  5. client 再执行 get 操作

请求路由

image.png

客户端连接redis集群某个实例时,如果操作的key不在该实例上,会被重定向(Move)到对应的实例去获取结果。

以集群模式登录客户端(注意命令的差别:-c 表示集群模式),则可以清楚的看到“重定向”的信息. 当我们使用直连模式连接某个集群的实例时,有时候也会看到报错 Moved to xxx,此时需要使用集群模式连接。

故障识别

Redis Cluster中每个节点都存有集群中所有节点的信息。它们之间通过互相ping-pong去判断节点是否可以连接。

如果有一半以上的节点去ping一个节点的时候没有回应,集群就认为这个节点宕机。

如果有的主节点挂了,则从节点会自动发起选举,选择新的主节点,然后通知集群其他节点(不需要人工干预或者哨兵)。

同时Cluster是去中心化,由多个节点组成,客户端连接时可以只用一个节点的地址,其余节点可通过该节点自动发现,但如果该节点挂了,就必须手动更换地址,因此连接多个地址安全性更高。(go的客户端好像是根据地址个数判断是否使用集群模式连接)

最后总结一下集群模式的优点

  • 无中心架构,支持动态扩容
  • Cluster自动具备哨兵监控和故障转移(主从切换)能力
  • 客户端连接集群内部地址可自动发现
  • 高性能、高可用,有效解决了Redis分布式需求

缺点

  • 运维复杂
  • 只能使用0号数据库