答:
Redis 切片集群是目前使用比较多的方案,Redis 切面集群支持多个主从集群进行横向扩容,架构如下:
使用切片集群有什么好处?
提升 Redis 读写性能,之前的主从模式中,只有 1 个 master 可以进行写操作,在切片集群中,多个 master 承担写操作压力
多个主从集群进行存储数据,比单个主从集群存储数据更多
比如10G数据,1个主从集群的话,1个master需要存储10G,对有3个主从集群的切片集群来说,只需要master1存储3G,master2存储3G,master3存储4G即可
具备主从复制、故障转移
切片集群中的每一个主从集群中,slave 节点不支持读,只做数据备份,因为已经有其他master节点分担压力
切片集群支持水平扩容,可以无限扩容吗?
不可以,官方推荐不要超过1000个,因为各个小集群之间需要互相进行通信,如果水平节点过多,会影响通信效率。
切片集群中插入数据时,数据被放在哪个master中?
Redis 切片集群中,数据是通过 哈希槽分区
来存储的,Redis 切片集群中有 16384
个哈希槽,每一个 master 会拿到一些槽位,在向切片集群中插入数据时,会根据 key 计算对应的哈希槽,插入到对应的哈希槽中,那么计算出来的哈希槽在哪个master中,数据当然也就被存放在对应的master上。(在切片集群中,只有master节点才有插槽,slave节点没有插槽)
故障恢复(Failover):切片集群中如果一个master挂了,如何选举主节点?
当 master 挂了之后,该 master 下的所有 slave 会向所有节点广播 FAILOVER_AUTH_REQUEST
信息,其他节点收到后,只有 master 响应,master 会相应第一个收到的 FAILOVER_AUTH_REQUEST
信息,并返回一个 ack,尝试发送 failover 的 slave 会收集 master 返回的 FAILOVER_AUTH_ACK
,当 slave 收到超过半数的 master 的 ack 后,就会变成新的 master。
这样会导致 slave 一直没收到超过半数的 master 的 ack,难道要一直选举吗?
其实不会导致 slave 一直选举的,因为在 slave 知道 master 挂了之后,会经过一个延时时间 delay
之后再去给所有节点发送选举消息
延迟时间计算:delay = 500ms + random(0~500ms) + slave_rank * 1000ms
(版本不同可能不一样,原理大致相同)
slave_rank表示slave已经从master复制数据的总量的rank,rank越小,表示复制的数据越新,该slave节点也就越先发起选举。
因此数据量越多的 slave 就越早发送选举消息,也就越早得到 master 的 ack,成为新的 master。
集群切片中的脑裂问题了解吗?如何解决?
比如一个主从集群:master1 对应两个从节点 slave1、slave2,如果master1和两个从节点出现网络分区,两个slave会选举出来一个新的master节点,客户端是可以感知到两个master,但是两个master之间因为网络分区无法感知,客户端会向这两个master都写入数据,之后如果网络分区恢复,其中一个master变为slave,就会导致数据丢失问题。
如何解决?添加redis配置:
min-slave-to-write 1
表示写数据时,写入master之后,不立即返回客户端写成功,而是去slave同步数据,取值为1表示最少同步1个slave之后,才算数据写成功,如果同步的slave节点数量没有达到我们配置的值,就算数据写失败,取值建议:集群总共3个节点,可以取1,这样集群中超过半数(1个master + 1个slave)都写入数据成功,才算写成功。
但是这个配置为了数据的一致性,牺牲了一定的集群可用性,如果一个master的所有slave都挂了,这个小集群就不可用了,master无法写入数据。
一般不使用,redis丢一点数据也影响不大,所以主要还是保证redis的可用性
集群是否完整才能对外提供服务?
当redis.conf配置 cluster-require-full-coverage no
时,表示如果一个主从集群全部挂掉之后,集群仍然可用,如果为 yes,表示不可用
比如有3个主从集群,其中一个主从集群全部瘫痪,配置为no,则整个集群仍然可以正常工作
Redis集群如何对批量操作命令的支持?
对于 mset、mget 这样的多个 key 的原生批量操作命令,redis 集群只支持所有key落在同一个slot的情况,如果多个key一定要用mset在redis集群上操作,则可以在key之前加上{XX},这样就会根据大括号中的内容计算分片hash,确保不同的key落在同一slot内,例如:
mset {user1}: name zhuge {user1}:age 18
虽然name和age计算出来的 hash slot 值不同,但是前边加上大括号{user1},redis集群就会根据 user1 计算插槽值,最后name和age可以放入同一插槽。