Redis进阶(五):集群

1.概念

集群,从广义来讲:只要是多个机器,构成了分布式系统,都可以称为一个集群

狭义的集群:redis提供的集群模式,这个集群模式之下,主要是要解决存储空间不足的问题(拓展存储空间)

哨兵模式提高了系统的可用性,哨兵模式中,本质上还是redis主从节点存储数据,其中就要求一个主节点/从节点,就得存储整个数据的"全集"

引入多台机器,每台机器分担一部分:存储一部分数据,每台存储数据的机器还需要搭配多个从节点

2.分片

上述红框标注的就是分片~ 三种主流的分片方式

2.1 hash求余

借助hash函数,把一个key映射到整数,再针对数组长度求余,就可以得到一个数组下标

比如有三个分片:0,1,2

此时可以针对要插入的数据的key(redis都是键值对结构的数据)计算hash值(比如md5:将string经过数据计算得到一个整数),再把这个hash值余上分片的个数,就得到了一个下标,此时就可以把这个数据放到该下标对应的分片中了。

hash(key) % length(分片的个数,上述就是3)


但如果分片添加了,也就是扩容发生的时候,分片结果就会发生变化(需要重新进行分配)。

2.2 一致性hash算法

上述方式,如果数据很大,且发生数据搬运,开销极大,只能在非生产环境下,通过替换的方式进行扩容,依赖机器更多了,成本也高,因此一致性hash算法解决上述问题

在hash求余这种操作,当前key属于哪个分片是交替的:例如102 -》0 ,103-》1,104-》2 ...0,1,2.....,在一致性hash下,把交替出现,改成连续出现。

具体分为几步:

把0->2^32-1这个数据空间,映射到⼀个圆环上.数据按照顺时针⽅向增⻓.

假设有三个分区,在圆环上进行划分

假定一个key,计算得到hash值,该key值划分就是顺时针往下找,找到的第一个分区就是key所属分片

这就相当于,N个分⽚的位置,把整个圆环分成了N个管辖区间.Key的hash值落在某个区间内,就对应区间管理.

扩容场景

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

优点:⼤⼤降低了扩容时数据搬运的规模,提⾼了扩容操作的效率.

缺点:数据分配不均匀(有的多有的少,数据倾斜).

2.3 hash槽分区算法(redis使用)

就比如说:

此处,每个分区都会使用位图的数据结构表示当前有多少槽位号,16384个bit位,用每一个0/1来区分自己这个分片当前是否持有该槽位号

总结一下:key值先通过hash算法计算一下得到一个hash值,hash值再取模16384得到槽位,根据槽位数再划分到不同的分片。

分片增加场景:

注意事项

Redis集群是最多有16384个分⽚吗?

key是先映射到槽位 ,再映射到分片的。

如果每个分片包含的槽位比较多,如果槽位个数相当,就可以认为是包含的key数量相当。

如果每个分片包含的槽位比较少,槽位个数并不能直观的反应到key的数目。

因此造成:有的槽位有key,有的槽位没有key

如果每个分片只有一个槽位:很难保证数据在各个分片的均衡性

为什么是16384

1.节点之间通过心跳包进行通信,心跳包包含每个节点持有什么slots (槽位),槽位使用位图这样的数据结构表示的,16384 (16k)是2kb字节的空间,redis留出2kb的空间来保存槽位,如果slots更多了,就需要更大的空间去保存槽位。因为是周期性通信*(非常频繁,占用带宽)

2.另⼀⽅⾯,Redis集群⼀般不建议超过1000个分⽚.所以16k对于最⼤1000个分⽚来说是⾜够⽤

的,同时也会使对应的槽位配置位图体积不⾄于很⼤.

3.集群搭建

需求:

3.1 实现

在sh文件添加:

实现批量创建redis配置文件

执行脚本:

bash 复制代码
sh xxx.sh

创建redis容器:

在yml文件中进行编辑:

其他redis节点配置:

启动容器:

bash 复制代码
docker -compose up -d

