java后端领域

V1

2023/03/03阅读:25主题:默认主题

redis 各种集群架构核心原理

主从架构

如下图,一个主节点,可以搭建多个从节点,在主节点挂掉之后,可以人工让某个从节点变成主,其他从节点 slave of new master。

优缺点

  • 优点:对比只有一个主节点,可以实现读写分离,主节点故障时可以通过工人将从节点切换主节点来恢复
  • 缺点:
    • 需要人工介入来实现切换,同时使用服务需要重启才能确保生效(针对每个ip使用域名替代,在切换主从节点时,运维负责更新域名对应新的ip,但是业务侧可能有域名解析缓存,比如jvm等,需要重启服务才能马上生效)
    • 不能水平扩展。只有一个主节点能支撑写入,不能通过扩节点来实现水平扩展,只能通过增加内存来实现垂直扩展,所以存储的数据量以及处理能力只能单机水平

主从 + sentinel 架构

由于单纯的主从架构存在故障时需要人工切换的缺点,因此引入了第三方 sentinel 来解决这个问题,如下图:

通过搭建大于等于3个节点的 sentinel 奇数节点,组建一个监控redis节点的监控集群来实现故障自动切换。

故障自动切换核心步骤

主要分为3个大步骤:确定主节点不可用;负责故障转移的sentinel节点选举;故障转移。

确定主节点不可用

  1. 每个 sentinel 节点启动时会启动3个定时任务,其中一个是每隔1秒就向主从节点发送ping消息,如果主节点超时没有回复,该 sentinel 节点会主观任务主节点不可用,这是主观下线,可能因为网络原因导致误判,因此需要询问其他 sentinel 节点。
  2. 进行主观下线的 sentinel 节点会发送相关命令给其他 sentinel 节点该 master 是否可用,在收到其他 sentinel 节点回复时,判断是否有过半(sentinel数量/2+1)的 sentinel 节点认为不可用,如果是,则认为 master 真的不可用,这算是客观下线,该 sentinel 节点会优先发起负责故障转移的节点选举。

负责故障转移的sentinel节点选举

  1. 进行客观下线的 sentinel 节点会向其他 sentinel 节点发送 sentinel is-master-down-by-addr 命令,如果该节点没有给其他 sentinel 节点投票过,那么就直接投票给先来的节点,而且有且只有一票。
  2. 当 sentinel 收到的投票数过半(sentinel数量/2+1)时,就成为leader,有该 sentinel 节点负载故障转移

故障转移

  1. 在从节点列表中选出一个节点作为新的主节点,选择步骤:
  • 过滤不健康的节点,比如:主观下线,5秒没有回复过 sentinel 节点等等
  • 优先选择优先级最高的从节点列表,如果存在最大一个则返回,否则按照下面步骤继续挑选
  • 选择复制偏移量最大的从节点,如果存在最大一个则返回,否则按照下面步骤继续挑选
  • 选择 runid 最小的从节点
  1. sentinel leader 向上面选出的一个从节点发送 slaveof no one 命令让其成为主节点
  2. sentinel leader 向其他从节点发送 slave of new master 让其成为新master的从节点
  3. sentinel 节点集合将原来的 master 更新为salve,监控是否恢复,如果恢复,则让其 slave of new master 成为从节点

客户端如何自动感知和切换

以 jedis 客户端为例,在初始化完成时,客户端会针对每个sentinel起一个监听线程,监听 sentinel 的切换master频道:+switch-master。当发送故障转移时,sentinel会向该频道发送通知,并且向订阅的那个client推送,client收到通知后,判断如果是当前的master发送转移,对通知里面的新master进行重新初始化连接池。这个过程全自动,无需人工重启即可秒级生效。

优缺点

  • 优点:可以实现故障自动转移,无需人工接入
  • 缺点:不能支持水平扩展。

redis cluster 架构

redis cluster 是一种分布式集群架构,所有数据不再存在一个主节点上,而是通过分配规则,分配到多个主节点上,每个节点负责其中一部分,如下图:

如何将数据平均分配给每个主节点

