系统架构-性能篇章1(应用系统性能1)

本文涉及的产品
云原生大数据计算服务 MaxCompute,5000CU*H 100GB 3个月
云原生大数据计算服务MaxCompute,500CU*H 100GB 3个月
简介:
 

在前面的文章中,说了很多JVM和数据库方面的东西,我所描述的内容大多偏重于技术本身,和实际的业务系统结合的比较少,本文开始进入实际的系统设计中应当注意的方方面面(文章偏重于访问量高,但是每次访问量并不是很大的系统),而偏重点在于性能和效率本身,由于这个知识涉及的基础和面很广,所以建议是先看下以前写的内容或自己有一定的基础来才开始接触比较好,另外本文也不能诠释性能的关键,从一个应用系统前端到后端涉及的部分非常多,本文也只会说明其中一部分,后续的部分我们再继续说;下面我们想一下一个web应用绝大部分请求的整个过程:client发出请求->server开始响应并创建请求对象及反馈对象->如果没有用户对象就创建session信息->调用业务代码->业务代码分层组织数据->调用数据(从某个远程或数据库或文件等)->开始组织输出数据->反馈数据开始通过模板引擎进行渲染->渲染完成未静态文件向客户端进行输出->待客户端接收完成结束掉请求对象(这种请求针对短连接,长连接有所区别)。

就从前端说起吧,说下一下几个内容:

1、线程数量

2、内容输出

3、线程上下文切换

4、内存

 

1.首先说下线程数量,线程数量很多人认为在配置服务器的线程数量时认为越多越好,各大网站上很多人也给出了自己的测试数据,也有人说了每个CPU配置多少线程为合适(比如有人说过每个CPU给25个线程较为合适),但是没有一个明确的为什么,其实这个要和CPU本身的运行效率和上来说明,并非一概而论的,也需要考虑每个请求所持有的CPU开销大小以及其处于非Running状态的时间来说明,线程配置得过多,其实往往会形成CPU的征用调度问题,要比较恰当将CPU用满才是性能的最佳状态(说到线程就不得不说下CPU,因为线程就是消耗CPU的,其本身持有的内存片段非常小,前面文章已经说明了它的内存使用情况,所以我们主要是讨论它与CPU之间的关系)。

首先内存到CPU的延迟在几十纳秒,虽然CPU内部的三级缓存比这个更加小,但是几乎对于我们所能识别的时间来讲可以被忽略;另外内存与CPU之间的带宽也是以最少几百M每秒的速度通信,所以对于内存与CPU交互数据的时间开销对于常规的高并发小请求的应用客户忽略掉,我们只计算本身的计算延迟开销以及非计算的等待开销,这些都一般会用毫秒来计算,相互之间是用10e6的级别来衡量,所以前者可以忽略,我们可以认为处于running的时间就是CPU实际执行的时间,因为这种短暂的时间也很难监控出来到底用了多久。

那么首先可以将线程的运行状态划分为两大类,就是:运行与等待,我们不考虑被释放的情况,因为线程池一般不会释放线程,至于等待有很多种,我们都认为它是等待就可以了;为什么是这两种呢,这两种正好对应了CPU是否在被使用,running状态的线程就在持有CPU的占用,等待的就处于没有使用CPU。

再明确一个概念,一个常规的web请求,后台对应一个线程对它的请求进行处理,同一个线程在同一个时间片上只能请求一个CPU为他进行处理,也就是说我们可以认为它不论请求过多少次CPU、不论请求了多少个CPU,只要这些CPU的型号是一样的,我们就可以认为它是请求的一个CPU(注意这里的CPU不包含多个core的情况,因为多个core的CPU只能说明这个CPU的处理速度可以接近于多个CPU的速度,而真正对线程的请求来讲,它认为这是一个CPU,在主板上也是一个插槽,所以计算CPU的时候不考虑多核心)。

最后明确线程在什么情况下会发生等待,比如读取数据库时,数据库尚未反馈内容之前,该线程是不会占用CPU的,只会处理等待;类似的是向客户端输出、线程为了去持有锁的等待一系列的情况。

