🙊
关于作者
  • 个人简历
  • 联系作者
  • 运维日常记录
    • RAID 磁盘阵列
    • MBR 与 GPT 分区
    • Linux 命令行判断GPT和MBR分区
    • CentoS 7 系统 扩容根分区
  • Linux运维学习笔记
    • 计算机网络基础知识
    • Linux 系统启动过程
    • Linux 命令基本格式
    • Linux 文件删除原理
    • Linux 目录结构说明
    • Linux 查看命令帮助信息
    • Linux Yum 命令
    • Linux Apt 命令
  • Linux 运维管理
    • Linux 硬件管理
    • Linux 软件管理
    • Linux 磁盘管理
    • Linux 系统管理
    • Linux 网络管理
    • Linux 用户和组管理
    • Linux 文件与目录管理
    • Linux 文件压缩与解压缩管理
    • Linux SSL证书自动更新管理
  • 运维环境搭建
    • CentOS 7 安装与优化
    • CentOS 安装高版本Node.js
    • CentOS 升级安装Python2.7.X
    • CentOS 安装 Python3.8.X
    • CentOS 安装 PHP7.4.X
    • CentOS 安装 Mysql 8.0
    • CentOS 安装 Zabbix 5.0
    • Windows Server 部署 IIS
    • Cronsun 任务管理器部署
    • Teltport 堡垒机部署
    • Jump Server 堡垒机搭建及使用
    • CI & CD 持续集成部署
    • ELK6.5.0+Filebeat 日志系统部署
    • Lustre 分布式并行文件系统部署
  • 系统安全加固
    • Linux 操作系统加固
    • Windows 操作系统安全加固
    • Password 安全加固
    • OpenSSL 安全加固
    • NFS 服务安全加固
    • Rsync 服务安全加固
    • IIS 服务安全加固
    • PHP 语言环境安全加固
    • Apache 服务安全加固
    • Nginx 服务安全加固
    • Tomcat 服务安全加固
    • MySQL 服务安全加固
    • PostgreSQL 服务安全加固
    • Redis 服务安全加固
    • MongoDB 服务安全加固
    • 暴力破解攻击和防御
  • 云原生运维教程
    • Docker 理论
    • Docker 基本架构
    • Docker 基本概念
    • Docker 基本使用
      • 容器
      • 镜像
      • 仓库
    • Docker 存储
    • Docker 网络
    • Docker 安装
  • Linux 系统故障排查
    • Linux 系统重置密码方法
    • Linux 系统误操作修改目录权限为 777 修复方法
  • Windows 系统故障排查
    • Windows 和 Windows Server 中启用/禁用 SMBv1、SMBv2 和 SMBv3
    • Windows10建立映射网络驱动器报错,无法挂载共享文件系统,解决办法
  • 运维工具使用
    • 常用 Git 命令简介及使用
    • 常用 SVN 命令简介及使用
    • 常用 Vi / Vim 文本编辑工具简介及使用
    • 国内常用加速源使用及配置
    • 软碟通制作U启动和再生龙恢复Linux系统及备份
    • 常用JetBrains系列IDE快捷键
  • 中间件教程学习
    • Nginx 极简教程
    • Nginx 安装
    • Nginx 配置
    • Nginx 问题集
    • Mysql 教程
    • Mysql 运维
    • Mysql 原理
    • Redis 教程
    • Redis 持久化
    • Redis 复制
    • Redis 哨兵
    • Redis 集群
    • Redis 运维
    • PostgreSQL 教程
    • H2 教程
    • SqLite 教程
    • 数据库中间件 flyway
  • Nginx 入门教程
  • MySQL 入门教程
  • Nosql 数据库
  • 常用工具快捷键
    • Windows10常用快捷键大全
  • Group 1
由 GitBook 提供支持
在本页
  • Redis 集群方案
  • 客户端分区方案
  • 代理分区方案
  • 查询路由方案
  • Redis 集群的限制
  • 数据分区
  • 分区策略
  • 集群节点
  • 判断槽是否由当前节点负责处理
  • MOVED 错误
  • 集群高可用
  • 重新分片
  • ASK 错误
  • 复制
  • 故障检测
  • 故障转移
  • 选举新的主节点
  • Redis 集群配置
  • 重点
  • 参考资料

这有帮助吗?

  1. 中间件教程学习

Redis 集群

上一页Redis 哨兵下一页Redis 运维

最后更新于5年前

这有帮助吗?

是 Redis 提供的分布式数据库方案。