redis cluster 采用虚拟槽的方案,将集群设置 0~16383 一共 16384个槽,在集群初始化时可以给每个主节点平均分配对应的槽,如果扩容时,redis cluster 通过将现有的每个主节点迁移一部分槽的数据到新的主节点,以使每个主节点负责的槽个数尽量平均,同时保证迁移期间,客户端能通过重定向方式来正确获取相关数据,保证不影响业务,缩容类似不再阐述。扩容时槽迁移的核心流程如下图:

集群中每个节点如何实现数据同步

redis cluster 并没有引起类似 zookeeper 等第三方组件来实现各个节点数据同步,而且通过 gossip 协议来实现。gossip(流言)协议核心思想是:每个节点定期将本节点得到的信息发送给集群的其他部分节点,收到其他节点的信息时,回复时也带上自身相关信息,通过这样相互传播,跟流言一样,最终大家得到的信息到达一致。

redis cluster 关于gossip的核心实现:每个节点定时(每秒10次)地从本节点知道的集群节点中根据一定规则选择一部分节点,然后给这些节点发送 ping 消息,消息中带自身信息+ 1/10 其他节点信息,接收节点收到时会解析并且更新本地节点列表信息(如槽映射关系、主从角色等),根据接收的信息判断是否进行故障转移,并且给发送节点回复 pong 消息,内部封装自身状态数据。

故障转移如何实现的

故障转移跟sentinel的类似,分别有主观下线、客观下线、故障恢复步骤。

  • 主观下线: 定时任务定时检查本地节点列表的最后更新时间,如果超过固定的时间(cluster-note-timeout),则将其标记为主观下线(pfail)状态。
  • 客观下线:被主观下线的节点随着gossip会同步给其他节点,节点收到含有主观下线的节点状态时,更新本地的下线报告链表,当超过半数以上持有槽的主节点的有效报告(没过期)都标记某个节点为主观下线时,会认为最终不可用,将其标记为客观下线,然后向集群广播1条fail消息,通知所有节点将故障节点标记为客户下线。
  • 故障恢复:从节点通过定时任务发现复制的主节点进入客观下线后触发
    • 从节点资格检查:故障的主节点所有从节点检查自己与主节点最后的断线时间,如果超过一定时间就不具备
    • 准备选举时间:每个符合资格检查的从节点,采用每个节点不同的时间触发的机制来保证前面触发的选举优先得胜,复制偏移量越大(同步延迟低)的优先触发。
    • 发起选举:选举时更新配置纪元,广播选举消息,获得超过一半以上的主节点(只要活着的主节点>=1即可)投票的从节点将会成为新的主节点
    • 替换主节点:选举获胜的从节点取消复制之前的主节点,然后撤销之前主节点复制的槽并且将槽委派给自己,最后向集群广播自己的pong消息,通知所以节点当前从节点变成主节点并且接管了故障主节点的槽信息

客户端访问 redis cluster 的核心流程是怎么样的

以jedis客户端为例,客户端发起一个命令的核心流程如下图:

优缺点

  • 优点:高可用、支持水平扩展、扩缩容时对业务测无需改动和操作
  • 缺点:
    • 多key操作如 MGET MSET pipeline 等命令有限制,这些key必须对应的槽必须是同个主节点负责,否则会报错。不过客户端可以将key属于哪个server进行分组,然后将对应同个主节点的key分成一批然后发送相关命令,并行给相关主节点发现命令,然后再汇总,需要客户端进行封装。
    • gossip 协议对集群的网络带宽要求高,太多节点时会加大网络带宽的压力

codis 集群架构

codis 是 redis 集群一种解决方案,那时候 redis cluster 还没出来,是豌豆荚将这个开源了,成为当时非常流行的集群解决方案,不过现在也有不少公司在使用,其架构图如下:

codis 主要有下面几个组件:

  • codis server:这是进行了二次开发的 Redis 实例,其中增加了额外的数据结构,支持数据迁移操作,主要负责处理具体的数据读写请求。
  • codis proxy:接收客户端请求,并把请求转发给 codis server。多KEY操作的支持主要是在这层来实现的。该服务是无状态的,可以通过增加实例来进行扩容。
  • Zookeeper 集群:保存集群元数据,例如数据位置信息和 codis proxy 信息。
  • codis dashboard 和 codis fe:共同组成了集群管理工具。其中,codis dashboard 负责执行集群管理工作,包括增删 codis server、codis proxy 和进行数据迁移。而 codis fe 负责提供 dashboard 的 Web 操作界面,便于我们直接在 Web 界面上进行集群管理。

