同事老是吐槽我的接口性能差,原来真凶就在这里!

news2024/11/16 7:43:34
V-xin:ruyuanhadeng获得600+页原创精品文章汇总PDF

一、前情回顾

上篇文章:《为什么每个程序员都必须坚持写博客?这篇文章教你怎么写!》聊了一下系统架构中,百亿流量级别高并发写入场景下,如何承载这种高并发写入,同时如何在高并发写入的背景下还能保证系统的超高性能计算。

这篇文章咱们继续来聊一下,百亿级别的海量数据场景下还要支撑每秒十万级别的高并发查询,这个架构该如何演进和设计?

咱们先来看看目前系统已经演进到了什么样的架构,大家看看下面的图:

在这里插入图片描述

首先回顾一下,整个架构右侧部分演进到的那个程度,其实已经非常的不错了,因为百亿流量,每秒十万级并发写入的场景,使用MQ限流削峰、分布式KV集群给抗住了。

接着使用了计算与存储分离的架构,各个Slave计算节点会负责提取数据到内存中,基于自研的SQL内存计算引擎完成计算。同时采用了数据动静分离的架构,静态数据全部缓存,动态数据自动提取,保证了尽可能把网络请求开销降低到最低。

另外,通过自研的分布式系统架构,包括数据分片和计算任务分布式执行、弹性资源调度、分布式高容错机制、主备自动切换机制,都能保证整套系统的任意按需扩容,高性能、高可用的的运行。

下一步,咱们来研究研究架构里的左侧部分


二、日益膨胀的离线计算结果

其实大家会注意到,在左侧还有一个MySQL,那个MySQL就是用来承载实时计算结果和离线计算结果放在里面汇总的。

终端的商家用户就可以随意的查询MySQL里的数据分析结果,支撑自己的决策,他可以看当天的数据分析报告,也可以看历史上任何一段时期内的数据分析报告。

但是那个MySQL在早期可能还好一些,因为其实存放在这个MySQL里的数据量相对要小一些,毕竟是计算后的一些结果罢了。但是到了中后期,这个MySQL可是也岌岌可危了。


给大家举一个例子,离线计算链路里,如果每天增量数据是1000万,那么每天计算完以后的结果大概只有50万,每天50万新增数据放入MySQL,其实还是可以接受的。

但是如果每天增量数据是10亿,那么每天计算完以后的结果大致会是千万级,你可以算他是计算结果有5000万条数据吧,每天5000万增量数据写入左侧的MySQL中,你觉得是啥感觉?

可以给大家说说系统当时的情况,基本上就是,单台MySQL服务器的磁盘存储空间很快就要接近满掉,而且单表数据量都是几亿、甚至十亿的级别。

这种量级的单表数据量,你觉得用户查询数据分析报告的时候,体验能好么?基本当时一次查询都是几秒钟的级别。很慢。

更有甚者,出现过用户一次查询要十秒的级别,甚至几十秒,上分钟的级别。很崩溃,用户体验很差,远远达不到付费产品的级别。

所以解决了右侧的存储和计算的问题之后,左侧的查询的问题也迫在眉睫。新一轮的重构,势在必行!


三、分库分表 + 读写分离

首先就是老一套,分库分表 + 读写分离,这个基本是基于MySQL的架构中,必经之路了,毕竟实施起来难度不是特别的高,而且速度较快,效果比较显著。

整个的思路和之前第一篇文章:《别光看NB的Github开源项目,你得参考他们去设计自己的架构!》讲的基本一致。

说白了,就是分库后,每台主库可以承载部分写入压力,单库的写并发会降低;其次就是单个主库的磁盘空间可以降低负载的数据量,不至于很快就满了;

而分表之后,单个数据表的数据量可以降低到百万级别,这个是支撑海量数据以及保证高性能的最佳实践,基本两三百万的单表数据量级还是合理的。

然后读写分离之后,就可以将单库的读写负载压力分离到主库和从库多台机器上去,主库就承载写负载,从库就承载读负载,这样避免单库所在机器的读写负载过高,导致CPU负载、IO负载、网络负载过高,最后搞得数据库机器宕机。

首先这么重构一下数据库层面的架构之后,效果就好的多了。因为单表数据量降低了,那么用户查询的性能得到很大的提升,基本可以达到1秒以内的效果。

在这里插入图片描述

四、每秒10万查询的高并发挑战

上面那套初步的分库分表+读写分离的架构确实支撑了一段时间,但是慢慢的那套架构又暴露出来了弊端出来了,因为商家用户都是开了数据分析页面之后,页面上有js脚本会每隔几秒钟就发送一次请求到后端来加载最新的数据分析结果。