此时一个线程过来如果一个线程毫无等待(这种情况不存在,只是一种假设),不论它处理多久,处理时间长度多长,此时如果只有一个CPU,那么这个应用服务器只需要一个1个线程就足以支撑,因为线程没有等待,那么CPU就没有停止运行,1个线程处理完这个请求后,接着就处理下一个请求,CPU一直是满的,也几乎没有太大的征用,此时1个线程就是最佳的,如果是多个同型号的CPU,那么就是CPU数量的线程是最佳的;不过这个例子比较极端,在很多类似的情况下,大家喜欢用CPU+1或CPU-1来完成对类似情况的线程设置,为了保证一些特殊情况的发生。

那么考虑下实际的情况,如果有等待,这个等待不是锁等待的(因为锁等待有瓶颈,瓶颈在于CPU的个数对于他们无效),应该如何考虑呢?我们此时来考虑下这个等待的时间长度应该如何去考虑,假如等待的时间长度为100ms,而运行的时间长度为10ms,那么在等待的这100ms中,就可以有另外10个线程进来,对CPU进行占用,也就是说对于单个CPU来说,11个线程就可以占满整个CPU的使用,如果是多个CPU当然在理论上可以乘以CPU的个数,这里再次强调,这里的CPU个数是物理的,而不算多核,多核在这里的意义比如以前一个CPU处理一个线程需要30ms,现在采用4个core,只需要处理10ms了,在这里体现了速度,所以计算是不要用它来计算。

那么对于锁等待呢?这个有点麻烦了,因为这个和模块有关系,这里也只能说明某个有锁等待的模块要达到最佳状态的访问效率可以配置的线程数,首先要明确锁等待已经没有CPU个数的概念,不论多少个CPU,只要运行到这段代码,他们就是一个CPU,不然锁就没有存在的意义了;另外,假如访问是非常密集的,那么当某个线程持有锁并访问的时候,其他没有得到的运行到这个位置都会处于等待,我们将一个模块的所有有锁等待的时间集中在一起,只有当前一个线程将具有锁的这段代码运行完成后,下一个线程才可以继续运行,所以它其他地方都没有瓶颈,或者说其他地方理论配置的线程数都会很高,唯独遇到这个地方就会很慢,假如一个线程从运行代码时长为20ms,等待事件为100ms,锁等待为20ms,此时假如该线程没有受到任何等待就是140ms即可运行完成,而当多个线程同时并发到这里的时候,后续每个线程将会等待20*N的时间长度,当有7个线程的时候,恰好排满运行的队列,也就是当又7个线程访问这个模块的时候,理论上刚好达到每个线程顺序执行而且成流水线状态,但是这里不能乘以CPU的个数了,为什么,你懂的。

 

2.内容输出,其实内容输出有很多种方法,在java方面,你可以自己编写OutputStream或者PrintWriter去输出,也可以用渲染模板去渲染输出,渲染的模板也有很多,最常见的就是JSP模板来渲染,也有velocity等各种各样的渲染模板,当然对于页面来讲只能用渲染模板去做,不过异步请求你可以选择,在选择时要对应选择才能将效果做得比较好。

说到这里不得不说下velocity这个东西,也就是经常看到的vm的文件,这种文件和JSP一样都是渲染模板的方法,只是语法格式有所区别,velocity是新出来的东西,很多人认为新的东西肯定很好,其实velocity是渲染效率很低的,在内容较小的输出上对性能进行压力测试,其单位时间内所能承受的访问量,比JSP渲染模板要低好几倍,不过对较大的数据输出和JSP差不多,也就是页面输出使用velocity无所谓的,而且效果比JSP要好,但是类似ajax交互中的小数据输出建议不要使用vm模板引擎,使用JSP模板引擎甚至于直接输出是最佳的方式。

