一、单机Redis存在的问题
问题1:
数据丢失问解决方案:
利用RDB和AOF实现数据的持久化
问题2:
并发能力弱解决方案:
搭建主从集群 ,实现主从分离
问题3:
存储空间小解决方案:
搭建分片集群 ,利用槽机制 实现动态扩容
问题4:
故障恢复解决方案:
利用Redis哨兵机制,实现健康检测和自动恢复
二、主从集群解析
2.1 定义
将一台Redis服务器的数据,复制到其他的Redis服务器。前者为主节点 ,后者为从节点。
2.2 特点
- 数据的复制是
单向的
,只能从主节点到从节点。Master以写
为主,Slave以读
为主; - 默认情况下,每台Redis都是主节点;
- 一个主节点可以有多个从节点(或者没有从节点),一个从节点只能由一个主节点;
- Redis主从复制支持
主从复制
和从从复制
。后者是Redis后续版本新增功能的。
二八定律:80%的情况下是在进行读操作,20%是在进行写操作
2.3 主从复制的作用
java
1. 数据冗余:主从复制实现了数据的"热备份",是持久化之外的一种数据冗余方式;
2. 故障恢复:当主节点出现问题时,可由从节点提供服务,实现快速的故障恢复
3. 负载均衡:在主从复制的基础上,配合"读写分离",由主节点提供写功能,从节点提供读功能分担服务器的负载。尤其是在"写少读多"的场景,通过多个从节点分担读负载,可以大大提高Redis服务器的并发量。
4. 高可用(集群)基石:主从复制还是"哨兵"和"集群"能够实施的基础。
2.4 数据同步机制
- Slave启动成功连接到master后会发送一个
Sync同步命令
,包括ReplictId和OffSet
信息; - Master接到命令,执行
bgsave
命令启动后台的存盘进程
,同时收集所有收到的用于修改数据集命令
,在后台进程执行完毕后,master将传送整个数据文件到slave,并完成一次完全同步
,同时主服务器不会拒绝客户端的读写,将客户端的写命令写入到缓冲区
中;【全量同步】 - Master发送完
快照数据
后,会将缓冲区中的命令发送给slave服务器,slave服务器开始执行slave命令; - 接下来,每当主服务器收到一条写命令后,就会将写命令同步给从服务器,保证主从服务器数据的一致。【增量同步 】。
其中ReplictId和Offset用于增量同步时,判断Master和Slave两者之间的数据版本以及差异
等问题。
全量复制:
slave服务在接收到数据库文件数据后,将其存盘并加载到内存中;
增量复制:
Master继续将"新的"所有收集到的修改命令一次传给slave,完成同步【注意】:只要重新连接到Master,一次完全同步(全量复制)将会被自动执行。
2.5 两种配置模式(配置主机和从机)
配置文件配置:
主机断开连接,从机依旧连接到主机,但是没有写操作。一旦主机回来了,从机依然接收主机写的信息。
命令行配置:
如果从机重启了,就会变成主机。
三、哨兵(Sentinel)集群模式
解决的问题:
一旦主机宕机后,能主动
从从节点中选举出主机。
一对多(一个哨兵监控多个Redis实例):
哨兵本质是一个独立进程
,可独自运行。哨兵通过发送命令,等待Redis服务器响应,从而监控运行的多个Redis实例。
3.1 主要流程
- 哨兵发送命令,让Redis服务器返回监控其运行状态,包括Master server和Slave server;
- 当哨兵监测到master宕机后,会自动将slave切换到master,通过
发布订阅模式
通知其他的从机修改配置文件,切换主机。
存在的问题:
单个哨兵如果出现问题,那么将无法监控Redis运行状态,就无法在主机出现故障时,及时的切换
解决方法:
多对多模式,即多个sentinel哨兵监控多个Redis实例。
3.2 哨兵功能
java
1. 监控(monitor):哨兵会不断的检查主节点和从节点是否运作正常
2. 自动故障转移(Automatic failover): 当"主节点"不能正常工作时,哨兵会开始"自动故障转移操作",它会将失效主节点的其中一个"从节点升级为新的主节点",并让其他从节点改为复制新的主节点;
3. 配置提供者(Configuration provider):客户端在初始化时,通过连接哨兵来获得当前Redis服务的主节点地址
4. 通知:哨兵可以将故障转移的结果发送给客户端
其中,每个哨兵监控所有的主机和从机,哨兵之间也会相互监控。
3.3 整体运行机制
3.3.1 判断Master主节点故障
主观下线:
当主服务器宕机后,假设哨兵1先检测到这个结果,系统并不会马上进failover(重新选举)过程,仅仅是哨兵1主观地认为主服务不可用,这个现象为主观下线 ;
客观下线:
当后面的哨兵也监测到主服务器不可用且数量达到一定值 时,那么哨兵之间就进行一次投票,投票的结果由一个哨兵发起,进行failover操作,切换成功后,就会发布订阅模式 让各个哨兵监控的从服务器切换主机,这个过程称为客观下线。
3.3.2 选举新的Master节点
出现故障后,就需要选取新的Master节点。选举依据为:
java
排除原则:
1. 排除已经宕机的slaves;
2. Sentinel leader会向所有的slaves发送命令,响应慢(回复ping命令时间大于五秒钟)的排除;
3. 与原Master通信慢(与失效服务器连接断开的时长超过down-after选项指定的时长十倍)的排除;
优先原则:
5. 判断slave节点的save-priority值, 越小优先级越高 -> 选择优先级高的slave节点;
6. 若优先级相同,选择offset大的节点, 越大数据复制的最完整 -> 选择offset大的slave节点;
7. 若offset相同,则选择runid最小的(启动最早的节点) -> 选择runid最小的slave节点
3.3.3 实现故障转移
新的Master节点选举完成后,需要更新每个节点的主从配置信息
。包括故障的Master节点和Slave节点。所谓的更新,即故障转移机制,整理流程为:
java
1. 首先, sentinel给备选的slave节点发送salveof no one命令,使该节点成为Master节点;
2. 其次, sentinel给其他的slave节点发送salve of [master节点的ip和port],让这些slave成为新master的从节点,开始新的master同步数据;
3. 最后,sentinel将故障节点标记为slave,故障节点恢复后会自动成为新的master的slave节点。
四、分片集群(多个主节点)解析
4.1 背景
哨兵集群虽然可以解决高可用和高并发读
的问题。但仍然存在两个问题:
- 大数据量的存储问题
- 高并发写的问题
因此,使用分片集群
可以解决上述问题。
4.2 特点
数据分布式存储
。每个Master存储数据部分数据;健康状态自监测
。master之间每隔一段时间会进行通信,若某一个master发生故障,可进行故障转移,取代了哨兵机制;读写分离
。单master和多slave之间也满足了读写分离。
4.3 集群数据分区方案
4.3.1 哈希值 % 节点数
过程
:对key进行hash,利用hash值对节点数量取余
,映射到对应节点上。
缺点:
一旦其中某个master宕机,每个key对应的"映射关系"需要重新计算,短时间造成数据查询错误,导致数据库的压力增大,会影响所有数据,一般采用翻倍扩容方式
4.3.2 一致性哈希算法(自动缓存转移) + 虚拟节点(自动负载均衡)
原理:
将多个master节点均匀的分布在一个圆环上,对key进行hash,判断hash落在哪个点上,然后顺时针旋转,去最近的master节点去查询。这样就算某一个master宕机,也只有1/3的数据失效。当增加或者删除节点时,部分节点信息会迁移到附近节点上。
缺点:
当节点数量较少时,增加或删除节点,对单个节点的影响可能很大
,造成数据的严重不平衡【影响单个节点的所有数据】
解决方案:
使用虚拟节点 。在相邻节点之间增加非相邻的虚拟节点。例在node1和node2之间增加node3、node4等。当某个master宕机后,失效的数据远小于1/3.
缺点:
一致性hash在扩容时还是会导致一个节点的部分时间不可用
4.3.3 虚拟槽分区
虚拟槽中的槽就是大量虚拟节点的抽象化
,将原来的虚拟节点变成一个槽,Redis内置是有16383个槽。每个Redis节点存储一部分虚拟槽。将redis集群分成16384个槽,每个master1节点负责一些槽。
java
【特点:】key不是与节点绑定,而是与虚拟槽点绑定。redis会根据【key的有效部分】计算插槽值,主要分为两种情况:
- key中包含"{}",且"{}"中至少包含一个字符,使用"{num}"使用num来计算插槽值slot;
- 否则,使用key来计算插槽值slot;
场景:计算某个key在哪个实例?
1. 将16384个插槽分配到不同的实例上;
2. 根据key的有效部分计算哈希值,对16384取余;
3. 余数作为插槽,寻找插槽所在的实例即可。
【好处:】
4. 方便的添加或移除节点;
5. 对应槽的采用【直接复制,槽不变化】数据过去显然比rehash快很多
为什么是16384(2^14)个?
答:因为redis发送心跳包时,会将所有槽信息放到心跳包中,发送给其他的redis来交换集群信息。CRC16算法产生的hash值有16bit,但是redis cluster实例建议不超过1000个,超过1000个容易发生网络阻塞
,而在redis实例不超过1000个的情况下,将redis集群划分成16384个槽占用的大小的是2k
,是比较节省内存空间的,否则使用16bit占用内存大小为16k,完全没有必要。
五、哨兵模式和集群模式的区别
5.1 哨兵模式
优点:
高可用,在主节点出现故障时实现故障的转移
缺点:
集群容量一旦达到上限,在线扩容十分麻烦,无法做到水平拓展
5.2 集群模式
优点:
可以横向扩展
缺点:
客户端实现复杂,且slave节点不提供读写的能力,仅仅是一个冷备节点
5.3 区别
- 哨兵模式监控权交给了哨兵系统;集群模式中工作节点自己做监控
- 哨兵模式发起选举是选举一个leader哨兵节点来处理故障转移;集群模式在节点中选举一个新的主节点来处理故障的转移。