此时就有一个问题了,渐渐的查询MySQL的压力越来越大,基本上可预见的范围是朝着每秒10级别去走。

但是我们分析了一下,其实99%的查询,都是页面JS脚本自动发出刷新当日数据的查询。只有1%的查询是针对昨天以前的历史数据,用户手动指定查询范围后来查询的。

但是现在的这个架构之下,我们是把当日实时数据计算结果(代表了热数据)和历史离线计算结果(代表了冷数据)都放在一起的,所以大家可以想象一下,热数据和冷数据放在一起,然后对热数据的高并发查询占到了99%,那这样的架构还合理吗?

当然不合理,我们需要再次重构系统架构


五、 数据的冷热分离架构

针对上述提到的问题,很明显要做的一个架构重构就是**冷热数据分离。**也就是说,将今日实时计算出来的热数据放在一个MySQL集群里,将离线计算出来的冷数据放在另外一个MySQL集群里。

然后开发一个数据查询平台,封装底层的多个MySQL集群,根据查询条件动态路由到热数据存储或者是冷数据存储。

通过这个步骤的重构,我们就可以有效的将热数据存储中单表的数据量降低到更少更少,有的单表数据量可能就几十万,因为将离线计算的大量数据结果从表里剥离出去了,放到另外一个集群里去。此时大家可想而知,效果当然是更好了。

因为热数据的单表数据量减少了很多,当时的一个最明显的效果,就是用户99%的查询都是针对热数据存储发起的,性能从原来的1秒左右降低到了200毫秒以内,用户体验提升,大家感觉更好了。
在这里插入图片描述

六、自研Elasticsearch+HBase+纯内存的查询引擎

架构演进到这里,看起来好像还不错,但是其实问题还是很多。因为到了这个阶段,系统遇到了另外一个较为严重的问题:冷数据存储,如果完全用MySQL来承载是很不靠谱的。冷数据的数据量是日增长不断增加,而且增速很快,每天都新增几千万。

因此你的MySQL服务器将会面临不断的需要扩容的问题,而且如果为了支撑这1%的冷数据查询请求,不断的扩容增加高配置的MySQL服务器,大家觉得靠谱么?

肯定是不合适的!

要知道,大量分库分表后,MySQL大量的库和表维护起来是相当麻烦的,修改个字段?加个索引?这都是一场麻烦事儿。

此外,因为对冷数据的查询,一般都是针对大量数据的查询,比如用户会选择过去几个月,甚至一年的数据进行分析查询,此时如果纯用MySQL还是挺灾难性的。

因为当时明显发现,针对海量数据场景下,一下子查询分析几个月或者几年的数据,性能是极差的,还是很容易搞成几秒甚至几十秒才出结果。

因此针对这个冷数据的存储和查询的问题,我们最终选择了自研一套基于NoSQL来存储,然后基于NoSQL+内存的SQL计算引擎。


具体来说,我们会将冷数据全部采用ES+HBase来进行存储,ES中主要存放要对冷数据进行筛选的各种条件索引,比如日期以及各种维度的数据,然后HBase中会存放全量的数据字段。

因为ES和HBase的原生SQL支持都不太好,因此我们直接自研了另外一套SQL引擎,专门支持这种特定的场景,就是基本没有多表关联,就是对单个数据集进行查询和分析,然后支持NoSQL存储+内存计算。

这里有一个先决条件,就是如果要做到对冷数据全部是单表类的数据集查询,必须要在冷数据进入NoSQL存储的时候,全部基于ES和HBase的特性做到多表入库关联,进数据存储就全部做成大宽表的状态,将数据关联全部上推到入库时完成,而不是在查询时进行。

对冷数据的查询,我们自研的SQL引擎首先会根据各种where条件先走ES的分布式高性能索引查询,ES可以针对海量数据高性能的检索出来需要的那部分数据,这个过程用ES做是最合适的。

接着就是将检索出来的数据对应的完整的各个数据字段,从HBase里提取出来,拼接成完成的数据。

然后就是将这份数据集放在内存里,进行复杂的函数计算、分组聚合以及排序等操作。

上述操作,全部基于自研的针对这个场景的查询引擎完成,底层基于Elasticsearch、HBase、纯内存来实现。

在这里插入图片描述

七、实时数据存储引入缓存集群

好了,到此为止,冷数据的海量数据存储、高性能查询的问题,就解决了。接着回过头来看看当日实时数据的查询,其实实时数据的每日计算结果不会太多,而且写入并发不会特别特别的高,每秒上万也就差不多了。

因此这个背景下,就是用MySQL分库分表来支撑数据的写入、存储和查询,都没问题。

