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配置文件
执行脚本:
sh xxx.sh
创建redis容器:
在yml文件中进行编辑:
其他redis节点配置:
启动容器:
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,是有可能出现不能访问的情况