1.在之前的文章《??亿流量大考(1):日增上亿数据,把MySQL直接搞宕机了...??》中,讲到了业务数据平台第一阶段的架构演进。通过离线和实时计算链路的拆分、离线计算的增量计算优化、实时计算的滑动时间窗口计算引擎、分库分表+读写分离等技术手段,支持百亿订单数据存储和计算。我们先来回回顾一下当时的架构图,然后继续说说面对高并发、高可用、高性能等各种技术挑战,这个架构应该如何继续演进。2.主备高可用架构看上面的架构图。你有没有发现其中的致命问题?就是如何避免系统出现单点故障!在初始部署架构下,由于数据平台系统对CPU、内存、磁盘的要求较高,我们在单机上部署在更高配置的虚拟机上,16核CPU、64G内存、SSD固态驾驶。本机的配置可以保证数据平台系统在高负载下的正常运行。但是,如果数据平台系统只部署在单机上,则会导致致命的单点故障问题,即部署在单机上的数据平台系统宕机,会立即导致整个系统崩溃。坠毁。所以在初期,我们对数据平台实现了主备高可用架构,即部署在两台机器上,但同时只会有一台机器运行,而另一台机器是一台备份。处于活跃状态的系统会将滑动窗口计算引擎的计算状态和结果写入zookeeper,并作为元数据存储。关于基于zookeeper的元数据存储,我们完全参考了开源Storm流式计算引擎的架构实现,因为Storm作为一个非常优秀的分布式流式计算系统,同样需要大量的高并发读写计算中间状态和数据,他是基于zookeeper进行存储的。zookeeper本身的读写性能是非常高的,zookeeper集群本身可以达到非常高的可用性。同时,它还提供了大量分布式系统所需的功能支持,包括分布式锁、分布式协调、主选举、主备切换等。因此,基于zookeeper,我们实现了主备自动切换。如果主节点宕机,备节点会感知到,自动剪花变为主节点。同时,它会自动读取他们共享的一个计算引擎的中间状态,然后继续恢复之前的计算。看看下图,一起来体验吧。完成上述主备架构后,必须消除系统的单点故障,保证基本的可用性。而且在实际线上生产环境中的表现还不错。系统一年总会出现几次故障,但每次都能自动切换到备用机稳定运行。这里举几个生产环境机器故障的例子,因为部署在公司云环境,使用虚拟机。可能遇到的潜在故障包括但不限于以下几种情况:虚拟机所连接的主机网络故障过高,磁盘坏了。所以在线上高负载环境下,永远不要希望机器永远宕机。必须随时做好准备,机器会挂掉!系统必须有足够的故障预测、高可用架构和故障演练,以保证在各种场景下都能持续运行。3.Master-Slave架构的分布式计算系统但是这个时候另一个问题又出现了。让我们考虑一个问题。事实上,数据平台系统的核心任务就是计算每个时间窗口内的数据,但是随着每天数据量的增长越来越大,每个时间窗口内的数据量也会越来越大。同时,数据平台系统的计算负荷也会越来越高。线上生产环境呈现的情况是数据平台系统部署机器的CPU负载越来越高,高峰期容易100%,机器压力大。新一轮制度重构势在必行。首先,我们将数据平台系统完全重构设计成一个分布式计算系统,将任务调度和任务计算两个职责分离,并有一个专门的Master节点负责读取分片的数据(也就是所谓的-称为时间窗口,一个窗口就是一个数据分片),然后将每个数据分片的计算任务分发给多个Slave节点。Slave节点的任务就是一个接一个的接收计算任务。每个计算任务都是在一个数据分片上执行一条几百到几千行的复杂SQL语句,生成相应的数据分析结果。同时,对于Master节点,为了避免单点故障,我们还是沿用了之前的Active-Standby架构。Master节点在线部署,一主一备。通常,活动节点运行。一旦宕机,备节点就会切换到主节点,然后自动调度运行各种计算任务。这个架构部署上线后,效果还是很好的,因为Master节点其实是读取数据分片,然后为每个数据分片构造计算任务,然后将计算任务分发给各个Slave节点进行计算。Master节点没有太多复杂的任务,部署一台高配置的机器绝对没问题。负载主要在Slave节点上,而Slave节点部署了多台机器,每台机器执行部分计算任务,因此大大降低了单个Slave节点的负载,只要有需要,Slave集群都可以随时执行。扩容部署更多的机器,这样无论计算任务多忙,都可以不断扩容,保证单台Slave机器的负载不会过高。4、弹性计算资源调度机制在解决了单机计算负载压力大的问题之后,我们又遇到了下一个问题,就是线上生产环境中偶尔会出现某个计算任务耗时过长,导致某个Slave机器积压了大量长时间未处理的计算任务。这个问题其实主要是系统波峰波谷的数据差异造成的。你可以考虑一下。在高峰期,涌入的数据量非常大。极有可能是某个数据分片所包含的数据量过大,达到了普通数据分片的数倍甚至数十倍。这是原因之一。还有一个原因,因为到目前为止的计算操作实际上都是基于几百到几千行的复杂SQL,在MySQL从库中实现来进行计算。因此,在高峰期,MySQL从库所在的数据库服务器的CPU负载和IO负载可能会非常高,导致SQL执行性能下降数倍。这时候数据分片的数据量很大,执行起来很慢。它会导致计算任务执行时间过长。最后一个导致负载不均衡的原因是每个计算任务对应一个数据分片和一条SQL,但是不同的SQL执行效率不同。有些SQL可能会在200毫秒内结束,而其他SQL可能需要1秒。因此不同的SQL有不同的执行效率,导致不同计算任务的执行时间不同。因此,我们专门在Master节点上增加了计算任务指标上报、计算任务耗时预估、任务执行状态监控、机器资源管理、弹性资源调度等机制。实现的一个效果大概是:Master节点会实时感知每台机器的计算任务执行情况、排队负载压力、资源使用情况。同时收集各台机器计算任务的历史指标,然后根据计算任务的历史指标将任务分发到负载较低的从机,估计当前的耗时计算任务,综合考虑当前从机的负载。.通过这种机制,我们充分保证了在线Slave集群资源的均衡利用,不会出现单机负载过高或者计算任务排队时间过长的情况。经过生产环境的实施和一些优化,该机制运行良好。5.分布式系统的高容错机制实际上,一旦将系统重构为分布式系统架构,可能会出现各种各样的问题。这时候就需要制定一套完整的容错机制。总的来说,本系统目前线上生产环境可能出现的问题包括但不限于:Slave节点在执行过程中突然宕机、计算任务执行时间过长、计算任务执行失败等。因此,Master节点需要对Slave节点的计算任务调度实现一套容错机制。总体思路如下:1.Master节点会监控每个计算任务的执行状态,同时也会监控每个Slave节点的运行状态。2、如果出现SlaveDowntime,那么Master此时会将Slave未完成的计算任务重新分配给其他Slave节点。Master会将这个计算任务重新分配给其他Slave节点执行。4、如果某个计算任务不能在多个Slave中计算成功,此时会将该计算任务存入一个延迟内存队列中。过一段时间,比如等高峰期过去了,再尝试执行计算任务。5、如果一个计算任务等待了很久没有成功执行,可能是hang死了,这时Master节点会更新计算任务Versionnumber,然后将计算任务分配给其他Slave节点执行。6.之所以更新版本号,是为了避免说新分配的Slave执行并写入结果后,之前的Slave挂了一会儿死了恢复,然后将计算结果写入存储覆盖正确的结果.使用版本号机制可以避免这种情况。6.系统架构阶段性总结到这里为止,其实当时运行的还是挺好的。在每天上亿级的请求和数据场景下,这个系统架构能够很好的承载。如果写入数据库的并发数更高的话,可以随时添加更多的master数据库。如果读并发过高,可以随时增加更多的从库。同时,如果单个表的数据量太大,可以拆分更多的表。从计算节点也可以根据需要随时扩展。计算性能在这个请求级别和数据级别也能保持较高水平,因为数据分片计算引擎(滑动窗口)可以保证计算性能可以秒级完成。同时,通过弹性资源调度机制,可以使各个Slave计算节点的负载保持非常均衡。此外,整个分布式系统还实现了高可用和高容错机制。Master节点是Active-Standby架构,可以自动故障转移。Slave节点的任何故障都会被Master节点感知到并自动重试计算任务。7、下一阶段的展望其实如果每天只有上亿的流量请求进来,这个架构是可以支撑的,但是问题是随之而来的是每天的请求流量开始达到几十亿甚至上百亿级的请求,上面的架构已经支撑不住了。需要继续重构和演进系统架构。