既然是分布式,自然具备分布式系统的基本特性:可扩展、高可用、一致性。

  • Redis 集群通过划分 hash 槽来分片,进行数据分享。

  • Redis 集群采用主从模型,提供复制和故障转移功能,来保证 Redis 集群的高可用。

  • 根据 CAP 理论,Consistency、Availability、Partition tolerance 三者不可兼得,而 Redis 集群的选择是 AP。Redis 集群节点间采用异步通信方式,不保证强一致性,尽力达到最终一致性。

Redis 集群方案

客户端分区方案

客户端 就已经决定数据会被 存储 到哪个 redis 节点或者从哪个 redis 节点 读取数据。其主要思想是采用 哈希算法 将 Redis 数据的 key 进行散列,通过 hash 函数,特定的 key会 映射 到特定的 Redis 节点上。

客户端分区方案 的代表为 Redis Sharding,Redis Sharding 是 Redis Cluster 出来之前,业界普遍使用的 Redis 多实例集群 方法。Java 的 Redis 客户端驱动库 Jedis,支持 Redis Sharding 功能,即 ShardedJedis 以及 结合缓存池 的 ShardedJedisPool。

  • 优点

不使用 第三方中间件,分区逻辑 可控,配置 简单,节点之间无关联,容易 线性扩展,灵活性强。

  • 缺点

客户端 无法 动态增删 服务节点,客户端需要自行维护 分发逻辑,客户端之间 无连接共享,会造成 连接浪费。

代理分区方案

客户端 发送请求到一个 代理组件,代理 解析 客户端 的数据,并将请求转发至正确的节点,最后将结果回复给客户端。

  • 优点:简化 客户端 的分布式逻辑,客户端 透明接入,切换成本低,代理的 转发 和 存储 分离。

  • 缺点:多了一层 代理层,加重了 架构部署复杂度 和 性能损耗。

代理分区 主流实现的有方案有 Twemproxy 和 Codis。

Twemproxy

Twemproxy 也叫 nutcraker,是 twitter 开源的一个 redis 和 memcache 的 中间代理服务器 程序。Twemproxy 作为 代理,可接受来自多个程序的访问,按照 路由规则,转发给后台的各个 Redis 服务器,再原路返回。Twemproxy 存在 单点故障 问题,需要结合 Lvs 和 Keepalived 做 高可用方案。

  • 优点:应用范围广,稳定性较高,中间代理层 高可用。

  • 缺点:无法平滑地 水平扩容/缩容,无 可视化管理界面,运维不友好,出现故障,不能 自动转移。

Codis

Codis 是一个 分布式 Redis 解决方案,对于上层应用来说,连接 Codis-Proxy 和直接连接 原生的 Redis-Server 没有的区别。Codis 底层会 处理请求的转发,不停机的进行 数据迁移 等工作。Codis 采用了无状态的 代理层,对于 客户端 来说,一切都是透明的。

  • 优点

实现了上层 Proxy 和底层 Redis 的 高可用,数据分片 和 自动平衡,提供 命令行接口 和 RESTful API,提供 监控 和 管理 界面,可以动态 添加 和 删除 Redis 节点。

  • 缺点

部署架构 和 配置 复杂,不支持 跨机房 和 多租户,不支持 鉴权管理。

查询路由方案

客户端随机地 请求任意一个 Redis 实例,然后由 Redis 将请求 转发 给 正确 的 Redis 节点。Redis Cluster 实现了一种 混合形式 的 查询路由,但并不是 直接 将请求从一个 Redis 节点 转发 到另一个 Redis 节点,而是在 客户端 的帮助下直接 重定向( redirected)到正确的 Redis 节点。

  • 优点

无中心节点,数据按照 槽 存储分布在多个 Redis 实例上,可以平滑的进行节点 扩容/缩容,支持 高可用 和 自动故障转移,运维成本低。

  • 缺点

严重依赖 Redis-trib 工具,缺乏 监控管理,需要依赖 Smart Client (维护连接,缓存路由表,MultiOp 和 Pipeline 支持)。Failover 节点的 检测过慢,不如 中心节点 ZooKeeper 及时。Gossip 消息具有一定开销。无法根据统计区分 冷热数据。

Redis 集群的限制

Redis 集群相对 单机 在功能上存在一些限制,需要 开发人员 提前了解,在使用时做好规避。

  • key 批量操作 支持有限。

类似 mset、mget 操作,目前只支持对具有相同 slot 值的 key 执行 批量操作。对于 映射为不同 slot 值的 key 由于执行 mget、mget 等操作可能存在于多个节点上,因此不被支持。

  • key 事务操作 支持有限。