说到这里JSP模板引擎在输出时是会被预先编译为java的class文件,VM是解释执行的,所以小文件两者性能差距很大,当遇到大数据输出时,其实大部分时间在输出文件的过程中,解释时间几乎就可以被忽略掉了。

那么JSP输出小文件是不是最快的呢?未必,JSP的输出其实是将JSP页面的内容组成字符串,最终使用PrintWriter流取完成,中间跳转交互其实还是蛮多的,而且有部分容器在组装字符串的时候竟然用+,这个让我很是郁闷啊,所以很多时候小数据的输出,我还是喜欢自己写,经过测试得到的结果是使用OutputStream的性能将会比PrintWriter高一些,(至于高多少,大家可以自己用工具或写代码测试下就知道了,这里可能单个处理速度几乎看不出区别,要并发访问看下平均每秒能处理的请求数就会有区别了),字符集方面,在获取要输出内容的时候,指定byte的字符集,如:String.getByte(“字符集”),一般这类输出也不会有表头,只需要和接收方或者叫浏览器一致就可以了(有些接收方可能是请求方);其实OutputStream比PrintWriter快速的原因很简单,在底层运行和传输的过程中,始终采用二进制流来完成,即使是字符也需要转换成byte格式,在转换前,它需要去寻找很多的字符集关系,最终定位到应该如何去转换,内部代码看过一下就明白,内部的方法调用非常多,一层套一层,相应占用的CPU开销也会升高。

总结起来说,如果你有vm模板引擎,在页面请求时建议使用vm模板引擎来做,因为代码要规范一些,而且也很好用;另外如果在简单的ajax请求,返回数据较小的情况下,建议使用OutputStream直接输出,这个输出可以放在你的BaseAction的中,对实现类中是透明的,实现类只需要将处理的反馈结果数据放在一个地方,由父类完成统一的输出即可,此处将Ajax类的调用可以独立一个父亲类出来,这样继承后就不用关心细节了。

输出中文件和大数据将是一个问题,对于文件来说,尤其是大文件,在前面文章已经说明,输出时压缩只能节省服务器输出时和客户端的流量,从而提高下载速度,但是绝对不会提高服务器端的性能,因为服务器端是通过消耗CPU去做动作,而且压缩的这个过程是需要时间的,这种只会降低速度,而绝对不会提高;那么大文件的方法就是一种是将大文件提前压缩好存放,如果实在太大,需要考虑采用断点传送,并将文件分解。

对大数据来讲,和文件类似,不过数据可能对我们要好处理一点,需要控制访问频率甚至于直接在超过访问频率下拒绝访问请求,每次请求的量也需要控制,如果对特殊大的数据量,建议采用异步方式输出到文件并压缩后,再由客户端下载,这样不论是客户端还是服务器端都是有好处的。

 

3、线程上下文切换,对于线程的上下文切换,在一般的系统中基本遇不到,不过一些特殊应用会遇到,比如刚才的异步导出的功能,请求的线程只是将事情提交上去,但是不是由它去下载,而是由其他线程再去处理这个问题,处理完成后再回写某个状态即可;在javaNIO中是非常的多,NIO是一种高性能服务器的解决方案,在有限的线程资源情况下,对极高并发的小请求,并存在很多推拉数据的情况下是很有效的,最大的要求就是服务器要有较好的连接支撑能力,NIO细节不用多说,理解上就是异步IO,把事情交给异步的一个线程去做,但是它也未必马上做,它做完再反馈,这段时间交给你的这个线程不是等待而是去做其他的事情,充分利用线程的资源,处理完反馈结果的线程也未必是开始请求的线程,几个来来回回是有很多的开销的,总体其实效率上未必有单个请求好,但是对服务器的性能发挥是非常有效的。

线程之间的开销大小也要看具体应用情况以及配置情况决定,此时将任务和线程没有做一个一对一的绑定,而是放一堆事情在队列中,处理线程也有很多,谁有时间处理谁就处理它,每个线程都做自己这一类的事情,甚至于将一些内容交给远程去做,交互后就不管了,结果反馈的时候,这边再由一个线程去处理结果请求即可。

