写点什么

开发一套高容错分布式系统

作者:JAVA活菩萨
  • 2022 年 8 月 04 日
  • 本文字数:3465 字

    阅读完需:约 11 分钟

开发一套高容错分布式系统

一、写在前面


我们先来回看一下当时的那个架构图,然后继续聊聊这套架构在面对高并发、高可用、高性能等各种技术挑战下,应该如何继续演进。



二、active-standby 高可用架构

大家看看上面的那个架构图,有没有发现里面有一个比较致命的问题?就是如何避免系统单点故障!

在最初的部署架构下,因为数据平台系统对 CPU、内存、磁盘的要求很高,所以我们是单机部署在一台较高配置的虚拟机上的,16 核 CPU、64G 内存、SSD 固态硬盘。这个机器的配置是可以保证数据平台系统在高负载之下正常运行的。

但是如果仅仅是单机部署数据平台系统的话,会导致致命的单点故障问题,也就是如果单台机器上部署的数据平台系统宕机的话,就会立马导致整套系统崩溃。

因此在初期的阶段,我们对数据平台实现了 active-standby 的高可用架构,也就是一共部署在两台机器上,但是同一时间只有一台机器是会运行的,但是另外一台机器是备用的。处于 active 状态的系统会将滑动窗口计算引擎的计算状态和结果写入 zookeeper 中,作为元数据存储起来。

关于元数据基于 zookeeper 来存储,我们是充分参考了开源的 Storm 流式计算引擎的架构实现,因为 Storm 作为一个非常优秀的分布式流式计算系统,同样需要高并发的读写大量的计算中间状态和数据,他就是基于 zookeeper 来进行存储的。

本身 zookeeper 的读写性能非常的高,而且 zookeeper 集群自身就可以做到非常高的可用性,同时还提供了大量的分布式系统需要的功能支持,包括分布式锁、分布式协调、master 选举、主备切换等等。

因此基于 zookeeper 我们实现了 active-standby 的主备自动切换,如果 active 节点宕机,那么 standby 节点感知到,会自动切花为 active,同时自动读取他们共享的一个计算引擎的中间状态,然后继续恢复之前的计算。

大家看下面的图,一起感受一下。



在完成上述的 active-standby 架构之后,肯定是消除掉了系统的单点故障了,保证了基本的可用性。而且在实际的线上生产环境中表现还不错,一年系统总有个几次会出现故障,但是每次都能自动切换 standby 机器稳定运行。

这里随便给大家举几个生产环境机器故障的例子,因为部署在公司的云环境中,用的都是虚拟机,可能遇到的坑爹故障包括但不限于下面几种情况:

  • 虚拟机所在的宿主机挂了

  • 虚拟机的网络出现故障

  • 负载过高导致磁盘坏了

所以在线上高负载环境中,永远别寄希望于机器永远不宕机,你要随时做好准备,机器会挂!系统必须做好充分的故障预测、高可用架构以及故障演练,保证各种场景下都可以继续运行。

三、Master-Slave 架构的分布式计算系统

但是此时另外一个问题又来了,大家考虑一个问题,数据平台系统其实最核心的任务就是对一个一个的时间窗口中的数据进行计算,但是随着每天的日增数据量越来越多,每个时间窗口内的数据量也会越来越大,同时会导致数据平台系统的计算负载越来越高。

在线上生产环境表现出来的情况就是,数据平台系统部署机器的 CPU 负载越来越高,高峰期很容易会 100%,机器压力较大。新一轮的系统重构,势在必行。

首先我们将数据平台系统彻底重构和设计为一套分布式的计算系统,将任务调度与任务计算两个职责进行分离,有一个专门的 Master 节点负责读取切分好的数据分片(也就是所谓的时间窗口,一个窗口就是一个数据分片),然后将各个数据分片的计算任务分发给多个 Slave 节点。

Slave 节点的任务就是专门接收一个一个的计算任务,每个计算任务就是对一个数据分片执行一个几百行到上千行的复杂 SQL 语句来产出对应的数据分析结果。

同时对 Master 节点,我们为了避免其出现单点故障,所以还是沿用了之前的 Active-Standby 架构,Master 节点是在线上部署一主一备的,平时都是 active 节点运作,一旦宕机,standby 节点会切换为 active 节点,然后自动调度运行各个计算任务。



这套架构部署上线之后,效果还是很不错的,因为 Master 节点其实就是读取数据分片,然后为每个数据分片构造计算任务,接着就是将计算任务分发给各个 Slave 节点进行计算。

Master 节点几乎没有太多复杂的任务,部署一台高配置的机器就绝对没问题。

负载主要在 Slave 节点,而 Slave 节点因为部署了多台机器,每台机器就是执行部分计算任务,所以很大程度上降低了单台 Slave 节点的负载,而且只要有需要,随时可以对 Slave 集群进行扩容部署更多的机器,这样无论计算任务有多繁忙,都可以不断的扩容,保证单台 Slave 机器的负载不会过高。

四、弹性计算资源调度机制

