首先共享之前的一切文章 , 欢迎点赞收藏转发三连下次一定 >>>>
文章合集 : juejin.cn/post/694164…
Github : github.com/black-ant
CASE 备份 : gitee.com/antblack/ca…
一 . 前语
- 一种是一致性哈希 , 这种算法在 适用dis Cluster计划中并没有完结,首要在外部的署理形式 (Twemproxy)
- 一种是 Slot 哈希槽算法 ,这种算法便是 Cluster 的中心算法
所以谈到这个问题的时分,不能只讲一部分。在 Redis 3.0 之前
,Redis 是没有集群计划的,在这个时期完结 Redis 的 散布式
首要由客户端自行完结
。 一般的完结方法便是一致性 Hash。
而 Redis 3.0 之后
,Redis 完结了 Cluster 集群,也就采用了相对而言更简练的 Slot 槽方法。
下面来一步步的了解其间的变化 ,以及为什么要这样做 :
第一步 :单节点到多节点集群
之前也聊过,单节点的功能是有瓶颈的。当单节点达到瓶颈
后,构建集群
便是最合理,最经济的用法。
这就衍生出几个问题 :
- 单节点的时分,直接把数据往一个节点丢就行,查询也是一个节点去处理查询
- 集群后,
数据应该放在哪个节点
? 是全部存一份仍是分开存? - 集群后,
查询应该查询哪个节点
? 不或许全量查询吧 , 一个一个节点查,功能太差了
为了解决这些问题, Redis 供给了多种集群的构建方法 :
-
Sentinel 岗兵形式 :
主节点
支撑读写,从节点
支撑读,岗兵节点担任维护高可用- 这个计划下,主节点和从节点
都有全量数据
,适合数据量相对少
的场景 - 主节点担任写操作,主节点数据写入后将数据依照流程
同步
到从节点 - 当主节点
异常
后 ,从节点会被推举
为主节点,从而完结后续的写和同步
- 这个计划下,主节点和从节点
- Redis Cluster : 这个计划即为一致性Hash的计划,后边详细来讲
-
Twemproxy : 类似于署理形式,数据的分片和担任均衡由 Twemproxy 来完结
- Twemproxy 本身不供给高可用,适用于轻量级的场景
可以看到, Redis 集群的计划很详细,Sentinel 流程里边关于上述问题的处理也很完善。可是数据量假如太大
,用岗兵的计划就不够了。上十亿的数据每个节点复制一份,功能,容量都扛不住。
这个时分,就要考虑运用 Cluster 计划,那么一致性Hash在 Cluster 形式里边又起到什么作用呢?
第二阶段 : 一致性哈希的种种变化
那么咱们有了数据,也有了多个集群节点,怎么样让数据放在对应的节点上呢?
- 要求一 : 数据量大,数据只能存在一个节点上
- 要求二 : 要确保数据相对均匀散布到一切的节点上
- 要求三 : 不能影响到查询的效率,所以查询应该只用查询一个集群节点
- 要求四 : 要完结高可用,节点宕机后能快速恢复,支撑缩容扩容
2.1 首先数据的散布计划
针关于要求一
和要求二
, 数据只能在一个节点,且一切数据应该均匀的散布在一切的节点上。
关于均匀而言 ,一般咱们的方法便是 Hash
+ 取模
,可是这样会有一些问题。
经过取模的方法咱们虽然可以让数据均匀散布 ,可是一旦扩展或许缩容
,就会导致全量数据的重新搬迁和核算,这显然是不可行的。
于是就衍生出了一个计划 :一致性哈希。详细的计划如下 :
- S1 : 首先构建一个 Hash 环,例如一个Hash
算法的规模
是 0到2^32-1 , 那么就会构成一个整数环
- S2 : 对 Redis
数据节点
进行Hash
, 得到的值意味着它映射到了环上的一个点
- S3 : 刺进时 ,当一个数据来的时分 ,对 Key 进行 Hash 函数核算,
映射到环上的一个点
- S4 : 对该点进行
顺时针查找
,找到第一个
Redis子节点,便是该key应该操作
的 Redis子节点 - S5 : 查询时同理 , 先 Hash 再进行节点的查询
2.2 其次确保数据的均衡
上面的问题很明显,明显节点C和节点A之间空余空间更大,就会导致数据不均衡
,大部分数据被指向了某一个节点。
为此 一致性Hash 做了更多的优化 :虚拟节点
。 当节点较少的时分,为每个物理节点创立多个虚拟节点
,使一切的节点均匀的散布
在 Hash 环上 , 从而使数据相对均衡
。
- S1 : 为每个物理节点
生成多个虚拟节点
,并且让一切的节点都均匀的散布
在 Hash 环上面 - S2 : 当数据操作恳求进来时 , 假如指向了虚拟节点,就
映射到实践的物理节点中
经过这样的方法,就可以确保数据的相对均衡。 当然,这种均衡仍是相对的。
2.3 数据的查询和节点的扩容
数据查询的流程和数据刺进的流程是相同的,当恳求到来的时分,依据恳求的 Key 核算出对应的数据节点
,再到该节点中进行数据查询。
而节点变化就比较麻烦了,当一个节点需求下线的时分,需求将该节点里边的一切数据都会依据 Hash 环的轮动状况 ,搬迁当时 Hash 规模内
的数据到 Hash环 中对应的下一个节点中
。
然后后续的查询都会走到下一个节点中进行查询
2.4 总结一下一致性哈希
上面说了,这种计划多见于外部署理组件,例如 Twitter 发布的 Twemproxy ,例如 Predis-Proxy。
一致性哈希能完结数据的定位,也能完结相对均匀的数据,可是它仍是有一些问题 。
- 相对而言复杂度更高,节点发生变化的时分,需求搬迁
整个节点
的数据。 - 数据只能
相对均衡
,无法对优势节点进行特殊定制,数据的散布彻底依据 Hash 算法来完结- 这儿假如把虚拟节点搞得更多,其实也能削减这种问题
- 一致性Hash抗危险才能相对弱一些,当节点挂了的时分,会导致数据出现大面积不均衡,从而导致单个节点压力高
- 其实 Hash 槽也有,只不过一致性hash的特性会导致
流量直接到
下一个节点
- 其实 Hash 槽也有,只不过一致性hash的特性会导致
这个时分就需求咱们了解一下 Redis 的槽概念了。
第三阶段 : Redis 集群分片的计划
3.1 Slot Partitioning 槽分区算法
Redis Cluster 界说了 16384 个槽位,将这些槽位分发给一切的物理节点
槽位的核算
- 一般 Cluster 默许依据 Key 进行
crc16
算法进行 Hash 核算,然后依据16384
进行取模 - 可是 特殊状况下 ,Cluster 可以指定某个Key挂载到特定的槽位上(经过
Tag
完结 , Tag 映射槽位)
指令的恳求
与一致性Hash相同的是 ,Cluster 的槽位挑选仍是经过客户端来完结的。
当 Cluster 衔接集群的时分,其本身会得到一份集群的槽位信息
,从而直接定位到方针节点。
不过,每个集群节点同样会保存一切的槽位信息,目的在于后续槽位变化
或许 客户端向一个过错的节点发送指令时 , 节点会依据这些信息将指令发送到正确的节点。
3.2 槽数据的搬迁
当槽位进行搬迁的时分,当时槽处于过渡状态。此刻槽即存在于原节点A(migrating
),又存在于新节点B (importing
)。此刻 Cluster 客户端上钩算出来数据还在 A节点中(过错结果
)。
- 当数据搬迁时 :
-
S1 : 一次性获取源节点槽位的
一切 key 列表
,逐一
对 Key 进行搬迁 -
S2 :
原节点A
此刻充任客户端角色,指向Dump
命令进行数据序列化 -
S3 :
原节点A
向方针节点B
发起restore
指令,携带序列化数据进行拜访 -
S4 :
方针节点B
接收到数据,保存
到方针节点 ,并且回来成功
-
S5 :
原节点A
把当时Key 在自己的节点中进行删除
-
S1 : 一次性获取源节点槽位的
- 当此刻恳求数据时 :
-
S1 : 客户端首先去 A节点(过错节点) 恳求数据 ,假如
数据还在A节点中
,直接回来 -
S2 : 假如数据现已搬迁 ,A节点回来 ASK 指令,且告知
B节点的地址
- S3 : 客户端向B节点发起 ASK 拜访 , 此刻仅为了防止死循环(由于或许搬迁一半,槽位未创立好)
- S4 : 履行之前的操作
-
S1 : 客户端首先去 A节点(过错节点) 恳求数据 ,假如
3.3 槽思维的扩展
Redis Cluster 是 Redis 官方的计划,这其实也算是一种分片的思路。 而在外部东西里边 ,同样有类似的计划。
例如国产组件 Codis , 其本质上是一个署理中间件,和 Twemproxy 有一些类似。
这个组件会将一切的 key 默许划分为 1024
个槽位(slot) 。 不同于客户端自己的处理,槽位的核算是在 Codis 中进行的 ,拜访 Codis 和拜访单节点Redis 没有区别。
3.4 后续待扩展的细节
- 槽位的核算方法
- 为什么界说这些数量的槽位
- 不同节点之间如何同步信息
- 。。。。。
- 时刻有限,东西不少,后续迭代
总结
时刻有限 ,Redis 槽位还有一些细节点这一篇没有说 ,后边会来探讨一下为什么槽位要那么界说,以及详细传输的细节。
内容或许会有一些不太准确的地方,学习的也不太深入 ,欢迎指导。