速来报名!AICon北京站鸿蒙专场~ 了解详情
写点什么

Redis Cluster 原理初探

  • 2019-09-20
  • 本文字数:3405 字

    阅读完需:约 11 分钟

Redis Cluster原理初探

虽然到现在仍未发现公司内部有团队在使用 Redis Cluster,但是这丝毫不影响我们去了解它。Redis Cluster 是一个可以在多个 Redis 节点之间进行数据共享的分布式集群。和以往了解的客户端通过一致性哈希解决 redis 多节点负载均衡的方式不同,Redis Cluster 是在服务端,通过节点之间的特殊协议进行通讯,达到服务端对请求进行负载均衡。对于客户端来说,其负载均衡策略是透明的,客户端不需要自己做负载均衡。

集成简介

Redis Cluster 特性之一是引入了槽的概念。一个 redis 集群包含 16384 个哈希槽,集群中的每个 redis 节点,分配到一部分槽。而集群使用公式 CRC16(key) % 16384 来计算每次请求的键 key 属于哪个槽,通过查询集群配置,便可知道 key 对应的槽属于哪个 redis 节点,然后再将请求打到该节点。举个例子,一个集群可以有两个节点,其中:


1.节点 A 负责处理 0 号至 5000 号哈希槽。


2.节点 B 负责处理 5001 号至 10000 号哈希槽。


3.节点 C 负责处理 10001 号至 16383 号哈希槽。


通过上述公式,可对 key X 计算出一个值,该值为 0-16383 中的一个数。假设 key X 通过上述公式计算出来的值为 34,根据上面例子,34 即为槽标识,亦 key X 属于槽 34,而槽 34 分配到了节点 A,也就是说节点 A 负责 key X 的读写。


通过将哈希槽分布到不同节点,我们可以很容易地向集群中添加或者删除节点。比如说:


  1. 如果用户将新节点 D 添加到集群中,那么集群只需要将节点 A 、B、C 中的某些槽移动到节点 D 就可以了。

  2. 与此类似,如果用户要从集群中移除节点 A ,那么集群只需要将节点 A 中的所有哈希槽移动到节点 B 和节点 C ,然后再移除节点 A 就可以了。


因为槽在节点之间移动不会造成节点阻塞,所以无论是添加新节点还是移除已存在节点,又或者改变某个节点包含的哈希槽数量,都不会造成集群下线,redis 集群能保证槽的平滑移动。


RedisCluster 还有一个特性便是去中心化。客户端可以连接集群中的任意一个节点,集群中的任意一个节点都可对外提供服务。节点之间可共享集群配置(如槽的分配)。或者我们可以理解为,集群中的任意一个节点都是中心节点。假设有两个节点 A 和 B,客户端连接了 A 节点,并发起了一次请求 a,A 节点计算请求 a 的 key 得知该请求应该打到 B 节点上,然后 A 节点对请求 a 返回一个 MOVED B,通知客户端重定向到 B 节点。

集成简介

redis 集群架构图


因为槽在节点之间移动不会造成节点阻塞,所以无论是添加新节点还是移除已存在节点,又或者改变某个节点包含的哈希槽数量,都不会造成集群下线,redis 集群能保证槽的平滑移动。


以上图片,蓝色的为 redis 节点,这里是指 master 节点,一个 master 节点可以配置多个 slave。绿色为客户端,可以理解为我们的应用。


架构细节:


(1)所有的 redis 节点彼此互联(PING-PONG 机制),内部使用二进制协议优化传输速度和带宽。


(2)节点的 fail 是通过集群中超过半数的节点检测失效或者某个节点主从全挂时才生效。


(3)客户端与 redis 节点直连,不需要中间 proxy 层。客户端不需要连接集群所有节点,连接集群中任何一个可用节点即可。


(4)redis-cluster 把所有的物理节点映射到[0-16383]slot 上。

集群容错

为了当部分节点失效时,cluster 仍能保持可用,Redis 集群采用每个节点拥有 1(主服务自身)到 N 个副本的主从模型。类似于 master/slave。但是 redis cluster 却不是强一致性的,因为 cluster 内部 master 和 slave 之间是通过异步复制做数据同步的,复制过程中可能 master 挂了,这就导致部分数据没有完全同步至 slave 上,不过这种可能性还是很小的。


以上是集群选举过程。


选举过程是集群中所有 master 参与,如果半数以上 master 节点与当前 master 节点通信超时,则集群认为当前 master 节点挂掉.


