Redis 集群

本篇文章学习下 Redis 搭建集群的三种方式。

三种集群方式

三种集群方式分别是 主从复制方式,哨兵模式,Redis-Cluster 集群

主从复制

一个主数据库实例 master,一个或多个从数据库实例 slave。

客户端可对 master 读写操作,对 slave 只有读的操作,对 master 的操作会自动同步给 slave。

工作流程、原理

  1. slave 启动后,发送 SYNC 指令到 master,master 收到指令后执行 bgsave 保存快照,即 RDB 文件
  2. master 将生成的快照发送给 slave,生成快照期间及发送给 slave 收到的操作会记录到缓冲区
  3. slave 收到快照后,加载快照数据
  4. master 将缓冲区的数据也发给 slave,slave 收到后执行
  5. 此后,master 的每一次操作都会同步给 slave,保持 master 与 slave 之间的数据一致性。

优点:

  1. 自动同步,可进行读写分离,
  2. 非阻塞方式进行

缺点:

  1. 不具备自动容错与恢复能力,master 或者 slave 宕机后可能导致客户端请求失败
  2. master 宕机后,如果缓冲区的数据没同步完,恢复后可能会存在数据不一致
  3. 难以扩容

哨兵模式

哨兵模式基于主从复制,多加了哨兵来监控、处理故障

  1. 监控 master、slave 是否正常运行
  2. 当 master 出现故障时,能自动将一个 slave 转换为 master,
  3. 多个哨兵可以监控同一个 redis,哨兵之间也会自动监控

通过 sentinel monitor <master-name> <ip> <redis-port> <quorum> 来定位master的IP、端口,一个哨兵可以监控多个master数据库,只需要提供多个该配置项即可。哨兵启动后,会与要监控的master建立两条连接:

  1. 一条连接用来订阅master的_sentinel_:hello频道与获取其他监控该master的哨兵节点信息
  2. 另一条连接定期向master发送INFO等命令获取master本身的信息

与 master 建立连接后,哨兵会执行三个动作

  1. 定期(一般10s一次,当master被标记为主观下线时,改为1s一次)向 master 和 slave 发送 INFO 命令
  2. 定期向 master 和 slave 的_sentinel_:hello频道发送自己的信息
  3. 定期(1s一次)向 master、slave 和其他哨兵发送 PING 命令

INFO 信息可以获取当前数据库的相关信息从而实现新节点的自动发现。所以说 哨兵只需要配置 master 数据库信息就可以自动发现其 slave 信息,获取到 slave 后,哨兵也会向 slave 建立两条连接执行监控。通过 INFO 命令,哨兵可以获取主从数据库的信息,并进行相应的操作,如 角色变更 等。

接下来哨兵向主从数据库的_sentinel_:hello频道发送信息与同样监控这些数据库的哨兵共享自己的信息,发送内容为哨兵的ip端口、运行id、配置版本、master名字、master的ip端口还有master的配置版本。这些信息有以下用处:

  1. 其他哨兵可以通过该信息判断发送者是否是新发现的哨兵,如果是的话会创建一个到该哨兵的连接用于发送PING命令。
  2. 其他哨兵通过该信息可以判断master的版本,如果该版本高于直接记录的版本,将会更新
  3. 当实现了自动发现slave和其他哨兵节点后,哨兵就可以通过定期发送PING命令定时监控这些数据库和节点有没有停止服务。

如果被 PING 的数据库或者节点超时(通过 sentinel down-after-milliseconds master-name milliseconds 配置)未回复,哨兵认为其主观下线(sdown,s就是 Subjectively —— 主观地)。如果下线的是 master,哨兵会向其它哨兵发送命令询问它们是否也认为该 master 主观下线,如果达到一定数目(即配置文件中的 quorum )投票,哨兵会认为该 master 已经客观下线(odown,o就是 Objectively —— 客观地),并选举领头的哨兵节点对主从系统发起故障恢复。若没有足够的 sentinel 进程同意 master 下线,master 的客观下线状态会被移除,若 master 重新向 sentinel 进程发送的 PING 命令返回有效回复,master 的主观下线状态就会被移除

哨兵认为 master 客观下线后,故障恢复的操作需要由选举的领头哨兵来执行,选举采用 Raft 算法:

  • 发现 master 下线的哨兵节点(我们称他为 A )向每个哨兵发送命令,要求对方选自己为领头哨兵
  • 如果目标哨兵节点没有选过其他人,则会同意选举 A 为领头哨兵
  • 如果有超过一半的哨兵同意选举 A 为领头,则 A 当选
  • 如果有多个哨兵节点同时参选领头,此时有可能存在一轮投票无竞选者胜出,此时每个参选的节点等待一个随机时间后再次发起参选请求,进行下一轮投票竞选,直至选举出领头哨兵