只支持 多 key 在 同一节点上 的 事务操作,当多个 key 分布在 不同 的节点上时 无法 使用事务功能。

  • key 作为 数据分区 的最小粒度

不能将一个 大的键值 对象如 hash、list 等映射到 不同的节点。

  • 不支持 多数据库空间

单机 下的 Redis 可以支持 16 个数据库(db0 ~ db15),集群模式 下只能使用 一个 数据库空间,即 db0。

  • 复制结构 只支持一层

从节点 只能复制 主节点,不支持 嵌套树状复制 结构。

数据分区

分区策略

分布式存储需要解决的首要问题是把 整个数据集 按照 分区规则 映射到 多个节点 的问题,即把 数据集 划分到 多个节点 上,每个节点负责 整体数据 的一个 子集。

Redis 集群通过划分 hash 槽来将数据分区。

整个 redis 集群有 16384 个哈希槽,决定一个 key 应该分配到那个槽的算法是:计算该 key 的 CRC16 结果再模 16834。

集群中的每个节点负责一部分哈希槽,比如集群中有3个节点,则:

  • 节点A存储的哈希槽范围是:0 – 5500

  • 节点B存储的哈希槽范围是:5501 – 11000

  • 节点C存储的哈希槽范围是:11001 – 16384

注意

  • 如果数据库中有任何一个槽没有得到处理,那么集群处于下线状态。

集群节点

集群节点保存键值对以及过期时间的方式与单机 Redis 服务完全相同。

Redis 集群节点分为主节点(master)和从节点(slave),其中主节点用于处理槽,而从节点则用于复制某个主节点,并在被复制的主节点下线时,代替下线主节点继续处理命令请求。

节点间通信

集群中的节点通过发送和接收消息来进行通信。

Redis 集群节点发送的消息主要有以下五种:

  • MEET - 请求接收方加入发送方所在的集群。

  • PING - 集群中每个节点每隔一段时间(默认为一秒)从已知节点列表中随机选出五个节点,然后对这五个节点中最久没联系的节点发送 PING 消息,以此检测被选中的节点是否在线。

  • PONG - 当接收方收到发送方发来的 MEET 消息或 PING 消息时,会返回一条 PONG 消息作为应答。

  • FAIL - 当一个主节点 A 判断另一个主节点 B 已经进入 FAIL 状态时,节点 A 会向集群广播一条关于节点 B 的 FAIL 消息,所有收到这条消息的节点都会立即将节点 B 标记为已下线。

  • PUBLISH - 当节点收到一个 PUBLISH 命令时,节点会执行这个命令,并向集群广播一条 PUBLISH 消息,所有接受到这条消息的节点都会执行相同的 PUBLISH 命令。

判断槽是否由当前节点负责处理

当节点计算出 key 所属的槽为 i 之后,节点会根据以下条件判断槽是否由自己负责:

clusterState.slots[i] == clusterState.myself

MOVED 错误

当节点发现键所在的槽并非自己负责处理的时候,节点就会向客户端返回一个 MOVED 错误,指引客户端转向正在负责槽的节点。

MOVED 错误的格式为:

MOVED <slot> <ip>:<port>

个人理解:MOVED 这种操作有点类似 HTTP 协议中的重定向。

集群高可用

重新分片

Redis 集群的重新分片操作可以将任意数量的已经指派给某个节点(源节点)的槽改为指派给另一个节点(目标节点),并且相关槽所属的键值对也会从源节点被移动到目标节点。

重新分片操作可以在线进行,在重新分片的过程中,集群不需要下线,并且源节点和目标节点都可以继续处理命令请求。

Redis 集群的重新分片操作由 Redis 集群管理软件 redis-trib 负责执行的,redis-trib 通过向源节点和目标节点发送命令来进行重新分片操作。

重新分片的实现原理如下图所示:

ASK 错误

ASK 错误与 MOVED 的区别在于:ASK 错误只是两个节点在迁移槽的过程中使用的一种临时措施,在客户端收到关于槽 i 的 ASK 错误之后,客户端只会在接下来的一次命令请求中将关于槽 i 的命令请求发送至 ASK 错误所指示的节点,但这种转向不会对客户端今后发送关于槽 i 的命令请求产生任何影响,客户端任然会将关于槽 i 的命令请求发送至目前负责处理槽 i 的节点,除非 ASK 错误再次出现。

判断 ASK 错误的过程如下图所示:

复制

故障检测

集群中每个节点都会定期向集群中的其他节点发送 PING 消息,以此来检测对方是否在线。

节点的状态信息可以分为:

  • 在线状态;

  • 下线状态(FAIL);

  • 疑似下线状态(PFAIL),即在规定的时间内,没有应答 PING 消息;