什么时候整个集群不可用?当集群不可用时, 所有对集群的操作做都将失败。以下是会导致集群不可用的其中两种情况:


a:集群任意 master 挂掉,并且当前 master 没有 slave,集群不可用。


b:集群超过半数以上 master 挂掉,无论是否有 slave,集群不可用。

集群扩展

什么时候整个集群不可用?当集群不可用时, 所有对集群的操作做都将失败。以下是会导致集群不可用的其中两种情况:


选举过程是集群中所有 master 参与,如果半数以上 master 节点与当前 master 节点通信超时,则集群认为当前 master 节点挂掉。


以往的一致性哈希方案,如果我们移除或者新增节点时,虽然说不会导致全局 key 的 rehash,但是也会影响到部分 key 的失效。Redis Cluster 在可用性和可扩展性上比较重视,如果集群新增一个节点,在给该节点分配槽时,这些槽所属的源节点和该节点会进行一次 key 的迁移,并且迁移过程中不阻塞集群服务。如果移除一个节点,同理,我们需要将待移除的节点的 key 迁移到另一个节点上。


那集群是如何做到 key 迁移不阻塞集群服务的呢?


key 迁移过程中,涉及到 CLUSTER SETSLOT slot8 MIGRATING node 命令和 CLUSTER SETSLOT slot8 IMPORTING node 命令,前者用于将给定节点 node 中的槽 slot8 迁移出节点,而后者用于将给定槽 slot8 导入到节点 node :


(1)、如果一个槽被设置为 MIGRATING 状态时,原本持有该槽的节点会继续接受关于这个槽的命令请求,但只有当键存在于该节点时,节点才会处理这个请求。如果命令所使用的键不存在于该节点,那么节点将向客户端返回一个 ASK 转向(redirection)错误,告知客户端,要将命令请求发送到槽的迁移目标节点。


(2)、如果一个槽被设置为 IMPORTING 状态时,节点仅在接收到 ASKING 命令之后,才会接受关于这个槽的命令请求。如果客户端向节点发送该槽的数据请求,命令为非 ASKING 时,那么节点会使用 MOVED 转向错误将命令请求转向至真正负责处理这个槽的节点。


举个例子来看看。


假设现在,我们有 A 和 B 两个节点,我们想将槽 8 从节点 A 移动到节点 B ,于是我们:


**(1)、向节点 B 发送命令 CLUSTER SETSLOT 8 IMPORTING A


(2)、向节点 A 发送命令 CLUSTER SETSLOT 8 MIGRATING B**


每当客户端向其他节点发送关于哈希槽 8 的命令请求时,这些节点都会向客户端返回指向节点 A 的转向信息(迁移中,虽然 A 和 B 都有槽 8 所对应的 key,但是各个节点仍然认为槽 8 由 A 负责,只有迁移结束后,槽 8 才属于 B 节点而不属于 A)。


(1)、如果命令要处理的键已经存在于槽 8 里面,那么这个命令将由节点 A 处理。



(2)、如果命令要处理的键未存在于槽 8 里面,那么这个命令由节点 B 处理。



这种机制将使得节点 A 不再创建关于槽 8 的任何新键。


与此同时,一个特殊的客户端 redis-trib 以及 Redis 集群配置程序(configuration utility)会将节点 A 中槽 8 里面的键移动到节点 B 。移动 key 的操作是原子性的,也就是一个 key 如果从 A 移动到 B,那么移动时,都不会出现 key 在 A 和 B 中同时出现。

内部数据结构

RedisCluster 涉及三个核心的数据结构 clusterState、clusterNode、clusterLink 都在 cluster.h 中定义。这三个数据结构中最重要的属性就是:clusterState.slots、clusterState.slots_to_keys 和 clusterNode.slots,它们保存了三种映射关系:


clusterState:集群状态


nodes:所有结点


migrating_slots_to:迁出中的槽


importing_slots_from:导入中的槽


slots_to_keys:槽中包含的所有 Key,用于迁移 Slot 时获得其包含的 Key


slots:Slot 所属的结点,用于处理请求时判断 Key 所在 Slot 是否自己负责 clusterNode:结点信息


slots:结点负责的所有 Slot,用于发送 Gossip 消息通知其他结点自己负责的 Slot。


clusterLink:与其他结点通信的连接


以下为这三个数据结构的定义:






结合以上数据结构,我们看看客户端请求集群时,集群处理的的流程:


