1.哨兵集群
哨兵+主从。一主两从。
+----+
| M1 |
| S1 |
+----+
|
+----+ | +----+
| R2 |----+----| R3 |
| S2 | | S3 |
+----+ +----+
当Master宕机后,s1和s2在认定之后,会通过选举机制选举出新的主节点,进行故障转移。
哨兵的主要功能:
集群监控:负责Redis Master 和Slave的正常工作。
消息通知:如果Redis实例有故障,哨兵负责发送消息作为报警通知给管理员。
故障转移:如果Master node挂掉之后,从节点经过选举机制会自动选举出新的主节点。
配置中心:在故障转移之后,通知client客户端新的master地址。
主备切换时的数据丢失问题:
1.初步复制导致的数据丢失。
master -> slave复制是异步的,如果数据还没有复制到slave,master就宕机了,就会造成数据丢失。
2.脑裂导致的数据丢失。
某个主人所在机器突然脱离了正常的网络,跟其他奴隶机器不能连接,但是实际上master仍然运行着。此时哨兵可能就会认为 master停机机了,然后开启选举,将其他奴隶转换为master。这个时候,积累里就会有两个master,也就是所谓的脑裂。
此时有时某个slave被切换为master,但是可能客户端还没来得及切换到新的master,还继续向旧master写数据。因此旧master再次恢复的时候,会被作为一个slave挂到新的master上去,自己的数据会清空,重新从新的master复制数据。而新的master并没有后来client写入的数据,因此,这部分数据也就丢了。
数据丢失的解决方案
min-slaves-to-write 1
min-slaves-max-lag 10
表示,要求至少有1个slave,数据复制和同步的重复不能超过10秒。
如果说一旦所有的slave,数据复制和同步的重复都超过了10秒钟,那么这个时候,master就不会再接收任何请求了。
1.减少初始化复制数据的丢失
有了min-slaves-max-lag
这个配置,就可以确保说,一旦slave复制数据和ack立刻太长,就认为可能master停机机后损失的数据太多了,那么就拒绝写请求,这样可以把master停机时由于部分数据未同步到slave导致的数据丢失降低的可控范围内。
2.减少脑裂的数据丢失
如果一个主人出现了脑裂,跟其他奴隶丢了连接,那么上面两个配置可以确保说,如果不能继续给指定数量的奴隶发送数据,而且奴隶超过10秒没有给自己ack消息,那么就直接拒绝客户端的写请求。因此在脑裂场景下,最多就丢失10秒的数据。
slave ->master的选举算法
如果一个主人被认为是odown了,而且多数是数量的哨兵都允许主备切换,那么某个哨兵就会执行主备切换操作,然后首先要选举一个奴隶来,会考虑奴隶的一些信息:
- 跟master顶端连接的时长
- slave优先级
- 复制偏移
- 运行ID
如果一个奴隶跟主人粉碎连接的时间已经超过了down-after-milliseconds
的10倍,外加主人停机机的时长,那么奴隶就被认为不适合选举为主人。
(down-after-milliseconds * 10) + milliseconds_since_master_is_in_SDOWN_state
接下来进行slave进行排序:
- 按照slave优先级进行排序,slave优先级越低,优先级就可以。
- 如果slave优先级相同,那么看副本的偏移量,那个slave复制了越多的数据,offset越靠后,优先级就可以。
- 如果上面两个条件都相同,那么选择一个run id比较小的那个slave。
2.Redis Cluster
简介
- 自动将数据进行分片,每个 master 上放一部分数据
- 提供内置的高可用支持,部分 master 不可用时,还是可以继续工作的
在Redis Cluster架构下,每个Redis需要开通2个端口号,6379,16379。
16379是用来进行节点间通信的,也就是cluster bus。该通信用来进行故障检测、配置更新、故障转移授权。使用gossip
二进制协议,用于节点之间高效的数据交换,占用更少的网络带宽和处理时间。
分布式寻址算法
- hash 算法(大量缓存重建)
- 一致性 hash 算法(自动缓存迁移)+ 虚拟节点(自动负载均衡)
- redis cluster 的 hash slot 算法
hash 算法
来了一个 key,首先计算 hash 值,然后对节点数取模。然后打在不同的 master 节点上。一旦某一个 master 节点宕机,所有请求过来,都会基于最新的剩余 master 节点数去取模,尝试去取数据。这会导致大部分的请求过来,全部无法拿到有效的缓存,导致大量的流量涌入数据库。
一致性 hash 算法
一致性 hash 算法将整个 hash 值空间组织成一个虚拟的圆环,整个空间按顺时针方向组织,下一步将各个 master 节点(使用服务器的 ip 或主机名)进行 hash。这样就能确定每个节点在其哈希环上的位置。
来了一个 key,首先计算 hash 值,并确定此数据在环上的位置,从此位置沿环顺时针“行走”,遇到的第一个 master 节点就是 key 所在位置。
在一致性哈希算法中,如果一个节点挂了,受影响的数据仅仅是此节点到环空间前一个节点(沿着逆时针方向行走遇到的第一个节点)之间的数据,其它不受影响。增加一个节点也同理。
然而,一致性哈希算法在节点太少时,容易因为节点分布不均匀而造成缓存热点的问题。为了解决这种热点问题,一致性 hash 算法引入了虚拟节点机制,即对每一个节点计算多个 hash,每个计算结果位置都放置一个虚拟节点。这样就实现了数据的均匀分布,负载均衡。
redis cluster 的 hash slot 算法
redis cluster 有固定的 16384
个 hash slot,对每个 key
计算 CRC16
值,然后对 16384
取模,可以获取 key 对应的 hash slot。
redis cluster 中每个 master 都会持有部分 slot,比如有 3 个 master,那么可能每个 master 持有 5000 多个 hash slot。hash slot 让 node 的增加和移除很简单,增加一个 master,就将其他 master 的 hash slot 移动部分过去,减少一个 master,就将它的 hash slot 移动到其他 master 上去。移动 hash slot 的成本是非常低的。客户端的 api,可以对指定的数据,让他们走同一个 hash slot,通过 hash tag
来实现。
任何一台机器宕机,另外两个节点,不影响的。因为 key 找的是 hash slot,不是机器。
redis cluster 的高可用与主备切换原理
edis cluster 的高可用的原理,几乎跟哨兵是类似的。
判断节点宕机
如果一个节点认为另外一个节点宕机,那么就是 pfail
,主观宕机。如果多个节点都认为另外一个节点宕机了,那么就是 fail
,客观宕机,跟哨兵的原理几乎一样,sdown,odown。
在 cluster-node-timeout
内,某个节点一直没有返回 pong
,那么就被认为 pfail
。
如果一个节点认为某个节点 pfail
了,那么会在 gossip ping
消息中,ping
给其他节点,如果超过半数的节点都认为 pfail
了,那么就会变成 fail
。
从节点过滤
对宕机的 master node,从其所有的 slave node 中,选择一个切换成 master node。
检查每个 slave node 与 master node 断开连接的时间,如果超过了 cluster-node-timeout * cluster-slave-validity-factor
,那么就没有资格切换成 master
。
从节点选举
每个从节点,都根据自己对 master 复制数据的 offset,来设置一个选举时间,offset 越大(复制数据越多)的从节点,选举时间越靠前,优先进行选举。
所有的 master node 开始 slave 选举投票,给要进行选举的 slave 进行投票,如果大部分 master node(N/2 + 1)
都投票给了某个从节点,那么选举通过,那个从节点可以切换成 master。
从节点执行主备切换,从节点切换为主节点。
与哨兵比较
整个流程跟哨兵相比,非常类似,所以说,redis cluster 功能强大,直接集成了 replication 和 sentinel 的功能。
3.Redis同步机制
单机QPS是有上限的,如果一个节点又读又写,性能肯定是上不去的。读写分离就非常有必要了。从节点的复制分为全量复制和增量复制。
当启动slave的时候,会向master发送一个psync指令,如果是首次连接到master的话,会触发一个全量复制。master会启动一个线程,生成RDB快照,同时把新的写请求都缓存在内存中。RDB文件生成之后,master会将RDB发送给slave,slave先将文件写入磁盘,然后再加载至内存,然后master会把缓存中的新指令再发送给slave。
复制的核心流程:
- redis采用异步方式复制数据到slave路由器,不过redis2.8开始,slave节点会引发地确认自己每次复制的数据量;
- 一个主节点是可以配置多个从节点的;
- slave node也可以连接其他的
- slave node做复制的时候,不会阻塞master node的正常工作;
- slave node在做复制的时候,也不会阻止对自己的查询操作,它会用旧的数据集来提供服务;但是复制完成的时候,需要删除旧数据集,加载新数据集,这个时候就会暂停对外服务了;
- slave node主要用来进行横向扩容,做分离分离,扩容的slave node可以提高读的裂缝。
注意点:
1.全量复制时从节点复制时间超过60s,会判定为复制失败。
2.复制期间,内存占用连续超过64M,或一次性超过256M,则会停止复制,复制失败。
client-output-buffer-limit slave 256MB 64MB 60
3.心跳机制:主节点每10s发送一次心跳,从节点每隔1s发送一次心跳。
总结
Redis Sentinal用于高可用,在master宕机时会自动的将slave提升为master,继续提供服务。
Redis Cluster着眼于扩展性,当单个Redis内存不足是,使用Cluster进行分片存储。