codis 的核心原理

codis 如何保证高可用

  • codis proxy 是无状态的,可以通过部署多个,就算挂掉其中一部分,剩余的也能正常提供服务
  • codis-group 部署1主多从,当有故障时,通过 sentinel 来自动故障转移
  • zoopeeper/etcd 本身就是高可用设计
  • codis dashboard 和 codis fe:主要提供配置管理的操作,是弱依赖,无需额外保证。

数据如何分片存储到不同的 codis server

codis 将集群数据分位 0~1023 一共1024个slot,每个 codis server 负责维护部分的slot,跟 redis cluster 类似,其分配是通过 dashboard 来分配的,dashboard 将其中 slot 和 codis 的映射关系会存储到 zookeeper/etcd 等第三方存储中,同时发给 codis proxy,codis proxy 缓存到本地,在接受客户端请求时进行路由使用。

一次请求的执行流程

  • 客户端请求到达 proxy 时,proxy 使用 CRC32(key) % 1024 计算对应的 slot,然后根据之前每个 codis server 负责的slot查找该 slot 属于哪个 codis-group 负责,然后将请求发到对应的 codis-group(写请求或者没开启读写分离就打到master,如果开启读写分离,读请求转发到从库)。如果是多KEY操作或者 pipeline 时,codis proxy 负责将key 属于哪个codis-grup负责的进行分组,然后并行请求多个 codis-group ,然后汇总结果返回给客户端。

优缺点

  • 优点:
    • 对比 redis cluster,支持多key操作、支持 pipeline,完全兼容单实例的redis实例协议,具体对比如下图:
    • 通过proxy层承担增多客户端的连接数,减少对 redis 建立的连接数
  • 缺点:
    • 现在codis 社区在2018年就不更新了,最新只支持 redis-3.2.8 版本,所以后续版本的性能以及新特性,codis 无法使用。
    • 多了1层proxy,性能对应 redis cluster 有所降低

Twemproxy 架构

Twemproxy 是 Twitter 开源的集群方案,可以作为 redis 和 memcached 的proxy,推出的时间比 codis 和 redis cluster 要早,主要负责分批机制、请求转发的功能,下面可以挂多个 redis 或memcached 来扩展处理能力。Twemproxy 本身是单点,需要用Keepalived做高可用方案(或者LVS)。其最主要不太友好的是不支持在线扩缩容,维护成本 Twemproxy 也相对较高,有了 codis 和 redis cluster 的替代方案,一般很少见到有使用该方案,这里不再深入展开。下面是 Twemproxy 的架构图:

redis 不同架构的选型

主从架构适用的场景

适用存储数据小+请求量小+服务不重要+能容忍长时间服务不可用,比如内部使用的后台管理系统,选择这个架构主要是为了节约机器成本和运维成本

主从 + sentinel 架构适用的场景

因为该架构最大的存储容量和处理写能力都是单机的,所以使用存储量相关固定,请求量不太高并且不会持续增大的场景,工作中用到这种比较少,一般都是直接上 redis cluster 或者 codis。

codis & redis cluster 如何选择

  • 成熟度和稳定性:由于 codis 出生比较早,在业界应用广泛,相对于后期的 redis cluster 更加的成熟
  • 是否需要用到新特性:codis 最新只支持 redis-3.2.8 分支,如果想用到redis 3.2.8之后的新版本,只能选择 redis cluster
  • 是否频繁扩缩容:扩缩容时涉及数据的迁移,codis 支持异步迁移,对业务请求影响小,对比 redis cluster 更加合适
  • 团队的技术积累:运维团队和开发团队对 redis cluster 和 codis 的经验积累也是考虑的一方面

分类:

后端

标签:

后端

作者介绍

java后端领域
V1

研发过亿日活的app,java 8年+