Redis 集群详解:主从哨兵和切片集群有什么区别

引言

Redis 集群主要有两种形态:

  • 主从哨兵,用来保障高可用
  • 切片集群,用来实现水平扩展

前者通过哨兵监控与自动切换解决单点故障问题,后者基于哈希槽机制把数据分散到多个实例上,并通过重定向机制应对节点和槽位关系变化。

本文主要梳理这两种方案的核心设计,以及它们在定位目标上的差异。

Redis 两种集群方式

Redis 常见的集群方式主要有两种:

  1. 主从集群
  2. 切片集群

主从集群

主从集群中:

  • 主节点负责读写操作
  • 从节点主要负责复制主节点数据,提供数据备份能力

在常规主从模式下,从节点通常不负责自动选主,因此如果主节点宕机,集群本身并不能自动完成故障恢复。

哨兵模式

哨兵模式可以理解为主从集群的一种升级。

它的作用主要是:

  • 监控主节点和从节点状态
  • 在主节点宕机后帮助完成自动选主

因此,哨兵模式重点解决的是:

  • 高可用问题

但哨兵模式本身并不解决数据水平扩展问题,也不支持像切片集群那样基于数据分布做在线扩容。

切片集群

切片集群采用哈希槽来处理数据和实例之间的映射关系。

一个 Redis Cluster 集群一共有:

  • 16384 个哈希槽

这些哈希槽可以理解成一组固定编号的数据分区。每个键值对都会根据它的 key,被映射到其中一个哈希槽上,然后由负责该槽的实例来存储和处理这个 key。

所以切片集群重点解决的是:

  • 数据水平扩展问题

切片集群中的槽分布

在部署 Redis Cluster 方案时,可以使用 cluster create 命令创建集群。

创建完成后,Redis 会把 16384 个槽尽量平均分布在多个主节点实例上。

例如:

  • 如果集群中有 N 个主节点实例
  • 那么每个实例大致会负责 16384 / N 个槽

这样一来,数据就被切分到了不同实例中,实现了横向扩展。

切片集群中的从节点作用

在 Redis Cluster 模式下,从节点依然存在,但它的角色是:

  • 作为主节点的备用副本
  • 复制主节点数据
  • 在主节点故障时参与故障转移

默认情况下,从节点本身不承担正常读写服务,也不是主要的数据访问入口。

所以切片集群里:

  • 主节点负责槽和数据
  • 从节点负责冗余和故障恢复

哈希槽映射过程是怎样的

Redis Cluster 中,一个 key 会映射到哪个实例,本质上要先经过"key -> 槽"的映射。

这个过程通常分为两步:

  1. 先根据 key 计算哈希值
  2. 再根据哈希值映射到某个槽

更具体地说:

  1. Redis 会对 key 按照 CRC16 算法计算出一个 16 bit 的值
  2. 再用这个值对 16384 取模
  3. 最终得到一个 0 ~ 16383 范围内的数字

这个数字就代表该 key 所属的哈希槽编号。

所以:

  • key 先映射到槽
  • 槽再映射到实例

这就是 Redis Cluster 的基本数据定位方式。

切片集群客户端如何定位数据

客户端和 Redis Cluster 实例建立连接后,需要知道:

  • 哪些哈希槽归哪个实例负责

Redis Cluster 会在实例之间传播哈希槽分配信息,因此各个实例都会保存整个集群的槽位映射关系。

当客户端连接某个实例后,这个实例也会把对应的槽分布信息返回给客户端。这样客户端本地就会缓存:

  • 槽 -> 实例

的映射关系。

之后,客户端在发送请求时,就可以根据 key 所属槽,直接把命令发往正确实例。

实例和哈希槽关系变更后,客户端如何定位数据

Redis Cluster 提供了重定向机制来解决这个问题。

所谓"重定向",就是:

  • 客户端把请求发给了一个实例
  • 但这个实例并不负责该 key 所在的槽
  • 于是实例告诉客户端应该去找哪一个新实例

客户端再根据返回结果,重新发起请求。

这种机制主要出现在:

  • 集群扩容
  • 集群缩容
  • 哈希槽迁移
  • 槽重新均衡

等场景下。

常见的变更原因

实例与哈希槽对应关系发生变化,通常有两个常见原因:

  1. 集群新增或删除实例,需要重新分配槽
  2. 为了做负载均衡,需要在多个实例之间重新分布哈希槽