在整个过程中会涉及到一次或多次的线程切换,这个过程中的开销在某些时候也是不小的,关键还是要看应用场景,不能一概而论。

4、内存,最后还是内存,其实这里我就不想多说了,因为前面几篇文章说得太多了,不论是理论上还是实现上,以及经验上都说了非常多,不过可以说明的一点就是内存的问题绝大部分来源于代码,而代码有很大一部分可能性来源于工程的程序员编写或者框架,第三方包的内存问题相对较少,一般被开源出来的包内存溢出的可能性不大,但是不排除有写得比较烂的代码;二方包呢,一般指代公司内部人员封装的包,如果在经过很多项目的验证可以比较放心使用,要绝对放心的话还是需要看看源码才行,至于JVM本身的BUG一般不要找到这个上面来,虽然也有这种可能性,不过这种问题除了升级JVM外也没有太多的办法,修改它的源码的可能性不大,除非你真的太厉害了(这里在内存上一般是指C或C++语言的源码,java部分的基础类包这些代码如果真的有问题,还是比较容易修改的,但还是不建议自己刻意去修改,除非你能肯定有你更好的解决方案而且是稳定有效的);在编写代码的时候将那些可以提前做的事情做了(比如这个事情以后会反复做,重复做,而且都是一样的,那么可以提前做一次,以后就不用做了),那些逻辑是可以省掉的,最后是如果你的应用很特殊是不是更好的解决方案和算法来完成。

 

总结下,从今天提到的系统设计的角度来说,影响QPS的最关键的东西就是模板渲染,它会占据请求的很大一部分时间,而且这个东西可以做非常大的改进,比如:压缩空白字符、重复对象的简化和模板化、大数据和重复信息的CSS化、尽量将输出转化为网络可以直接接受的内容;而其次就是如何配置线程,配置得太少,CPU的开销一直处于一种比较闲的状态,而配置得太多,CPU的征用情况比较严重,没有建议值,只要最适合应用场景的值,不过你的代码如果没有太多的同步,线程最少应该设置为CPU的格式+1或-1个;上下文切换对常规应用一般不要使用,对特殊的应用要注意中间的切换开销应该如何降低;文件输出上讲提前做的压缩提前做掉,注意控制访问频率和单次输出量;最后内存上多多注意代码,配置上只需要控制好常规的几个参数,其余的在没有特殊情况不要修改默认的配置。

 

扩展,那么关于一个系统的架构中是不是就这么一点就完了呢,当然不是,这应该说说出了一个常见的OLTP系统的一些常见的性能指标,但是还有很内容,比如:缓存、宕机类异常处理、session切换、IO、数据库、分布式、集群等都是这方面的关键内容,尤其是IO也是当今系统中性能瓶颈的最主要原因之一;在后续的文章中会逐步说明一些相关的解决方案。

