同事们总是抱怨我的接口性能不好,原来罪魁祸首就在这里如何承载这种高并发的写法,后台如何保证系统的超高性能计算高并发写法。我们继续说这篇文章。在百亿级海量数据场景下,需要支持每秒10万级别的高并发查询。这种架构应该如何演进和设计?我们先来看看系统演进到什么样的架构。我们先看下图:首先我们回顾一下,整个架构右边的部分进化到什么程度其实是非常好的,因为百亿级的流量,每个每秒10万级并发写入的场景可以通过MQ限流调峰、分布式KV集群来抵御。然后,使用计算和存储分离架构。每个Slave计算节点将负责将数据提取到内存中,并基于自研的SQL内存计算引擎完成计算。同时采用了数据动静分离的结构,静态数据全部缓存,动态数据自动提取,保证了网络请求开销尽可能的降到最低。此外,通过自主研发的分布式系统架构,包括计算任务的数据分片和分布式执行、弹性资源调度、分布式高容错机制、自动主备切换机制,可以保证任意按需扩展整个系统,高性能,高可用运行。在下一步中,让我们研究研究架构的左侧部分。2.不断增长的离线计算结果。其实你会注意到,左边还有一个MySQL,用来承载实时计算结果和离线计算结果。总结在里面。终端业务用户可以在MySQL中自由查询数据分析结果,支持自己的决策。他可以查看当天的数据分析报告,也可以查看历史上任意一个时期的数据分析报告。但是早期那个MySQL可能比较好,因为这个MySQL存储的数据量比较小,毕竟只是一些计算后的结果。但是到了中后期,这个MySQL也岌岌可危了。让我举一个例子。在离线计算环节,如果增量数据是每天1000万条,那么计算后的结果只有每天50万条左右。每天50万条新数据放入MySQL,其实是可以接受的。但是如果每天增量数据是10亿,那么每天计算出来的结果大概是几千万。可以算出计算结果中有5000万条数据,每天向左边的MySQL写入5000万增量数据。在,你觉得它是什么感觉?我可以告诉你当时系统的情况。基本上单个MySQL服务器的磁盘存储空间很快就会接近满,单个表的数据量是上亿,甚至上亿。这么大的单表数据量,你觉得用户查询数据分析报表的体验会好吗?基本上那个时候一个查询就是几秒级别的。非常慢。更有什者,曾经出现过用户查询需要十几秒,甚至几十秒,甚至几分钟的情况。很破,用户体验很差,和付费产品的水平相去甚远。因此,解决了右侧的存储和计算问题后,左侧的查询问题就迫在眉睫了。新一轮重建势在必行!3.分库分表+读写分离首先是老套路,分库分表+读写分离,这个基本上是基于MySQL架构的,唯一的办法,毕竟它实现起来不是特别困难,速度也比较快,效果比较显着。整个思路和之前的第一篇文章基本一致:《??别光看NB的Github开源项目,你得参考他们去设计自己的架构??》。说白了,分库后,每个主库都可以承担一部分写压力,单个库的写并发会降低;其次,单个主库的磁盘空间可以减少数据负载量,不会很快被占满;分表后,单个数据表的数据量可以降低到百万级别。这是支撑海量数据和保证高性能的最佳实践。基本上单表数据量两三百万是合理的。那么读写分离后,就可以将单个库的读写负载压力分离到主库和从库的多台机器上。主库承担写负载,从库承担读负载。写入负载过高,导致CPU负载、IO负载、网络负载都很高,最后导致数据库机器崩溃。首先,通过这种方式重构数据库级架构后,效果要好很多。因为减少了单表的数据量,大大提高了用户查询的性能,基本可以在1秒内达到效果。4、每秒10万查询的高并发挑战上面初步的分库分表+读写分离架构确实支撑了一段时间,但是慢慢的那个架构的弊端又暴露出来了,因为商家用户打开数据分析页面后,页面上的js脚本会每隔几秒向后台发送一次请求,加载最新的数据分析结果。这时候就有问题了。渐渐地,查询MySQL的压力越来越大。基本上,可预见的范围正在朝着每秒10个的水平迈进。但是我们分析了。其实99%的查询都是页面JS脚本自动发送刷新当天数据的查询。只有1%的查询是针对昨天之前的历史数据,用户手动指定查询范围再查询。但是在现在的架构下,我们把当天的实时数据计算结果(代表热数据)和历史离线计算结果(代表冷数据)放在一起,所以你可以想象,热数据和冷数据放在一起,并且那么热点数据的高并发查询占比99%,那么这样的架构合理吗?当然不合理,我们需要重新重构系统架构。5.冷热数据分离架构鉴于上述问题,显然要做的架构改造之一就是冷热数据分离。也就是说,把今天实时计算的热数据放在一个MySQL集群中,把离线计算的冷数据放在另一个MySQL集群中。然后开发数据查询平台,封装多个底层MySQL集群,根据查询情况动态路由到热数据存储或冷数据存储。通过这一步的重构,我们可以有效的将热数据存储中单表??的数据量减少到更少,而有些单表的数据量可能是几十万,因为大量的数据导致离线计算是从表和里面剥离出来放在另一个集群中。这个时候大家可以想象一下,效果当然更好了。因为热点数据的单表数据量已经大大减少,当时最明显的一个效果就是99%的用户查询都是针对热点数据存储发起的,性能从1秒左右下降到不到200秒毫秒。提升,每个人都感觉更好。6、自研的Elasticsearch+HBase+纯内存查询引擎架构演化至此。好像还不错,但是还是有很多问题。因为在这个阶段,系统又遇到了一个比较严重的问题:数据冷存储,如果完全由MySQL托管,是非常不可靠的。冷数据量每天都在增加,而且增长速度非常快,每天都在增加几千万。所以,你的MySQL服务器就会面临不断扩容的问题,如果你不断扩容,再加一台高配置的MySQL服务器,来支撑那1%的冷数据查询请求,你觉得靠谱吗?一定是不合适!要知道,大量的分库分表后,维护大量的MySQL分库分表是相当麻烦的。修改字段?添加索引?都是麻烦事。另外,由于冷数据的查询一般是对大量数据的查询,比如用户会选择最近几个月甚至一年的数据进行分析查询。这个时候,如果单纯使用MySQL,后果会相当惨重。因为当时很明显,对于海量数据场景,一次性查询分析几个月或者几年的数据,性能极差,很容易几秒甚至几十秒就出结果。因此,针对冷数据的存储和查询问题,我们最终选择了开发一套自研的基于NoSQL的存储,然后是基于NoSQL+内存的SQL计算引擎。具体来说,我们会使用ES+HBase来存储所有的冷数据。ES主要存储各种过滤冷数据的条件索引,比如日期,各种维度的数据,然后HBase存储全量数据字段。因为ES和HBase原生的SQL支持不是很好,所以我们直接又开发了一套SQL引擎来支持这个特定场景,也就是基本没有多表关联,都是查询分析单条数据放。然后支持NoSQL存储+内存计算。这里有一个前提,就是如果要查询的冷数据都是单表数据集,冷数据进入NoSQL存储时,必须根据ES和HBase的特点实现多表入库关联。进入数据存储时,全部做成大宽表状态,所有数据关联上推到仓库,而不是查询时。对于冷数据查询,我们自研的SQL引擎首先使用了ES基于各种where条件的分布式高性能索引查询。ES可以高性能地检索海量数据所需的部分数据。这个过程用ES来做是最合适的。下一步就是从HBase中提取出检索到的数据对应的完整数据字段,拼接成完整的数据。然后就是把这个数据集放到内存中,进行复杂的函数计算,分组聚合,排序操作。以上操作均基于本场景自研查询引擎,底层基于Elasticsearch、HBase、纯内存。7、缓存集群引入实时数据存储。至此解决了海量数据存储和冷数据的高性能查询问题。然后回头看看当天的实时数据查询。其实实时数据每天的计算结果不会太多,写并发也不会特别高,每秒几万左右。因此,在这种背景下,使用MySQL分库分表来支持数据的写入、存储和查询是没有问题的。但是有个小问题,就是每个商户的实时数据不会经常变化。在一段时间内,可能根本不会变,所以不需要高并发请求,每秒10万级别的数据全部在数据库层面实现。酒吧?全部在数据库层面实现,可能需要给每个主库挂载很多从库,以支持高并发读取。因此,我们在这里引入了缓存集群。每次更新后写入实时数据时,会写入数据库集群,同时也会写入缓存集群。这是一种双写方法。那么在查询的时候,优先从缓存簇中走。这时候基本上90%以上的高并发查询都会去缓存集群,只有10%的查询会落地到数据库集群。第八,阶段性总结完成。至此,这个架构的左侧已经基本重构:热点数据基于缓存集群+数据库集群承载每秒10万级的高并发查询。冷数据基于自主研发的ES+HBase+内存计算的查询引擎,支持海量数据存储和高性能查询。经过实践,整体效果非常好。用户查询热数据基本有几十毫秒的响应速度,查询冷数据基本只有不到200毫秒的响应速度。九。下一阶段的展望其实要演进这里的架构并不容易,因为看起来这样的一张图涉及到无数的细节和技术方案的实现。一个团队至少需要一年的时间才能实现。这个水平。但是接下来,我们要面对的就是高可用的问题,因为对于付费级别的产品,我们必须要保证超高可用,99.99%的可用性,甚至是99.999%的可用性。
