Redis集群

集群概念

上一篇我们讲到了哨兵模式,提高了系统的可用性,但是真正用来存储数据的还是master跟slave节点,所有的数据都需要存储在单个的master和slave节点中。

如果数据量很大,超出了节点所在机器的物理内存,就会出现严重问题了。

那如何获得更大的空间呢,加机器就可以,一台机器搞不定,就用多台机器。

Redis集群就是在上述的思路下,引入多组的master跟slave,每组的master跟slave存储数据全集的一部分,从而构成一个更大的集体,称为Redis集群。

假设整个数据全集是1TB,此时引入三组master跟slave,则每组机器只需存储整个数据全集的1/3即可,每个红框部分可以称为一个分片,如果全量数据进一步增加,只要再增加更多的分片就行。

数据分片算法

Redis集群的核心思路就是用多组机器来存数据的每个部分,那么就有一个核心问题:给定一个具体的key,那么整个数据应该存储到哪个分片上?读取的时候又应该去哪个分片读取呢?

针对这个问题,目前有三个比较主流的实现方式:

1.哈希求余

设由N个分片,用【0,N-1】的顺序编号;

针对某个给定的key,先计算hash值,再把得到的结果%N,得到的结果就是分片编号。

如上图所示。

此分片算法的优点:简单搞笑,数据分配均匀。缺点:一旦需要扩容,N改变了,原有的映射规矩就被破坏,就需要让节点之间的数据相互传输重新排序,则此时需要搬运的数据量事比较多的,开销较大。

2.一致性哈希算法

为了降低上述的搬运开销,能够更高效的扩容,所以提出了“一致性哈希算法”。

  1. 把0-2^32-1这个数据空间映射到一个圆环上,数据按照顺时针方向增长。
  2. 假设当前存在三个分片,就把分片放到圆环的某个位置上。
  3. 假定有一个key,计算得到hash值:h,那么整个key就会映射到所属分片上,就是从h所在位置顺时针往下找,找到第一个分片就是key所属的分片。

这就相当于n个分片位置把整个圆环分成了n个管辖区间,key的hash值落入某个区间就归对应区间管理。

此时如果扩容一个分片,就只需原有分片在环上的位置不懂,在环上安排一个新分片即可~

此时只需要把0号分片上的部分数据搬运给3号分片上即可,1号分片和2号分片的管理区间不变。

优点:大大降低了扩容时数据搬运的规模,提高了扩容操作的效率。

缺点:数据分配不均。

3.哈希槽分区算法

为了解决上述问题,redis集群引入了哈希槽算法。

hash_slot = crc16(key) % 16384(其中crc16也是一种hash算法)
相当于把整个哈希值映射到16384个槽位上,然后再把这些槽位比较均匀的分配给每个分片,每个分片的节点都需要记录自己持有哪些分片。
如果需要扩容,就可以把之前每个分片持有的槽位各拿出一点,分给新分片。
还有两个问题:
1.redis集群是最多有16384个分片吗
并⾮如此. 如果⼀个分⽚只有⼀个槽位, 这对于集群的数据均匀其实是难以保证的.
实际上 Redis 的作者建议集群分⽚数不应该超过 1000。
2.为什么是16384个槽位?
  • 节点之间通过⼼跳包通信. ⼼跳包中包含了该节点持有哪些 slots. 这个是使⽤位图这样的数据结构 表⽰的. 表⽰ 16384 (16k) 个 slots, 需要的位图⼤⼩是 2KB. 如果给定的 slots 数更多了, ⽐如 65536 个了, 此时就需要消耗更多的空间, 8 KB 位图表⽰了. 8 KB, 对于内存来说不算什么, 但是在频繁的⽹络⼼跳包中, 还是⼀个不⼩的开销的。
  • 另⼀⽅⾯, Redis 集群⼀般不建议超过 1000 个分⽚. 所以 16k 对于最⼤ 1000 个分⽚来说是⾜够⽤ 的, 同时也会使对应的槽位配置位图体积不⾄于很⼤。

故障处理流程

1.故障判定

1. 节点 A 给 节点 B 发送 ping 包, B 就会给 A 返回⼀个 pong 包. ping 和 pong 除了 message type
属性之外, 其他部分都是⼀样的. 这⾥包含了集群的配置信息(该节点的id, 该节点从属于哪个分⽚,
是主节点还是从节点, 从属于谁, 持有哪些 slots 的位图...).
2. 每个节点, 每秒钟, 都会给⼀些随机的节点发起 ping 包, ⽽不是全发⼀遍. 这样设定是为了避免在节点很多的时候, ⼼跳包也⾮常多(⽐如有 9 个节点, 如果全发, 就是 9 * 8 有 72 组⼼跳了, ⽽且这是按照 N^2 这样的级别增⻓的).
3. 当节点 A 给节点 B 发起 ping 包, B 不能如期回应的时候, 此时 A 就会尝试重置和 B 的 tcp 连接, 看能 否连接成功. 如果仍然连接失败, A 就会把 B 设为 PFAIL 状态(相当于主观下线).
4. A 判定 B 为 PFAIL 之后, 会通过 redis 内置的 Gossip 协议, 和其他节点进⾏沟通, 向其他节点确认 B 的状态. (每个节点都会维护⼀个⾃⼰的 "下线列表", 由于视⻆不同, 每个节点的下线列表也不⼀定相同).
5. 此时 A 发现其他很多节点, 也认为 B 为 PFAIL, 并且数⽬超过总集群个数的⼀半, 那么 A 就会把 B 标记成 FAIL (相当于客观下线), 并且把这个消息同步给其他节点(其他节点收到之后, 也会把 B 标记成 FAIL).
此时,b就彻底被判定为故障节点了。

2.故障迁移

上述例⼦中, B 故障, 并且 A 把 B FAIL 的消息告知集群中的其他节点.
如果 B 是从节点, 那么不需要进⾏故障迁移.
如果 B 是主节点, 那么就会由 B 的从节点 (⽐如 C 和 D) 触发故障迁移了.
所谓故障迁移, 就是指把从节点提拔成主节点, 继续给整个 redis 集群提供⽀持.
具体流程如下:
1. 从节点判定⾃⼰是否具有参选资格. 如果从节点和主节点已经太久没通信(此时认为从节点的数据和主节点差异太⼤了), 时间超过阈值, 就失去竞选资格.
2. 具有资格的节点, ⽐如 C 和 D, 就会先休眠⼀定时间. 休眠时间 = 500ms 基础时间 + [0, 500ms] 随机时间 + 排名 * 1000ms. offset 的值越⼤, 则排名越靠前(越⼩).
3. ⽐如 C 的休眠时间到了, C 就会给其他所有集群中的节点, 进⾏拉票操作. 但是只有主节点才有投票资格.
4. 主节点就会把⾃⼰的票投给 C (每个主节点只有 1 票). 当 C 收到的票数超过主节点数⽬的⼀半, C 就会晋升成主节点. (C ⾃⼰负责执⾏ slaveof no one, 并且让 D 执⾏ slaveof C).
5. 同时, C 还会把⾃⼰成为主节点的消息, 同步给其他集群的节点. ⼤家也都会更新⾃⼰保存的集群结构信息.

集群扩容

本篇博客只讲述集群扩容的步骤,具体流程暂不详述。

  1. 把新的主节点加入到集群。
  2. 重新分配slots,输入响应命令就会进入交互操作:
  • 多少个slots要进行分配
  • 哪个节点来接受这些slots
  • 这些slots从哪些节点搬运过来

     3.给新的主节点添加从节点。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值