但是有一个小问题,就是说每个商家的实时数据其实不是频繁的变更的,在一段时间内,可能压根儿没变化,因此不需要高并发请求,每秒10万级别的全部落地到数据库层面吧?要全都落地到数据库层面,那可能要给每个主库挂载很多从库来支撑高并发读。

因此这里我们引入了一个缓存集群,实时数据每次更新后写入的时候,都是写数据库集群同时还写缓存集群的,是双写的方式。

然后查询的时候是优先从缓存集群来走,此时基本上90%以上的高并发查询都走缓存集群了,然后只有10%的查询会落地到数据库集群。

在这里插入图片描述

八、阶段性总结

好了,到此为止,这个架构基本左边也都重构完毕:

  • 热数据基于缓存集群+数据库集群来承载高并发的每秒十万级别的查询
  • 冷数据基于ES+HBase+内存计算的自研查询引擎来支撑海量数据存储以及高性能查询。

经实践,整个效果非常的好。用户对热数据的查询基本多是几十毫秒的响应速度,对冷数据的查询基本都是200毫秒以内的响应速度。

九、下一阶段的展望

其实架构演进到这里已经很不容易了,因为看似这么一张图,里面涉及到无数的细节和技术方案的落地,需要一个团队耗费至少1年的时间才能做到这个程度。

但是接下来,我们要面对的,就是高可用的问题,因为付费级的产品,我们必须要保证超高的可用性,99.99%的可用性,甚至是99.999%的可用性。

V-xin:ruyuanhadeng获得600+页原创精品文章汇总PDF

另外推荐儒猿课堂的1元系列课程给您,欢迎加入一起学习~

互联网Java工程师面试突击课(1元专享)

SpringCloudAlibaba零基础入门到项目实战(1元专享)

亿级流量下的电商详情页系统实战项目(1元专享)

Kafka消息中间件内核源码精讲(1元专享)

12个实战案例带你玩转Java并发编程(1元专享)

Elasticsearch零基础入门到精通(1元专享)

基于Java手写分布式中间件系统实战(1元专享)

基于ShardingSphere的分库分表实战课(1元专享)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/55853.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Kotlin高仿微信-第37篇-拍照

Kotlin高仿微信-项目实践58篇详细讲解了各个功能点,包括:注册、登录、主页、单聊(文本、表情、语音、图片、小视频、视频通话、语音通话、红包、转账)、群聊、个人信息、朋友圈、支付服务、扫一扫、搜索好友、添加好友、开通VIP等众多功能。 Kotlin高仿…

ZPL II 语言编程基础

ZPL II 语言概述 ZPL语言是一种script语言,分为ZPL语言和ZPL II 语言Zebra打印机支持最广泛的一种语言 ZPL II语言支持复杂标签格式,如文字,图片,条形码,序列号打印等等 ZPL II文件可以通过以下两种方式实现 纯文本编…

java字符编码总结

一、字符集(Charcater Set)与字符编码(Encoding) 字符集(Charcater Set 或 Charset):是一个系统支持的所有抽象字符的集合,也就是一系列字符的集合。字符是各种文字和符号的总称,包括各国家文字、标点符号、图形符号、数字等。常见的字符集有…

记录--从AI到美颜全流程讲解

这里给大家分享我在网上总结出来的一些知识,希望对大家有所帮助 美颜和短视频 美颜相关APP可以说是现在手机上的必备的软件,例如抖音,快手,拍出的“照骗”和视频不加美颜效果,估计没有人敢传到网上。很多人一直好奇美颜…

力扣hot100——第3天:11盛最多水的容器、15三数之和、17电话号码的字母组合

文章目录1.11盛最多水的容器1.1.题目1.2.解答1.2.1.题解1.2.2.自己对参考题解的进一步解释2.15三数之和【代码随想录已刷】3.17电话号码的字母组合【代码随想录已刷】1.11盛最多水的容器 参考:力扣题目链接;题解 1.1.题目 1.2.解答 1.2.1.题解 这道题…

Mybatis-多表联查

多表联查一、步骤一:创建pojo实体类二、步骤二:明确两个实体类之间的关系三、步骤三:修改pojo实体类四、步骤四:编写Mapper接口五、步骤五:编写Mapper映射文件题目1:通过订单id查询订单详情以及所属用户题目2:通过用户…

OpenCV入门(C++/Python)- 使用OpenCV读取、显示和写入图像(一)

使用OpenCV读取、显示和写入图像1.imread()读取图像imread()函数2.imshow()在窗口中显示图像waitKey()destoryAllWindows()3.imwrite()将图像写入文件目录读取、显示和写入图像是图像处理和计算机视觉的基础。即使裁剪、调整大小、旋转或应用不同的过滤器来处理图像&#xff0c…

