Redis高可用

Redis是一个单线程的高性能数据库,单线程的设计使得Redis在高并发场景下性能优越,但是也带来了单点故障的问题。为了避免单点故障,Redis提供了主从复制、哨兵和集群三种高可用方案,哨兵模式可以看作是主从复制架构的高可用扩展。

主从复制

主从复制是Redis最基本的高可用方案,通过将数据从主节点复制到从节点来实现数据的冗余备份。主节点负责处理写请求,从节点负责处理读请求。主从复制的优点是简单易用,缺点是主节点宕机后需要手动切换到从节点。

主从复制架构怎么复制数据? 主从复制架构是通过主节点的RDB快照和AOF日志来实现数据的复制的。

  1. 第一次同步:从节点启动时,会向主节点发送SYNC命令,主节点会将启用后台线程生成RDB数据快照,然后把当前的RDB数据快照发送给从节点,从节点接收到数据快照后,会将数据加载到内存中。
  2. 后续同步:从节点会向主节点发送PSYNC命令,主节点会将从节点的复制偏移量和当前的复制偏移量进行比较,如果相同,则只发送增量数据,否则重新发送数据快照。
  3. 主节点宕机:如果主节点宕机,没有哨兵的情况下,需要手动把某个从节点切换为主节点,并开始接受写请求。
  4. 从节点宕机:如果从节点宕机,主节点会继续处理写请求,从节点恢复后会向主节点发送PSYNC命令进行数据同步。
  5. 在主节点生成RDB快照、发送RDB快照、从节点加载RDB快照这三个过程中,主节点会将写操作命令缓存到内存中,等RDB快照发送完成后,再将缓存的写操作命令发送给从节点。

主从复制架构中主节点和从节点如何保持联系?

通过长连接的命令传播:在完成第一次同步之后,双方会维护一个TCP长连接,之后主节点会将写操作命令通过这个长连接发送给从节点。

主节点怎么处理很多从节点的同步请求?

replicaof <目标服务器的IP> 6379命令会将当前节点设置为从节点,并连接到目标服务器的6379端口。我们可以部分从节点连接到另外的从节点,形成从从节点的结构。这样可以减少主节点的压力。

从节点宕机重启之后,怎么确定是全量同步还是增量同步?

从节点在重启时会向主节点发送PSYNC命令,以一个offset作为参数。主节点维护了一个环形缓冲区,缓存主节点的写操作命令,还维护了自己写到的位置offset。比较这两个偏移量可以判断需要同步的数据是不是在缓冲区中,如果在缓冲区中,则只需要增量同步,否则需要全量同步。

主从复制有哪几种方式?

全量复制、增量复制和长连接命令传播。

哨兵

哨兵是Redis的高可用解决方案,通过监控主节点和从节点的状态来实现自动故障转移。哨兵会定期向主节点和从节点发送PING命令,如果主节点宕机,哨兵会自动将从节点提升为主节点,并通知其他从节点进行复制。所以哨兵主要是三个功能:

  1. 监控:定期向主节点和从节点发送PING命令,检查节点的状态。
  2. 选举:当主节点宕机时,哨兵会自动选举一个从节点提升为主节点。
  3. 通知:当主节点宕机时,哨兵会通知客户端和从节点进行切换。

下面以一个主节点故障说明哨兵模式是怎么实现主节点故障转移的,首先把宕机的主节点标记为“客观下线”:

  1. 为了减少误判和哨兵的单点故障,需要至少三个哨兵节点,组成一个哨兵集群。(记为哨兵A/B/C)
  2. 所有哨兵节点会定期向主节点和从节点发送PING命令,检查节点的状态。
  3. 如果哨兵A没有收到主节点的PING响应,哨兵A会把主节点标记为“主观下线”。
  4. 哨兵A会向其它哨兵节点发起投票,询问是否也认为主节点宕机。
  5. 其它哨兵节点也会向主节点发送PING命令,如果没有收到响应,则会投票支持哨兵A的判断。
  6. 如果“主节点下线”获得超过半数的投票,集群则会将主节点标记为“客观下线”。

接下来哨兵会选举一个从节点提升为主节点:

  1. 哨兵集群会首先从选出自己的leader节点,leader节点会负责后续的选举和通知工作。
  2. 选举一个从节点提升为主节点,哨兵会向所有从节点发送INFO命令,获取从节点的状态信息。
  3. 哨兵会根据从节点的状态信息,选举一个从节点提升为主节点。
  4. 哨兵会向选举出的从节点发送SLAVEOF NO ONE命令,将其提升为主节点。
  5. 哨兵会向所有从节点发送SLAVEOF <新主节点的IP>命令,将其设置为新的从节点。
  6. 哨兵会通过发布/订阅模式向客户端发送通知,告知主节点已经切换。
  7. 哨兵会持续监控之前的主节点,当其恢复之后,哨兵会将其设置为从节点,并将其数据同步到新的主节点。

到这里主节点故障转移完成。

集群

当数据量和并发请求量达到一台机器承受不了,需要使用Redis集群模式,进行数据分片,提供数据扩容和新的故障转移机制。这种集群又被叫做切片集群方案。

怎么写数据?

一个集群包括若干个hash槽,写数据时会根据键值计算hash值,找到对应的hash槽,然后将数据写到对应的节点中。每个节点由一个主节点和多个从节点组成,主节点负责处理写请求,从节点负责处理读请求。

怎么读数据?

  1. 客户端读数据时会根据键值计算hash值,找到对应的hash槽,然后将数据从对应的节点中读取。
  2. 集群节点收到请求后,会根据hash槽的映射关系,查看两个信息:
    1. hash槽是不是存在当前节点。
    2. 如果hash槽不在当前节点,则会返回MOVE重定向错误,把哈希槽所在的新实例的IP和port端口带回去。客户端会重新访问。
    3. 如果hash槽在当前节点,则会直接从当前节点读取数据(如果存在的话)。
  3. 当集群伸缩,节点会自动重新分配hash槽。这时候当前节点会返回ASK重定向错误,告诉客户端当前节点已经不再负责这个hash槽了,客户端会重新访问ASK重定向的节点。

集群节点怎么通信?

Gosiip协议。每个节点周期性选择k个节点进行通信,将本节点信息传播出去,直到所有节点都知道集群状态信息(一种谣言传播机制)。传播的信息包括:节点故障、主从节点变更,节点状态等。

集群节点怎么选举?

当一个集群节点主节点故障,集群会自动选举一个从节点提升为主节点。选举的过程如下:

  1. 槽节点之间进行通信,一个槽节点A标记另外一个槽节点C为下线为“主观下线”,即C主节点出问题。
  2. 其他槽节点会向槽节点C主节点发送PING命令,如果没有收到响应,则会投票支持主节点的判断,当“槽节点C主节点下线”获得超过半数的投票,集群则会将槽节点C主节点标记为“客观下线”。
  3. 集群会从槽节点C的从节点中选举一个从节点提升为主节点。

总结

介绍了三种高可用方案(实际是两种),主要是从数据可用和故障转移两方面来实现高可用。最后聊一下客户端是怎么知道Redis的高可用方案的。Redis提供了一个INFO命令,可以获取当前节点的状态信息,包括主节点和从节点的信息。客户端可以通过这个命令获取当前节点的状态信息,从而判断当前节点的可用性。

INFO replication
INFO cluster
CLUSTER NODES