也就是说,只要槽位归属发生变化,客户端原来缓存的槽位映射信息就可能失效。

重定向机制

Redis Cluster 常见的重定向主要有两种:

  1. MOVED
  2. ASK

它们虽然都表示"你要去别处访问",但语义并不一样。

全部迁移:MOVED

如果某个槽的数据已经全部迁移完成,那么客户端再访问旧实例时,旧实例会返回:

  • MOVED

例如:

text 复制代码
GET hello:key
(error) MOVED 13320 172.16.19.5:6379

这表示:

  • 13320 已经正式迁移到 172.16.19.5:6379

客户端收到 MOVED 后,需要做两件事:

  1. 把这次请求重新发到新的实例
  2. 更新本地缓存中的"槽 -> 实例"映射关系

所以 MOVED 的含义是:

  • 槽的归属已经正式改变了
  • 后续请求都应该发往新实例

部分迁移:ASK

如果某个槽还处于迁移过程中,那么客户端访问旧实例时,可能会收到:

  • ASK

例如:

text 复制代码
GET hello:key
(error) ASK 13320 172.16.19.5:6379

这通常意味着:

  • 这个槽并没有完全迁移完成
  • 只是当前访问的这个 key,已经被迁移到了新实例

此时客户端需要:

  1. 先向新实例发送 ASKING
  2. 再把真正的操作命令发给新实例

但要注意:

  • 客户端不会更新本地缓存中的槽位映射关系

因为 ASK 只表示一次临时重定向,而不是槽归属已经永久变化。

ASK 和 MOVED 的区别

这两个命令最核心的区别在于:

MOVED

  • 表示槽已经完成迁移
  • 客户端需要更新本地槽位缓存
  • 后续请求都要发往新实例

ASK

  • 表示槽还在迁移过程中
  • 客户端只需要临时把这一次请求发往新实例
  • 不更新本地槽位缓存

所以可以简单记忆为:

  • MOVED 是永久重定向
  • ASK 是临时重定向

主从哨兵和切片集群怎么选

可以从目标上直接区分:

主从哨兵

更适合解决:

  • 单点故障
  • 自动故障切换
  • 高可用问题

切片集群

更适合解决:

  • 单机内存不足
  • 单机吞吐不够
  • 需要水平扩展

因此两者并不是简单替代关系,而是:

  • 哨兵偏高可用
  • 切片偏可扩展

总结

这篇文章可以压缩成几条核心结论:

  1. Redis 集群常见有两种方式:主从哨兵和切片集群
  2. 主从哨兵主要解决高可用问题,切片集群主要解决水平扩展问题
  3. Redis Cluster 使用 16384 个哈希槽实现 key 到实例的映射
  4. key 先通过 CRC16 计算,再对 16384 取模,确定所属槽
  5. 客户端通过缓存槽位映射关系来定位数据
  6. MOVED 表示槽已经正式迁移完成,客户端需要更新缓存
  7. ASK 表示槽仍在迁移中,只做一次临时重定向

理解 Redis 集群,关键不是只记住"有哨兵"和"有哈希槽",而是要看清它们分别解决的是哪一类问题。


如果这篇文章对你有帮助,欢迎继续阅读本系列后续内容。若文中有不准确或需要补充的地方,也欢迎指出。

相关推荐
杰克尼2 小时前
redis(day08-Redis原理篇)
数据库·redis·php
余佬学数据库2 小时前
Oracle 19c RECOVER TABLE 恢复误删除数据
数据库·oracle
Dream of maid2 小时前
Mysql(6)关联查询
数据库·mysql
lonelyhiker2 小时前
cas学习笔记
数据库·笔记·学习
云淡风轻~窗明几净2 小时前
ubuntu的lazarus的Tline/TeaLine组件的构思
linux·数据库·ubuntu
雒珣2 小时前
Qt实现命令行参数功能示例:QCommandLineParser
开发语言·数据库·qt
知识分享小能手2 小时前
MongoDB入门学习教程,从入门到精通,MongoDB备份完全指南(23)
数据库·学习·mongodb
小高0072 小时前
🔥前端性能内卷终点?Signals 正在重塑我们的开发习惯
前端·javascript·vue.js
源来猿往2 小时前
mysql转postgresql【平移】
数据库·mysql·postgresql