当前位置: 首页 > 科技观察

亿流量大考:日增上亿数据,把MySQL直接搞宕机了_0

时间:2023-03-21 22:30:38 科技观察

亿级流量大测试:每天增加1亿条数据,直接关闭MySQL研发团队协同开发,包括各种业务系统,提供众多强大的业务功能。同时,整个平台包含了一个至关重要的核心数据产品。该数据产品的定位是全面支持用户的业务运营和快速决策。本文将聊一聊这个数据产品背后的一套大型商户数据平台,看看这个平台在分布式、高并发、高可用、高性能、海量数据等技术挑战下的架构演进。因为整个系统规模太大,涉及的研发人员多,持续时间长。文章很难表达各种详细的技术细节和解决方案。因此,本文主要从整体架构演进的角度进行阐述。至于选择这个业务数据平台项目来谈架构的演化过程,是因为这个平台基本上和业务的耦合度比较低,不像我们一直负责的C端电商平台等业务平台有如此繁重的业务,文章可以关注技术架构的演进,而不会涉及太多的业务细节。另外,这个平台项目在笔者带领的团队负责过的众多项目中比较简单,但也涉及到各种架构的演进过程,非常适合以文字的形式展示。2.业务数据平台的业务流程以下几点是本数据产品的核心业务流程:各种业务数据从用户每天使用的大量业务系统中实时采集,然后存储在自己的数据中心然后实时计算大量的几百到几千行的SQL,生成各种数据报表,最后将这些数据报表提供给用户进行分析。基本上,在业务系统的使用过程中,只要数据发生变化,就会立即反馈到各种数据报表中。用户可以即时看到数据报表的各种变化,进而快速指导自己的决策和管理。整个过程可以看下图就明白了。3、从0到1的过程中推出的最低版本在上图中看起来是不是很简单?看整个过程,数据平台好像只需要想办法把业务系统的数据收集起来,然后放到MySQL的各种表中,直接点击运行100多条几百行的大SQL,然后将SQL运行结果写入到另外一些MySQL表作为报表数据,然后用户直接点击报表页面,在MySQL中查询报表数据,就可以了!其实任何一个系统从0到1的过程都是比较low的。当初为了快速开发这个数据平台,真的是用这个架构来开发的。请看下图。其实一开始业务量小,请求量小,数据量小的时候,上面的架构是没有问题的,挺简单的。我们直接基于自己开发的数据库binlog采集中间件(这个又是一个复杂的系统,不在本文的讨论范围内,以后再说),感知各个业务系统的数据库中的数据变化,并在毫秒级同步到数据平台自带的MySQL库;然后在数据平台做一些定时的调度任务,每隔几秒钟运行几百条复杂而庞大的SQL,计算各种报表的数据,并将结果存入MySQL库;最后,用户只要刷新报表,就可以立即从MySQL库中找到最新的报表数据。基本上,在没有任何技术挑战的情况下,这个简单的架构会顺利运行并运行良好。然而,事情往往并没有我们想象的那么简单,因为我们都知道,国内互联网巨头最大的优势和资源之一就是丰富和海量的C端用户和B端合作商户。对于C端用户,任何一家互联网巨头推出一款新的C端产品,很可能瞬间拥有数亿用户;对于B端商户来说,如果哪家互联网巨头进入B端市场,凭借其巨大的影响力和合作资源,极有可能迅速聚集数十万,甚至数百万的付费B端用户。因此,不幸的是,在未来一两年内,这套系统将面临巨大的技术挑战和业务快速增长带来的压力。4.海量数据存储和计算的技术挑战其实和很多大型系统遇到的第一个技术挑战是一样的。这个系统遇到的第一个大问题就是海量数据的存储。你的系统上线之初可能会有几十家商户使用,然后随着你的产品销量不断的大力推广,可能在几个月内聚集了10万用户。这些用户每天都会大量使用你提供的产品,每天都会产生大量的数据。你可以想象一下,在几十万业务用户的场景下,你每天新增的数据量很可能是几千万。一条条数据,记住,这每天都是新数据!这会给你上面看到的非常低的架构带来很大的压力。如果你负责上面的系统,原来每天都有数千万的数据涌入MySQL。这种现象很令人沮丧,因为你的MySQL单表的数据量会迅速膨胀,很快就会达到单表几亿条数据,甚至几十亿条数据,然后你在那些怪物表上跑几百甚至几千行SQL?包含N级嵌套查询和N种多表连接?我跟你打赌,如果你愿意尝试,你会发现你的数据平台系统直接卡死了,因为跑一个大的SQL可能要好几个小时。那么MySQL的CPU负载压力直接是100%,如果不这样做,MySQL数据库服务器就会被关闭。所以这是第一个技术挑战。数据量越来越大,SQL运行越来越慢,MySQL服务器的压力越来越大。当时,我们已经看到业务的飞速增长,势必先重构系统架构。不能允许上述情况发生。第一次架构重构势在必行!5.离线计算和实时计算的拆分其实几年前我们做这个项目的时候,大数据技术在国内已经很好的应用了,尤其是在一些大的互联网公司,我们基本上都是用大数据技术支撑了很多生产环境的项目,大数据技术积累的经验也足够了。针对这个数据产品的需求,我们完全可以做到。将昨天和以前的数据放到大数据存储中,进行离线存储和离线计算,然后实时只采集今天的数据。因此,在这种技术挑战下,第一次架构重构的核心本质是将离线计算从实时计算中分离出来。看上面的图片。在新的架构下,有两个计算链路:离线和实时。一是离线计算环节:每天早上我们将业务系统MySQL数据库中昨天的数据导入到HadoopHDFS作为离线数据进行离线存储,然后基于Hive/对离线存储中的数据进行离线计算火花在清晨。离线计算链路得到大数据相关技术的全面支持后,完美解决了海量数据的存储。就算你一天进来上亿条数据也没问题。分布式存储可以随时扩展。同时,基于分布式计算技术,天然适用于海量数据的离线计算。哪怕每天早上花几个小时完成昨天之前的数据计算,这也没关系,因为一般一大早没人看数据,所以主要是在人去之前完成数据计算早上8点上班。另一个是实时计算环节:每天午夜后,当天最新的数据变化依然按照老路,业务数据库中的数据秒级同步到数据平台存储,然后数据平台系统运行大量SQL定时计算。同时,每天午夜时分,昨天的数据将从数据平台的存储中清除,只保留当天的数据。实时计算环节最大的变化是数据平台本地存储只保留当天的数据,大大减少了MySQL存储的数据量。举个例子:比如MySQL每天存储数千万条数据,单表数据量维持在千万级别。十秒内完成所有报表的计算。6.不断增加的数据量和计算压力但是,如果仅实现上述架构,只能暂时缓解系统架构的压力,因为业务仍在加速和增长。你总期望一天的数据量在千万级别,怎么可能?企业不会给你这个机会。很快可以预见,一天的数据量将达到数亿,甚至数十亿。一旦单日数据量达到亿级,单表数据量达到亿级,无论你如何优化SQL性能,都无法保证100多条复杂的SQL,几百条线路可以快速运行。到时候又会回到原来的问题。如果SQL计算太慢,数据平台核心系统会卡顿,甚至给MySQL服务器造成太大压力,100%负载后CPU会崩溃。除此之外,还有一个问题,就是单个MySQL数据库服务器的存储容量是有限的。如果单天的数据量达到甚至超过单个MySQL数据库服务器的存储限制,那么此时也会导致单个MySQL数据库。无法容纳所有的数据,这也是一个大问题!二次建筑改造势在必行!7、大数据领域实时计算技术的缺陷在几年前的这个项目背景下,当时可以选择的大数据领域实时计算技术主要是Storm,算是比较成熟的技术了,另外一个就是Spark生态中的SparkStreaming。当时还没有现在流行的Flink、Druid等技术。仔细排查后发现,目前大数据领域还没有实时计算技术可以支撑这种需求。因为Storm是不支持SQL的,即使你强行让他支持,它对SQL的支持也会很弱,完全不可能在这个流式计算引擎上执行成百上千行的复杂SQL。SparkStreaming也是如此。当时功能比较弱。虽然它可以支持简单SQL的执行,但是无法支持这种复杂SQL的精确运算。所以很遗憾,在当时的技术背景下,没有开源技术能够解决实时数据计算的痛点。你要根据具体的业务场景,从0开始定制开发自己的一套数据平台系统架构。8、分库分表解决数据扩容问题首先我们要先解决第一个痛点,即一旦单个数据库服务器无法存储当天的数据,怎么办?第一个首选方案当然是分库分表。我们需要将一个库拆分成多个库,将不用的库放在不同的数据库服务器上,每个库中放多张表。采用这种分库分表架构后,每个数据库服务器可以存储一部分数据,随着数据量的增长,可以不断增加更多的数据库服务器来容纳更多的数据,实现按需扩展。同时,将每个库中的单表拆分为多张表,可以保证单表的数据量不会太大,单表的数据量控制在几百万量级。基本上可以运行性能优化到极致的SQL语句。效率还是不错的,秒出结果是可以的。同样,这里给大家放一张图,大家可以直观感受一下:9、读写分离,减少了数据库服务器的负载。如果再次读取输入,数据库服务器的CPU负载和IO负载会非常高!你为什么这么说?因为此时写入数据库的并发已经达到几千每秒,同时频繁运行超大型SQL查询数据,数据库服务器的CPU运行会异常繁忙。因此,我们部署了读写分离的MySQL。每个主数据库服务器连接到多个从数据库服务器。写只能写到主库,查询可以从从库进行。我们看下图:10.自主研发的滑动窗口动态计算引擎但这还不够,因为在生产环境中,即使单表的数据量限制在几百万级别,也需要几十个几秒甚至几分钟让你运行数百行复杂的SQL。这种时效性对于付费级别的产品来说已经有点难以接受了。产品提出的极致性能要求在秒级!因此,针对上述系统架构,我们再次优化了架构,在数据平台中嵌入了我们纯自研的滑动窗口计算引擎。核心思想如下:数据库binlog采集中间件在采集过程中,将一个个的滑动时间窗口切入,每个滑动时间窗口为几秒,标记每个窗口中的数据,需要维护一个滑动时间窗口索引数据,包括每个切片在哪个窗口的数据,每个窗口中数据的一些具体的索引信息和状态,数据平台中的核心计算引擎会跟进。不是每隔几十秒就运行大量的SQL来计算一天的所有数据,而是基于一个个滑动的时间窗口,根据窗口标签提取那个窗口内的数据进行计算。只计算最近一个滑动时间窗口内的数据,然后这个滑动时间窗口内的数据可能有上千条左右,把所有复杂的SQL都跑一遍,计算出这个滑动时间窗口内的报表数据,然后合并这个窗口数据的计算结果和之前计算的其他窗口的计算结果,最后放到MySQL中的报表中另外这里还有一系列生产级的机制需要考虑,包括滑动时间窗口。如果计算失败怎么办?如果滑动时间窗口计算速度太慢怎么办?滑动窗口计算时系统死机,如何重启后自动恢复计算?等等,通过这个滑动窗口计算引擎,我们直接将系统计算性能提升了几十倍。基本上每个滑动窗口的数据都可以在几秒内完成所有报表的计算,相当于一下子完成了最后的呈现。用户实时数据的时效由几十秒提高到几秒。另外,看看下面的图片。11、离线计算环节的性能优化实时计算环节的性能问题由自研的滑动窗口计算引擎解决,但此时离线计算环节存在性能问题。..因为历史全量数据是每天凌晨从业务数据库离线导入,然后需要运行大量复杂的几千行复杂的SQL来对全量数百亿进行计算凌晨的数据。当数据量达到百亿级别时,这个过程需要很长时间,有时从凌晨到凌晨。关键问题是离线计算环节每天都要导入全量数据进行计算,非常可怜。这样做的原因是从业务数据库同步数据时,每天都会涉及到数据更新操作,而Hadoop中的数据不能像业务数据库那样更新,所以一开始每天全量导入历史数据,作为完整计算的最新快照。这里我们优化了离线计算环节,主要是从全量计算到增量计算:每天将数据导入Hadoop后,根据数据的业务时间戳分析提取每天变化的增量数据,而这些增量数据被放入独立的增量数据表中。同时需要根据具体的业务需求自动分析数据计算的基本血缘关系。有可能增量数据需要和全量数据的一部分混合才能完成计算。此时可能会提取全量历史数据的一部分,并结合起来完成计算。计算完成后,将计算结果与历史计算结果合并。完成了从全量计算到增量计算的转换过程,离线计算环节基本上凌晨就有上百亿的数据量。只需要一两个小时就可以完成昨天的增量数据的计算,然后就可以完成离线计算了。对于所有任务,性能至少比全计算高出十倍。12.阶段性总结至此,本系统是第一阶段做出的一套架构。不算太复杂,缺陷还是不少。不完美,但在当时的商业背景下,效果还是相当不错的。在该架构对应的早期业务背景中,每天新增数据约1亿条,但分库分表后,单表数据量在百万级别,一个表的峰值写入压力单台数据库服务器2000/s,查询压力100/s,数据库集群承载的总峰值写压力10000/s,查询压力500/s。如果需要,可以随时扩展更多的数据库服务器来承载更多的数据量。更高的写入并发和查询并发。而且,因为读写分离,高峰期各数据库服务器的CPU负载和IO负载不会满载,避免数据库服务器负载过大。自研的基于滑动时间窗的计算引擎,可以保证当天更新的实时数据可以在几秒内完成一个微批次的计算,反馈到用户看到的数据报表中.同时,这个引擎自己管理计算状态和日志。如果某个窗口出现计算失败、系统宕机、计算超时等各种异常情况,这个引擎可以自动重试和恢复。另外,昨天之前的海量数据是通过Hadoop和Spark生态离线存储和计算的。性能优化后,每天早上需要一两个小时的时间来计算昨天之前的所有数据。最后将实时和离线计算结果集成到同一个MySQL数据库中。此时,如果用户操作业务系统,实时数据报表会在几秒后刷新。如果想看昨天之前的数据,可以随时选择时间范围查看即临时是为了满足业务的需要。前几个月每天新增数亿条数据,离线和实时链路整体数据量达到百亿级。无论是存储扩展还是高效计算,这个架构基本都支持。十三。下一阶段展望本次大规模系统架构演进实践是一个系列文章,其中会包含很多篇文章,因为一次大规模系统架构演进的过程会持续很长时间,会做很多架构升级和重构,不断解决日益增长的技术挑战,最终完美抵御海量数据、高并发、高性能、高可用等场景。