相关实践学习
基于MaxCompute的热门话题分析
本实验围绕社交用户发布的文章做了详尽的分析,通过分析能得到用户群体年龄分布,性别分布,地理位置分布,以及热门话题的热度。
SaaS 模式云数据仓库必修课
本课程由阿里云开发者社区和阿里云大数据团队共同出品,是SaaS模式云原生数据仓库领导者MaxCompute核心课程。本课程由阿里云资深产品和技术专家们从概念到方法,从场景到实践,体系化的将阿里巴巴飞天大数据平台10多年的经过验证的方法与实践深入浅出的讲给开发者们。帮助大数据开发者快速了解并掌握SaaS模式的云原生的数据仓库,助力开发者学习了解先进的技术栈,并能在实际业务中敏捷的进行大数据分析,赋能企业业务。 通过本课程可以了解SaaS模式云原生数据仓库领导者MaxCompute核心功能及典型适用场景,可应用MaxCompute实现数仓搭建,快速进行大数据分析。适合大数据工程师、大数据分析师 大量数据需要处理、存储和管理,需要搭建数据仓库?学它! 没有足够人员和经验来运维大数据平台,不想自建IDC买机器,需要免运维的大数据平台?会SQL就等于会大数据?学它! 想知道大数据用得对不对,想用更少的钱得到持续演进的数仓能力?获得极致弹性的计算资源和更好的性能,以及持续保护数据安全的生产环境?学它! 想要获得灵活的分析能力,快速洞察数据规律特征?想要兼得数据湖的灵活性与数据仓库的成长性?学它! 出品人:阿里云大数据产品及研发团队专家 产品 MaxCompute 官网 https://www.aliyun.com/product/odps 
目录
相关文章
|
26天前
|
监控 安全 API
使用PaliGemma2构建多模态目标检测系统:从架构设计到性能优化的技术实践指南
本文详细介绍了PaliGemma2模型的微调流程及其在目标检测任务中的应用。PaliGemma2通过整合SigLIP-So400m视觉编码器与Gemma 2系列语言模型,实现了多模态数据的高效处理。文章涵盖了开发环境构建、数据集预处理、模型初始化与配置、数据加载系统实现、模型微调、推理与评估系统以及性能分析与优化策略等内容。特别强调了计算资源优化、训练过程监控和自动化优化流程的重要性,为机器学习工程师和研究人员提供了系统化的技术方案。
146 77
使用PaliGemma2构建多模态目标检测系统:从架构设计到性能优化的技术实践指南
|
20天前
|
机器学习/深度学习 算法 数据可视化
基于深度混合架构的智能量化交易系统研究: 融合SSDA与LSTM自编码器的特征提取与决策优化方法
本文探讨了在量化交易中结合时序特征和静态特征的混合建模方法。通过整合堆叠稀疏降噪自编码器(SSDA)和基于LSTM的自编码器(LSTM-AE),构建了一个能够全面捕捉市场动态特性的交易系统。SSDA通过降噪技术提取股票数据的鲁棒表示,LSTM-AE则专注于捕捉市场的时序依赖关系。系统采用A2C算法进行强化学习,通过多维度的奖励计算机制,实现了在可接受的风险水平下最大化收益的目标。实验结果显示,该系统在不同波动特征的股票上表现出差异化的适应能力,特别是在存在明确市场趋势的情况下,决策准确性较高。
57 5
基于深度混合架构的智能量化交易系统研究: 融合SSDA与LSTM自编码器的特征提取与决策优化方法
|
5天前
|
容灾 网络协议 数据库
云卓越架构:云上网络稳定性建设和应用稳定性治理最佳实践
本文介绍了云上网络稳定性体系建设的关键内容,包括面向失败的架构设计、可观测性与应急恢复、客户案例及阿里巴巴的核心电商架构演进。首先强调了网络稳定性的挑战及其应对策略,如责任共担模型和冗余设计。接着详细探讨了多可用区部署、弹性架构规划及跨地域容灾设计的最佳实践,特别是阿里云的产品和技术如何助力实现高可用性和快速故障恢复。最后通过具体案例展示了秒级故障转移的效果,以及同城多活架构下的实际应用。这些措施共同确保了业务在面对网络故障时的持续稳定运行。
|
1月前
|
机器学习/深度学习 人工智能 并行计算
【AI系统】Kernel 层架构
推理引擎的Kernel层负责执行底层数学运算,如矩阵乘法、卷积等,直接影响推理速度与效率。它与Runtime层紧密配合,通过算法优化、内存布局调整、汇编优化及调度优化等手段,实现高性能计算。Kernel层针对不同硬件(如CPU、GPU)进行特定优化,支持NEON、AVX、CUDA等技术,确保在多种平台上高效运行。
84 32
|
1月前
|
存储 机器学习/深度学习 人工智能
【AI系统】计算图优化架构
本文介绍了推理引擎转换中的图优化模块,涵盖算子融合、布局转换、算子替换及内存优化等技术,旨在提升模型推理效率。计算图优化技术通过减少计算冗余、提高计算效率和减少内存占用,显著改善模型在资源受限设备上的运行表现。文中详细探讨了离线优化模块面临的挑战及解决方案,包括结构冗余、精度冗余、算法冗余和读写冗余的处理方法。此外,文章还介绍了ONNX Runtime的图优化机制及其在实际应用中的实现,展示了如何通过图优化提高模型推理性能的具体示例。
57 4
【AI系统】计算图优化架构
|
16天前
|
机器学习/深度学习 存储 人工智能
基于AI的实时监控系统:技术架构与挑战分析
AI视频监控系统利用计算机视觉和深度学习技术,实现实时分析与智能识别,显著提升高风险场所如监狱的安全性。系统架构包括数据采集、预处理、行为分析、实时决策及数据存储层,涵盖高分辨率视频传输、图像增强、目标检测、异常行为识别等关键技术。面对算法优化、实时性和系统集成等挑战,通过数据增强、边缘计算和模块化设计等方法解决。未来,AI技术的进步将进一步提高监控系统的智能化水平和应对复杂安全挑战的能力。
|
21天前
|
机器学习/深度学习 前端开发 算法
婚恋交友系统平台 相亲交友平台系统 婚恋交友系统APP 婚恋系统源码 婚恋交友平台开发流程 婚恋交友系统架构设计 婚恋交友系统前端/后端开发 婚恋交友系统匹配推荐算法优化
婚恋交友系统平台通过线上互动帮助单身男女找到合适伴侣,提供用户注册、个人资料填写、匹配推荐、实时聊天、社区互动等功能。开发流程包括需求分析、技术选型、系统架构设计、功能实现、测试优化和上线运维。匹配推荐算法优化是核心,通过用户行为数据分析和机器学习提高匹配准确性。
67 3
|
19天前
|
前端开发 搜索推荐 安全
陪玩系统架构设计陪玩系统前后端开发,陪玩前端设计是如何让人眼前一亮的?
陪玩系统的架构设计、前后端开发及前端设计是构建吸引用户、功能完善的平台关键。架构需考虑用户需求、技术选型、安全性等,确保稳定性和扩展性。前端可选用React、Vue或Uniapp,后端用Spring Boot或Django,数据库结合MySQL和MongoDB。功能涵盖用户管理、陪玩者管理、订单处理、智能匹配与通讯。安全性方面采用SSL加密和定期漏洞扫描。前端设计注重美观、易用及个性化推荐,提升用户体验和平台粘性。
52 0
|
19天前
|
监控 Java 数据中心
微服务架构系统稳定性的神器-Hystrix
Hystrix是由Netflix开源的库,主要用于微服务架构中的熔断器模式,防止服务调用失败引发级联故障。它通过监控服务调用的成功和失败率,在失败率达到阈值时触发熔断,阻止后续调用,保护系统稳定。Hystrix具备熔断器、资源隔离、降级机制和实时监控等功能,提升系统的容错性和稳定性。然而,Hystrix也存在性能开销、配置复杂等局限,并已于2018年进入维护模式。
26 0
|
1月前
|
机器学习/深度学习 人工智能 调度
【AI系统】推理引擎架构
本文详细介绍了推理引擎的基本概念、特点、技术挑战及架构设计。推理引擎作为 AI 系统中的关键组件,负责将训练好的模型部署到实际应用中,实现智能决策和自动化处理。文章首先概述了推理引擎的四大特点:轻量、通用、易用和高效,接着探讨了其面临的三大技术挑战:需求复杂性与程序大小的权衡、算力需求与资源碎片化的矛盾、执行效率与模型精度的双重要求。随后,文章深入分析了推理引擎的整体架构,包括优化阶段的模型转换工具、模型压缩、端侧学习等关键技术,以及运行阶段的调度层、执行层等核心组件。最后,通过具体的开发流程示例,展示了如何使用推理引擎进行模型的加载、配置、数据预处理、推理执行及结果后处理。
89 0

热门文章

最新文章