几个redis节点构建成集群:

3.2 使用集群

使用集群存储数据:

-c:选型添加之后,redis客户端就会根据当前key实际算出来的槽位号,自动找到匹配的分片主机

4.故障处理

如果某个节点挂了,处理分几个情况

从节点挂了,挂就挂了不管,但如果是主节点挂了 ?

如果主节点挂了,就会自动把该主节点旗下的某个从节点选拨为主节点

4.1具体流程

1、先判断故障:

1.节点A给节点B发送ping包,B节点返回pong包,二个包除了message type属性不同之外,其他部分是一样的。

2.每个节点每秒钟都会给一些随机的节点发送ping包

3.A节点向B节点发送ping,不能正常返回pong,A就会尝试重置和B的TCP连接,如果还是失败,A就会把B标记为PEAIL(主观下线)

4.A判定BPEAIL之后,A会通过内置的Gossip协议,和其他节点进行沟通。让其他节点确认B状态

5.A发现其他节点也是认为B节点PFAIL,超过一半,那么A标记B为FAIL(客观下线),并且将消息同步给其他节点。

2、故障迁移

如果挂了的B节点是从节点无所谓

如果是主节点:需要从B节点的从节点挑选一个作为主节点

1.从节点首先需要判定是否有资格,从节点与主节点之间太久没同步了,此时差异太大,(超过了一定的阈值),就会失去资格

2.具有资格的节点会先进行休眠:休眠时间的大小因素主要为排名大小(offset值越大,排名越小)

3.有资格从节点的休眠时间到了,该节点就会给其他主节点进行拉票操作

4.主节点收到拉票请求就会投给那个参加竞选的从节点,当票数超过主节点数目的一半,该晋升成功的从节点自己负责 slaveof no one,并且让同为从节点的另一个从节点归属自己

5.同时,该节点晋升为主节点的消息也要发送给其他节点,以供其他节点更新自己的集群结构

集群宕机

出现以下几种情况会发生集群宕机:

1.某个分片,所有的主节点和从节点全挂了 :分片存储了部分的数据,如果该分片全挂了,就会宕机

2.主节点挂了,但该主节点没有从节点:和上述一个情况

3.超过半数的主节点挂了

5.集群扩容

场景:101-109 9个主机,构成了3主6从结构的集群,当前110和111也想加入到集群中:以110为主节点,111为从节点 == 分片从三个到四个

1.新的主节点添加到集群中

左ip为被新增的节点,右ip为集群上任意的一个节点:表明节点增添到哪个集群中

2.重新分配slots

然后需要输入分配多少槽位(通常16384 / 分片数)

紧接着,会询问让哪个节点来接收,粘贴110主机id即可

3.把从节点添加到集群中

5.1 问题

如果搬运key/slots时,此时的客户端能否访问咱们redis集群吗?

搬运key,大部分的key不是用来搬运的,针对这些未搬运的key:此时是可以访问的,针对这些正在搬运中的key,是有可能出现不能访问的情况

相关推荐
小刘|4 分钟前
《Java 实现希尔排序:原理剖析与代码详解》
java·算法·排序算法
逊嘘23 分钟前
【Java语言】抽象类与接口
java·开发语言·jvm
morris13130 分钟前
【SpringBoot】Xss的常见攻击方式与防御手段
java·spring boot·xss·csp
十叶知秋43 分钟前
【jmeter】jmeter的线程组功能的详细介绍
数据库·jmeter·性能测试
monkey_meng1 小时前
【Rust中多线程同步机制】
开发语言·redis·后端·rust
七星静香1 小时前
laravel chunkById 分块查询 使用时的问题
java·前端·laravel
Jacob程序员1 小时前
java导出word文件(手绘)
java·开发语言·word
ZHOUPUYU1 小时前
IntelliJ IDEA超详细下载安装教程(附安装包)
java·ide·intellij-idea
stewie61 小时前
在IDEA中使用Git
java·git
Elaine2023911 小时前
06 网络编程基础
java·网络