C. Carrying Conundrum(思维 + 奇偶数位)

Problem - 1567C - Codeforces 爱丽丝刚刚学会了加法。但是,她还没有完全学会 "携带 "的概念--她不是携带到下一列,而是携带到左边两列的列。 例如,评估20392976这个和的常规方法是如图所示。 然而,爱丽丝是按照图中的…

【在SpringBoot项目中使用Validation框架检查数据格式-常用的检查注解】

常用的检查注解 使用Validation框架检查数据格式时,常用的检查注解有: NotNull:不允许为null值 可用于任何类型的参数NotEmpty:不允许为空字符串,即长度为0的字符串 仅用于检查字符串类型的参数NotBlank:不…

【D3.js】1.17-给 D3 元素添加标签

title: 【D3.js】1.17-给 D3 元素添加标签 date: 2022-12-02 14:35 tags: [JavaScript,CSS,HTML,D3.js,SVG] 为了让图更易懂,我们给每一个rect添加上标签。 一、学习目标 如何添加text元素? .append(“text”) 如何设置text元素的值? .attr(…

[附源码]计算机毕业设计在线图书销售系统Springboot程序

项目运行 环境配置: Jdk1.8 Tomcat7.0 Mysql HBuilderX(Webstorm也行) Eclispe(IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持)。 项目技术: SSM mybatis Maven Vue 等等组成,B/S模式 M…

IPWorks macOS Edition通信组件

IPWorks macOS Edition通信组件 用于Internet通信的一整套组件。 IPWorks是一个用于Internet开发的综合框架,它消除了Internet开发的复杂性,提供了可编程的、支持SSL的组件,以便于执行诸如确保安全、发送电子邮件、传输文件、管理网络、浏览W…

物联网 MQTT 协议

MQTT官网:MQTT - The Standard for IoT Messaging MQTT中文网(全是广告):首页 | MQTT中文网 物联网百科 物联网(Internet of Things,简称IoT)是指通过各种信息传感器、射频识别技术、全球定位…

在线编程教学技术解决方案,覆盖所有授课场景需求

在线编程教学是一种应用较为广泛的远程教学形式,例如:互动体验,音视频技术的普及,对线上教学的质量与学习效率带来了很大的提升。在线编程教学可以让教师对学生进行在线编程教学,以一对多小班教学为主。那么在线编程教…

线上项目源码安全性处理方案

场景: 最近项目提出要对线上代码进行安全性处理,防止客户直接通过反编译工具将代码反编译出来 方案: 第一种方案使用的是代码混淆 第二种方案使用的是代码加密 方案比较 方案一:采用的proguard-maven-plugin插件 方案二&#xf…

要花多少亿美元,HPE才能买下超融合鼻祖Nu­t­a­n­ix?

【全球存储观察 | 热点关注】据报道,慧与科技HPE在近几个月与超融合提供商Nutanix就收购进行了谈判。 在这之前的2017年2月,HPE以6.5亿美元收购了超融合全球老二SimpliVity,后来整合成了HPE重要的超融合产品线,并进一步丰富了整体…

Seal库官方示例(五):ckks_basics.cpp解析

这个代码计算的是πx30.4x1\pi \times x^30.4 \times x 1πx30.4x1。 代码解析 方案选择 首先照例是方案选择 EncryptionParameters parms(scheme_type::ckks);参数设置 CKKS方案中使用rescale方法来控制膨胀的密文规模和噪声,这个和modulus switching有点类似…

[激光原理与应用-28]:《激光原理与技术》-14- 激光产生技术 - 激光的主要参数与指标

目录 1、 激光器的门限电流与功率输出 2、激光器的调制增益 3、功率/能量密度 6、额定功耗 7、转换效率 8、光斑大小 9、线宽 10、激光器的谱线宽度。 11、激光器的相对强度噪声RIN。 12、激光器的线性范围。 13、带内平坦度 14、激光器的温度特性 15、激光器的交…

基于PHP+MySQL信息技术学习网站设计与实现

智多在线网络学习平台为学习各种技术查看资料的用户提供一个准确、最新的技术与相关文档,浏览目前流行教学的新闻,提出技术上遇到的难点及问题,帮助其他用户回答所提出的问题,上传想要分享的资源,下载要获取的相关技术…

Spirng MVC——获取参数详解

文章目录1. 什么是 Spirng MVC1.1 MVC 定义1.2 MVC 和 Spring MVC 的关系2. 创建Spring MVC 项目3. Spring MVC 学习目标3.1 实现用户和程序的映射方法1:RequestMapping("/xxx")方法2:使用 POSTMapping("/xxx")方法3:使用…