在解决了单台机器计算负载压力过高的问题之后,我们又遇到了下一个问题,就是在线上生产环境中偶尔会发现某个计算任务耗时过长,导致某台 Slave 机器积压了大量的计算任务一直迟迟得不到处理。

这个问题的产生,其实主要是由于系统的高峰和低谷的数据差异导致的。

大家可以想想,在高峰期,瞬时涌入的数据量很大,很可能某个数据分片包含的数据量过大,达到普通数据分片的几倍甚至几十倍,这是原因之一。

还有一个原因,因为截止到目前为止的计算操作,其实还是基于几百行到上千行的复杂 SQL 落地到 MySQL 从库中去执行计算的。

因此,在高峰期可能 MySQL 从库所在数据库服务器的 CPU 负载、IO 负载都会非常的高,导致 SQL 执行性能下降数倍,这个时候数据分片里的数据量又大,执行的又慢,很容易就会导致某个计算任务执行时间过长。

最后一个造成负载不均衡的原因,就是每个计算任务对应一个数据分片和一个 SQL,但是不同的 SQL 执行效率不同,有的 SQL 可能只要 200 毫秒就可以结束,有的 SQL 要 1 秒,所以不同的 SQL 执行效率不同,造成了不同的计算任务的执行时间的不同。

因此,我们又专门在 Master 节点中加入了计算任务 metrics 上报、计算任务耗时预估、任务执行状态监控、机器资源管理、弹性资源调度等机制。

实现的一个效果大致就是:

  • Master 节点会实时感知到各个机器的计算任务执行情况、排队负载压力、资源使用等情况。

  • 同时还会收集各个机器的计算任务的历史 metrics

  • 接着会根据计算任务的历史 metrics、预估当前计算任务的耗时、综合考虑当前各 Slave 机器的负载,来将任务分发给负载较低的 Slave 机器。

通过这套机制,我们充分保证了线上 Slave 集群资源的均衡利用,不会出现单台机器负载过高,计算任务排队时间过长的情况,经过生产环境的落地实践以及一些优化之后,该机制运行良好。



五、分布式系统高容错机制

其实一旦将系统重构为分布式系统架构之后,就可能会出现各种各样的问题,此时就需要开发一整套的容错机制。

大体说起来的话,这套系统目前在线上生产环境可能产生的问题包括但不限于:

  • 某个 Slave 节点在执行过程中突然宕机

  • 某个计算任务执行时间过长

  • 某个计算任务执行失败

因此,Master 节点内需要实现一套针对 Slave 节点计算任务调度的容错机制,大体思路如下:

1.Master 节点会监控各个计算任务的执行状态,同时也会监控各个 Slave 节点的运行状态

2.如果说某个 Slave 宕机了,那么此时 Master 就会将那个 Slave 没执行完的计算任务重新分配给其他的 Slave 节点

3.如果说某个 Slave 的计算任务执行失败了,同时重试几次之后还是失败,那么 Master 会将这个计算任务重新分配给其他的 Slave 节点来执行

4.如果说某个计算任务在多个 Slave 中无法成功计算的话,此时会将这个计算任务储存在一个延时内存队列中,间隔一段时间过后,比如说等待高峰期故去,然后再重新尝试执行这个计算任务

5.如果某个计算任务等待很长时间都没成功执行,可能是 hang 死了,那么 Master 节点会更新这个计算任务的版本号,然后分配计算任务给其他的 Slave 节点来执行。

6.之所以要更新版本号,是为了避免说,新分配的 Slave 执行完毕写入结果之后,之前的那个 Slave hang 死了一段时间恢复了,接着将计算结果写入存储覆盖正确的结果。用版本号机制可以避免这种情况的发生。



六、阶段性总结

系统架构到这个程度为止,其实在当时而言是运行的相当不错的,每日亿级的请求以及数据场景下,这套系统架构都能承载的很好,如果写数据库并发更高可以随时加更多的主库,如果读并发过高可以随时加更多的从库,同时单表数据量过大了就分更多的表,Slave 计算节点也可以随时按需扩容。

计算性能也是可以在这个请求量级和数据量级下保持很高的水准,因为数据分片计算引擎(滑动窗口)可以保证计算性能在秒级完成。同时各个 Slave 计算节点的负载都可以通过弹性资源调度机制保持的非常的均衡。

另外整套分布式系统还实现了高可用以及高容错的机制,Master 节点是 Active-Standby 架构可以自动故障转移,Slave 节点任何故障都会被 Master 节点感知到同时自动重试计算任务。

七、下一个阶段的展望

其实如果仅仅只是每天亿级的流量请求过来,这套架构是可以撑住了,但是问题是,随之接踵而来的,就是每天请求流量开始达到数十亿次甚至百亿级的请求量,此时上面那套架构又开始支撑不住了,需要继续重构和演进系统架构。​

用户头像

JAVA活菩萨

关注

还未添加个人签名 2022.07.25 加入

还未添加个人简介

评论

发布
暂无评论
开发一套高容错分布式系统_Java_JAVA活菩萨_InfoQ写作社区