1、检查 key 所在 Slot 是否属于当前节点?


  • 1.1 计算 crc16(key) % 16384 得到 Slot

  • 1.2 查询 clusterState.slots 负责 Slot 的结点指针

  • 1.3 与 myself 指针比较


2、若不属于,则响应 MOVED 错误重定向客户端


3、若属于且 Key 存在,则直接操作,返回结果给客户端


4、若 Key 不存在,检查该 Slot 是否迁出中?(clusterState.migrating_slots_to)


5、若 Slot 迁出中,返回 ASK 错误重定向客户端到迁移的目的服务器上


6、若 Slot 未迁出,检查 Slot 是否导入中?(clusterState.importing_slots_from)


7、若 Slot 导入中且请求有 ASKING 标记,则直接操作


8、否则响应 MOVED 错误重定向客户端


本文转载自公众号贝壳产品技术(ID:gh_9afeb423f390)。


原文链接:


https://mp.weixin.qq.com/s/zjwiOkRFvQDpKfeFL1-dUQ


2019-09-20 14:228719

评论 2 条评论

发布
用户头像
若客户端连接的master 节点挂了,是如何处理的呢?

客户端与 redis 节点直连,不需要中间 proxy 层。客户端不需要连接集群所有节点,连接集群中任何一个可用节点即可。

2021-02-25 12:00
回复
集群下,一般客户端不会配置链接一个节点。如果链接的节点都挂了,那就没办法了
2023-09-16 10:28 · 福建
回复
没有更多了
发现更多内容

LeetCode152-乘积最大子数组-medium

书旅

LeetCode 动态规划

学习源码的第八个月,我成了Spring的开源贡献者

程序员DMZ

spring 开源

Flink任务执行-3

小知识点

大数据 flink

学习笔记2

Qx

学习

不完满的选择,要不要放弃

zhoo299

随笔杂谈

MySQL中几种常见的日志

Simon

MySQL 日志

云上攻击太多怎么办?不妨试试这些工具

华为云开发者联盟

黑客 云服务 数据安全 华为云 企业上云

图解JavaScript——进阶篇(执行上下文、变量对象、作用域、作用域链、闭包、this、原型及原型链、事件循环等一把梭)

执鸢者

Java 大前端 函数执行 事件循环

安全系列之——RSA的公钥私钥有多少人能分的清楚?RSA的签名验签与加密解密如何使用公私钥?

诸葛小猿

加密解密 非对称加密 rsa 签名验签

SecureBoost算法

soolaugust

学习 同态加密 secureboost

MySQL容器化详细教程

Simon

MySQL Docker 容器

Apache Pulsar 在 BIGO 的性能调优实战(上)

Apache Pulsar

力扣题 - 29 解析大佬题解

Geek_663541

Java算法

LeetCode题解:11. 盛最多水的容器,while循环双指针,JavaScript,详细注释

Lee Chen

大前端 LeetCode

ARTS打卡第一周(200511-200517)

老胡爱分享

ARTS 打卡计划 ARTS活动

疫情按下快进键,电商抢占市场红利需可靠的助力

华为云开发者联盟

高并发 电商 华为云 流量 云服务器

CSS属性整理

kidd

领导发表的报告,你真的读懂了吗?

罗小龙

工作经验

糖果不需要意义

zhoo299

随笔杂谈 电影

Docker从入门到放弃---基础篇

书旅

Docker 容器

Docker入门与简单使用

Simon

Docker Linux

带着面试题学习红黑树操作原理,解析什么时候染色、怎么进行旋转、与2-3树有什么关联

小傅哥

Java 数据结构 小傅哥 红黑树 2-3树

常用SQL语句分享

Simon

MySQL sql

CDN百科11 | 担心纸质病例被洪水淹没?ECS+CDN+OSS如何助力医疗上云

阿里云Edge Plus

CDN 存储 云服务器

[High Performance TIDB] Leeson 01:TIDB整体架构---作业

远鹏

高性能 #TiDB

TypeScript 设计模式之发布-订阅模式

Geek_z9ygea

typescript 大前端 设计模式

不说再见

太以

疫情 毕业季 遗憾 大学

Docker 架构及工作原理

哈喽沃德先生

Docker 容器 微服务

GrowingIO 数据采集 iOS SDK 测试实践

GrowingIO技术专栏

ios 数据采集 sdk

我与游戏相伴【自我访谈】

叶阳夏烟

系列 游戏 游戏观 访谈录

MySQL下的DB Link

Simon

MySQL

Redis Cluster原理初探_文化 & 方法_邱润景_InfoQ精选文章