故障转移

  1. 下线主节点的所有从节点中,会有一个从节点被选中。

  2. 被选中的从节点会执行 SLAVEOF no one 命令,成为新的主节点。

  3. 新的主节点会撤销所有对已下线主节点的槽指派,并将这些槽全部指派给自己。

  4. 新的主节点向集群广播一条 PONG 消息,告知其他节点这个从节点已变成主节点。

选举新的主节点

Redis 集群配置

我们后面会部署一个 Redis 集群作为例子,在那之前,先介绍一下集群在 redis.conf 中的参数。

  • cluster-enabled <yes/no> - 如果配置”yes”则开启集群功能,此 redis 实例作为集群的一个节点,否则,它是一个普通的单一的 redis 实例。

  • cluster-config-file <filename> - 注意:虽然此配置的名字叫“集群配置文件”,但是此配置文件不能人工编辑,它是集群节点自动维护的文件,主要用于记录集群中有哪些节点、他们的状态以及一些持久化参数等,方便在重启时恢复这些状态。通常是在收到请求之后这个文件就会被更新。

  • cluster-node-timeout <milliseconds> - 这是集群中的节点能够失联的最大时间,超过这个时间,该节点就会被认为故障。如果主节点超过这个时间还是不可达,则用它的从节点将启动故障迁移,升级成主节点。注意,任何一个节点在这个时间之内如果还是没有连上大部分的主节点,则此节点将停止接收任何请求。

  • cluster-slave-validity-factor <factor> - 如果设置成0,则无论从节点与主节点失联多久,从节点都会尝试升级成主节点。如果设置成正数,则 cluster-node-timeout 乘以 cluster-slave-validity-factor 得到的时间,是从节点与主节点失联后,此从节点数据有效的最长时间,超过这个时间,从节点不会启动故障迁移。假设 cluster-node-timeout=5,cluster-slave-validity-factor=10,则如果从节点跟主节点失联超过 50 秒,此从节点不能成为主节点。注意,如果此参数配置为非 0,将可能出现由于某主节点失联却没有从节点能顶上的情况,从而导致集群不能正常工作,在这种情况下,只有等到原来的主节点重新回归到集群,集群才恢复运作。

  • cluster-migration-barrier <count> - 主节点需要的最小从节点数,只有达到这个数,主节点失败时,它从节点才会进行迁移。更详细介绍可以看本教程后面关于副本迁移到部分。

  • cluster-require-full-coverage <yes/no> - 在部分 key 所在的节点不可用时,如果此参数设置为”yes”(默认值), 则整个集群停止接受操作;如果此参数设置为”no”,则集群依然为可达节点上的 key 提供读操作。

重点

  • 节点通过握手(MEET)来将其他节点添加到自己所处的集群中。

  • Redis 集群中有 16384 个槽可以指派给集群中的节点。每个节点都会记录哪些槽指派给了自己,哪些槽被指派给了其他节点。如果 16384 个槽中哪怕有一个槽为指派,则 Redis 集群的状态为下线状态。

  • 节点在接到一个命令请求时,会先检测这个命令请求要处理的键所在的槽是否由自己负责,如果不是的话,节点将向客户端返回一个 MOVED 错误,MOVED 错误携带的信息可以指引客户端将请求重定向至正在负责相关槽的节点。

  • Redis 集群的重新分片工作由 redis-trib 负责。重新分片的关键是将属于某个槽的所有键值对从一个节点转移至另一个节点。

  • 如果节点 A 正在迁移槽 i 至节点 B,那么当节点 A 没能在自己的数据库中找到命令指定的数据库键时,节点 A 会向客户端返回一个 ASK 错误,指引客户端到节点 B 接续查找指定的数据库键。

  • MOVED 错误表示槽的负责权从一个节点转移到了另一个节点;而 ASK 错误只是两个节点在迁移槽的过程中使用的一种临时措施。

  • 集群中的从节点用于复制主节点,并在主节点下线时,代替主节点继续处理命令请求。

  • 集群中的节点通过发送和接收消息来进行通信,常见的消息包括 MEET、PING、PONG、PUBLISH、FAIL 五种。

参考资料

  • 《Redis 实战》

  • 《Redis 设计与实现》

通过向节点发送 命令,可以将一个或多个槽指派给节点负责。

Redis 复制机制可以参考:

Redis 集群选举新的主节点流程基于

Redis 集群(Redis Cluster)
CLUSTER ADDSLOTS
Redis 复制
共识算法:Raft
Redis 集群教程
深入剖析 Redis 系列(三) - Redis 集群模式搭建与原理详解