选出领头哨兵后,领头者开始对系统进行故障恢复,从出现故障的 master 的从数据库中挑选一个来当选新的 master,选择规则如下:

  • 所有在线的 slave 中选择优先级最高的,优先级可以通过 slave-priority 配置
  • 如果有多个最高优先级的 slave,则选取复制偏移量最大(即复制越完整)的当选
  • 如果以上条件都一样,选取 id 最小的 slave

挑选出需要继任的 slave 后,领头哨兵向该数据库发送命令使其升格为 master,然后再向其他 slave 发送命令接受新的 master,最后更新数据。将已经停止的旧的 master 更新为新的 master 的从数据库,使其恢复服务后以 slave 的身份继续运行。

优缺点:
优点:

  1. 哨兵模式基于主从复制模式,所以主从复制模式的优点哨兵模式也有
  2. 哨兵模式下,master 挂掉后可以自行切换,系统可用性更高

缺点:

  1. 难以在线扩容,Redis 容量受制于单机节点,只能对 master 写。
  2. 需要额外的资源来启动 sentinel 进程,实现相对复杂,同时 slave 节点只作为备份,不提供服务
  3. 切换主从节点的时候时间花费较长。

Redis-Cluster集群

Cluster 模式实现了 Redis 的分布式存储,即每台节点存储不同的内容,来解决在线扩容的问题。

Cluster 采用无中心结构,它的特点如下:

  1. 所有的redis节点彼此互联(PING-PONG机制),内部使用二进制协议优化传输速度和带宽
  2. 节点的fail是通过集群中超过半数的节点检测失效时才生效
  3. 客户端与redis节点直连,不需要中间代理层.客户端不需要连接集群所有节点,连接集群中任何一个可用节点即可

Cluster 模式的具体工作机制:

  1. 在 Redis 的每个节点上,都有一个插槽(slot),取值范围为 0-16383
  2. 当我们存取 key 的时候,Redis 会根据 CRC16 的算法得出一个结果,然后把结果对 16384 求余数,这样每个 key 都会对应一个编号在 0-16383 之间的哈希槽,通过这个值,去找到对应的插槽所对应的节点,然后直接自动跳转到这个对应的节点上进行存取操作
  3. 为了保证高可用,Cluster 模式也引入主从复制模式,一个主节点对应一个或者多个从节点,当主节点宕机的时候,就会启用从节点
  4. 当其它主节点 ping 一个主节点 A 时,如果半数以上的主节点与 A 通信超时,那么认为主节点 A 宕机了。如果主节点 A 和它的从节点都宕机了,那么该集群就无法再提供服务了

Cluster 模式集群节点最小配置6个节点(3主3从,因为需要半数以上),其中主节点提供读写操作,从节点作为备用节点,不提供请求,只作为故障转移使用。

优缺点:
优点:

  1. 无中心架构,数据按照 slot 分布在多个节点。
  2. 集群中的每个节点都是平等的关系,每个节点都保存各自的数据和整个集群的状态。每个节点都和其他所有节点连接,而且这些连接保持活跃,这样就保证了我们只需要连接集群中的任意一个节点,就可以获取到其他节点的数据。
  3. 可线性扩展到 1000 多个节点,节点可动态添加或删除
  4. 能够实现自动故障转移,节点之间通过 gossip 协议交换状态信息,用投票机制完成 slave 到 master 的角色转换

缺点:

  1. 客户端实现复杂,驱动要求实现 Smart Client,缓存 slots mapping 信息并及时更新,提高了开发难度。目前仅 JedisCluster 相对成熟,异常处理还不完善,比如常见的 “max redirect exception”
  2. 节点会因为某些原因发生阻塞(阻塞时间大于 cluster-node-timeout)被判断下线,这种 failover 是没有必要的
  3. 数据通过异步复制,不保证数据的强一致性
  4. slave 充当“冷备”,不能缓解读压力
  5. 批量操作限制,目前只支持具有相同 slot 值的 key 执行批量操作,对 mset、mget、sunion 等操作支持不友好
  6. key 事务操作支持有线,只支持多 key 在同一节点的事务操作,多 key 分布不同节点时无法使用事务功能
  7. 不支持多数据库空间,单机 redis 可以支持16个 db,集群模式下只能使用一个,即 db 0

https://segmentfault.com/a/1190000022028642

2021/3/29 posted in  redis