集群
# 1 主从复制
# 1.1 全量复制
1.如果你为master配置了一个slave,不管这个slave是否是第一次连接上Master,它都会发送一个PSYNC命令给master请求复制数据。
2.master收到PSYNC命令后,会在后台进行数据持久化通过bgsave生成最新的rdb快照文件。
3.持久化期间,master会继续接收客户端的请求,它会把这些可能修改数据集的请求缓存在内存中。
4.当持久化进行完毕以后,master会把这份rdb文件数据集发送给slave,slave会把接收到的数据进行持久化生成rdb,然后再加载到内存中。
5.然后,master再将之前缓存在内存中的命令发送给slave。
6.当master与slave之间的连接由于某些原因而断开时,slave能够自动重连Master,如果master收到了多 个slave并发连接请求,它只会进行一次持久化,而不是一个连接一次,然后再把这一份持久化的数据发送给多个并发连接的slave。
# 1.2 部分复制、断点续传
1.master会在其内存中创建一个复制数据用的缓存队列,缓存最近一段时间的数据。
2.master和它所有的slave都维护了复制的数据下标offset和master的进程id,因此,当网络连接断开后,slave会请求master继续进行未完成的复制,从所记录的数据下标开始。
3.如果master进程id变化了,或者从节点数据下标offset太旧,已经不在master的缓存队列里了,那么将会进行一次全量数据的复制。
# 1.3 主从复制风暴
如果有很多从节点,为了缓解主从复制风暴(多个从节点同时复制主节点导致主节点压力过大),可以做如 下架构,让部分从节点与从节点(与主节点同步)同步数据。
# 2 哨兵模式
1.sentinel哨兵是特殊的redis服务,不提供读写服务,主要用来监控redis实例节点。
2.哨兵架构下client端第一次从哨兵找出redis的主节点,后续就直接访问redis的主节点,不会每次都通过 sentinel代理访问redis的主节点,当redis的主节点发生变化,哨兵会第一时间感知到,并且将新的redis主节点通知给client端。
缺点:
1.哨兵的配置较复杂。
2.主从切换的瞬间存在访问瞬断的情况。
3.哨兵模式只有一个主节点对外提供服务,没法支持很高并发。且单个主节点内存不宜设置得过大,否则会导致持久化文件过大,影响数据恢复或主从同步的效率。
# 3 高可用集群模式
集群模式没有中心节点,可水平扩展,可以线性扩展到上万个节点(官方推荐不超过1000个节点)。
Redis Cluster 将所有数据划分为 16384 个 slots(槽位),每个节点负责其中一部分槽位。槽位的信息存储于每个节点中。
槽位定位算法
Cluster 默认会对 key 值使用 crc16 算法进行 hash 得到一个整数值,然后用这个整数值对16384进行取模来得到具体槽位。
HASH_SLOT = CRC16(key) mod 16384
# 4 Redis集群节点间的通信机制
集中式:
优点在于元数据的更新和读取,时效性非常好,一旦元数据出现变更立即就会更新到集中式的存储中,其他节点读取的时候立即就可以立即感知到;不足在于所有的元数据的更新压力全部集中在一个地方,可能导致元数据的存储压力。 很多中间件都会借助zookeeper集中式存储元数据。
Redis集群节点间采用gossip协议进行通信。
gossip协议包括多种消息,包括ping,pong,meet,fail等等。
优点:
元数据更新比较分散,不是集中在一个地方,更新请求会陆陆续续,打到所有节点上去更新,有一定延时,降低了压力。
缺点:
元数据更新有延时可能导致集群的一些操作会有一些滞后。
# 5 Redis集群选举
# 5.1 选举流程
当slave发现自己的master变为FAIL状态时,便尝试进行Failover,以期成为新的master。由于挂掉的master 可能会有多个slave,从而存在多个slave竞争成为master节点的过程, 其过程如下:
1.slave发现自己的master变为FAIL。
2.将自己记录的集群currentEpoch加1,并广播FAILOVER_AUTH_REQUEST信息。
3.其他节点收到该信息,只有master响应,判断请求者的合法性,并发送FAILOVER_AUTH_ACK,对每一个 epoch只发送一次ack。
4.尝试failover的slave收集master返回的FAILOVER_AUTH_ACK。
5.slave收到超过半数master的ack后变成新Master。
(这里解释了集群为什么至少需要三个主节点,如果只有两个,当其中一个挂了,只剩一个主节点是不能选举成功的)
6.slave广播Pong消息通知其他集群节点。
从节点并不是在主节点一进入 FAIL 状态就马上尝试发起选举,而是有一定延迟,一定的延迟确保我们等待 FAIL状态在集群中传播,slave如果立即尝试选举,其它masters或许尚未意识到FAIL状态,可能会拒绝投票。
延迟计算公式:
DELAY = 500ms + random(0 ~ 500ms) + SLAVE_RANK * 1000ms
SLAVE_RANK表示此slave已经从master复制数据的总量的rank。Rank越小代表已复制的数据越新。这种方式下,持有最新数据的slave将会首先发起选举(理论上)。
# 5.2 集群脑裂问题
Redis集群没有过半机制会有脑裂问题,网络分区导致脑裂后多个主节点对外提供写服务,一旦网络分区恢复,会将其中一个主节点变为从节点,这时会有大量数据丢失。
# 5.3 Redis集群为什么至少要三个master节点,并且推荐奇数?
选举新master需要大于半数的集群master节点同意才能选举成功,如果只有两个master节点,挂了一个,就达不到过半数选举的条件。
奇数个master节点可以在满足选举条件的基础上节省一个节点。比如三个master跟四个master,大家挂了一个都可以选举新master,挂了两个都不可以选举新master。所以奇数的master节点更多的是从节省机器资源角度出发说的。
# 6 常见问题
# 6.1 Redis集群下可以执行批量操作命令吗?
Redis集群是没法执行批量操作命令的,如mget,pipeline等。这是因为redis将集群划分为16383个哈希槽,不同的key会划分到不同的槽中。
但是,Jedis客户端提供了计算key的slot方法,以及slot和节点之间的映射关系,通过这两个数据,就可以计算出每个key所在的节点,然后使用pipeline获取数据。
# 6.2 Redis集群支持多数据库吗?
Redis集群是不支持多数据库的,只有一个数据库空间,默认 SELECT 0,即db0。
# 6.3 Redis集群不足的地方?
1.集群模式下做批量操作比较麻烦,需要自己计算处理。
2.假如有一个key,对应的value是hash类型的,不支持映射到集群的不同节点。
# 6.4 Redis集群方案什么情况下会导致集群不可用?
当redis.conf的配置cluster-require-full-coverage为no时,表示当负责一个插槽的主节点下线且没有相应的从节点进行故障恢复时,集群仍然可用,如果为yes则集群不可用。