08.Redis集群
# 01.Redis主从
# 1.1 主从原理
- 1、和MySQL主从复制的原因一样,Redis虽然读取写入的速度都特别快,但是也会产生读压力特别大的情况
- 2、为了分担读压力,Redis支持主从复制,Redis的主从结构可以采用一主多从或者级联结构
- 3、Redis主从复制可以根据是否是全量分为全量同步和增量同步
- 注:Redis主节点Master挂掉时,运维让从节点Slave接管(
Redis主从默认无法自动切换,需要运维手动切换
)
# 1.2 主从复制优点
- 支持主从复制,主机会自动将数据同步到从机,可以进行读写分离;
- 为了分载 Master 的读操作压力,Slave 服务器可以为客户端提供只读操作的服务,写服务仍然必须由Master来完成;
# 1.3 主从复制缺点
- Redis不具备自动容错和恢复功能,主机从机的宕机都会导致前端部分读写请求失败
- 需要等待机器重启或者手动切换前端的IP才能恢复(也就是要人工介入);
- 主机宕机,宕机前有部分数据未能及时同步到从机,切换IP后还会引入数据不一致的问题,降低了系统的可用性;
# 02.哨兵模式
# 1.2.1 sentinel作用
1.当用Redis做主从方案时,假如master宕机,Redis本身无法自动进行主备切换
2.而Redis-sentinel本身也是一个独立运行的进程,它能监控多个master-slave集群,发现master宕机后能进行自动切换
# 1.2.2 sentinel原理
1.sentinel负责持续监控主节点的健康,当主节挂掉时,自动选择一个最优的从节点切换成主节点
2.从节点来连接集群时会首先连接sentinel,通过sentinel来查询主节点的地址
3.当主节点发生故障时,sentinel会将最新的主节点地址告诉客户端,可以实现无需重启自动切换Redis
# 1.2.3 Sentinel支持集群
1.只使用单个sentinel进程来监控Redis集群是不可靠的,当sentinel进程宕掉后sentinel本身也有单点问题
2.如果有多个sentinel,Redis的客户端可以随意地连接任意一个sentinel来获得关于Redis集群中的信息
# 1.2.4 Sentinel版本
1.Sentinel当前稳定版本称为Sentinel 2,Redis2.8和Redis3.0附带稳定的哨兵版本
2.安装完Redis-3.2.8后,Redis-3.2.8/src/Redis-sentinel启动程序 Redis-3.2.8/sentinel.conf是配置文件
# 1.3.5 哨兵模式的优缺点
优点:
- 哨兵模式是基于主从模式的,所有主从的优点,哨兵模式都具有
- 主从可以自动切换,系统更健壮,可用性更高(可以看作自动版的主从复制)
缺点:
- Redis较难支持在线扩容,在集群容量达到上限时在线扩容会变得很复杂
# 03.codis集群
# 1.3.1 为什么会出现codis
1.在大数据高并发场景下,单个Redis实例往往会无法应对
2.首先Redis内存不易过大,内存太大会导致rdb文件过大,导致主从同步时间过长
3.其次在CPU利用率中上,单个Redis实例只能利用单核,数据量太大,压力就会特别大
# 1.3.2 什么是codis
- 1.codis是Redis集群解决方案之一,codis是GO语言开发的代理中间件
- 2.当客户端向codis发送指令时,codis负责将指令转发给后面的Redis实例来执行,并将返回结果转发给客户端
- 3.Codis是由国人前豌豆荚大神开发的,采用中心化方式的集群方案
- 4.因为需要代理层Proxy来进行所有请求的转发,所以对Proxy的性能要求很高
# 1.3.3 codis部署方案
1.单个codis代理支撑的QPS比较有限,通过启动多个codis代理可以显著增加整体QPS
2.多codis还能起到容灾功能,挂掉一个codis代理还有很多codis代理可以继续服务
# 1.3.4 codis分片的原理
1.codis负责将特定key转发到特定Redis实例,codis默认将所有key划分为1024个槽位
2.首先会对客户端传来的key进行crc32计算hash值,然后将hash后的整数值对1024进行取模,这个余数就是对应的key槽位
3.每个槽位都会唯一映射到后面的多个Redis实例之一,codis会在内存中维护槽位和Redis实例的映射关系
4.这样有了上面key对应的槽位,那么它应该转发到那个Redis实例就很明确了
5.槽位数量默认是1024,如果集群中节点较多,建议将这个数值大一些,比如2048,4096
# 1.3.5 不同codis槽位如何同步
1.如果codis槽位值存在内存中,那么不同的codis实例间的槽位关系得不到同步
2.所以codis还需要一个分布式配置存储的数据库专门来持久化槽位关系
3.codis将槽位关系存储在zookeeper中,并且提供一个dashboard可以来观察和修改槽位关系
# 04.Cluster集群模式
# 4.1 什么是Redis集群
- Redis Cluster是一种服务器 Sharding 技术,3.0版本开始正式提供
- Redis 的哨兵模式基本已经可以实现高可用,读写分离
- 但是在这种模式下每台 Redis 服务器都存储相同的数据,很浪费内存
- 所以在 Redis3.0上加入了 Cluster 集群模式,实现了 Redis 的分布式存储
也就是说每台 Redis 节点上存储不同的内容
# 4.2 cordis集群模式弊端
codis采用中间加一层Proxy的中心化模式时,这就对Proxy的要求很高
因为它一旦出现故障,那么操作这个Proxy的所有客户端都无法处理
要想实现Proxy的高可用,还需要另外的机制来实现,例如Keepalive
而且增加一层Proxy进行转发,必然会有一定的性能损耗
那么除了客户端分片和上面提到的中心化的方案之外,还有比较好的解决方案么?
# 4.3 Cluster集群模式
Redis官方推出的Redis Cluster另辟蹊径,它没有采用中心化模式的Proxy方案
而是把请求转发逻辑一部分放在客户端,一部分放在了服务端,它们之间互相配合完成请求的处理
Redis Cluster采用16384个槽位进行路由规则的转发
在这个图中,每一个蓝色的圈都代表着一个 Redis 的服务器节点
它们任何两个节点之间都是相互连通的
客户端可以与任何一个节点相连接,然后就可以访问集群中的任何一个节点,对其进行存取和其他操作
Redis 集群有16384 个哈希槽,每个 key 通过 CRC16 校验后对 16384 取模来决定放置哪个槽
集群的每个节点负责一部分hash槽
,举个例子,比如当前集群有3个节点,那么:节点 A 包含 0 到 5460 号哈希槽
节点 B 包含 5461 到 10922 号哈希槽
节点 C 包含 10923 到 16383 号哈希槽
# 10.脑裂
# 0、脑裂原因
- 网络分区:
- 当主节点和从节点之间的网络连接中断时,主节点可能仍然可以提供服务,但从节点无法与主节点通信
- 在这种情况下,某些机制(如自动故障转移)可能会导致从节点升级为主节点,形成两个主节点
- 节点故障:
- 主节点短暂故障或暂停后恢复,但此时其他从节点已经接管了主节点的职责,形成两个主节点同时运行的情况
- 过度敏感的故障转移机制:
- 当故障检测机制过于敏感时,可能会因为短暂的网络抖动而触发错误的故障转移,导致脑裂
- 配置错误:
- 不当的集群配置或不正确的运维操作可能导致多个节点在误判情况下同时认为自己是主节点
# 1、哨兵模式脑裂
配置 quorum(仲裁数量):
确保
quorum
(仲裁节点数量)足够大,避免因为少数哨兵的误判导致的故障转移例如,配置
quorum
为 3,表示至少 3 个 Sentinel 节点同意主节点故障时,才会触发故障转移,减少错误的主从切换
配置
min-slaves-to-write
:该配置项要求主节点在提供写服务前,必须有指定数量的从节点处于可连接状态
这在一定程度上可以防止主节点因为网络分区导致的孤立而继续提供服务
min-slaves-to-write 1 min-slaves-max-lag 10
1
2该配置要求至少有一个从节点延迟小于 10 秒时,主节点才允许执行写操作
否则,即便主节点仍然在运行,它也会停止对外提供服务,避免脑裂导致的数据不一致问题
自动修复机制:
- 在网络恢复时,Sentinel 会自动尝试将以前的主节点作为从节点重新加入到集群中
- 通过这一步,Redis 集群可以确保数据重新同步,并防止持久性脑裂问题
# 2、Redis Cluster 脑裂
在 Redis Cluster 模式下,脑裂问题会在某些节点短暂失联时发生,导致集群中的多个节点认为自己是主节点
cluster-require-full-coverage
参数:- 这个参数决定集群中某些分片出现故障时,是否允许继续服务
- 如果设置为
yes
,即使部分分片不可用,集群仍然可以对外提供服务 - 但如果设置为
no
,则集群会拒绝提供服务,直到所有分片都可用
防止过早选举新主节点:
Redis Cluster 在触发故障转移前会设置一定的时间间隔,避免因为短暂的网络抖动或节点失联就触发选举
可以通过配置
cluster-node-timeout
来调整节点之间失联的时间阈值,避免因小故障引发脑裂这个配置表示节点失联超过 5000 毫秒(5 秒)后,才会触发故障转移,从而降低发生脑裂的可能性
cluster-slave-validity-factor
参数:该参数控制了从节点在多长时间未与主节点同步时还能参与选举
防止不合适的从节点成为新的主节点,导致不一致数据的出现
这个配置表示从节点在 10 秒内没有与主节点同步数据后,仍然有资格参与主节点选举
如果设置得较小,可以减少数据不一致的风险,但也会降低故障转移的灵活性
# 3、 Raft
算法
为了更好地解决分布式系统中的脑裂问题,一些 Redis 高可用解决方案(如
RedisRaft
)尝试通过实现 Raft 共识算法来解决Raft 是一种强一致性算法,在集群中的每个节点都会定期选举出一个 leader(类似于 Redis 的主节点)
而 leader 负责处理所有写请求并将数据复制到其他节点
通过这一机制,Raft 可以有效防止脑裂问题的出现
Raft 的选举过程需要多数节点(quorum)达成一致才能选举出新的 leader,避免了脑裂情况的发生
当网络恢复时,Raft 可以自动将“落后”的节点重新同步到最新状态,保证数据的一致性
虽然 Redis 本身并未实现 Raft,但一些扩展项目(如
RedisRaft
)在 Redis 集群上引入了 Raft 算法,以进一步增强其一致性和容错能力
# 4、人为运维干预
除了自动化机制,在特殊情况下,还可以通过人为干预来解决 Redis 脑裂问题
手动关闭孤立主节点:
- 在发生脑裂时,可以手动将错误的主节点关闭,确保集群中的唯一主节点继续提供服务
- 这需要有可靠的监控系统来及时发现和处理脑裂问题
网络优化:定期优化网络架构,减少网络分区发生的概率,从根本上避免脑裂