写点什么

架构师训练营 1 期第 7 周:性能优化(一)- 总结

用户头像
piercebn
关注
发布于: 2020 年 11 月 07 日

本文主要介绍如何做系统的性能测试,以及根据测试结果,对系统进行性能优化的思路和手段。



一、性能测试:系统性能的主要技术指标

性能测试

  • 性能测试是性能优化的前提和基础,也是性能优化结果的检查和度量标准。不同视角下的网站性能有不同的标准,也有不同的优化手段。 

  • 主观视角:用户感受到的性能,快,爽,友好提示 

  • 客观视角:性能指标衡量的性能,具体的测试指标高低

  • 性能优化的最终目的是让用户感受的性能好,所以作为架构师在进行性能优化的时候,一方面真实的要提高客观的性能指标,另一方面也不能一门心思的扎到客观指标上去,也要考虑到最终目的是要提升用户的主观感受,想办法让用户主观感受更好些,比如通过异步操作,友好提示等方式让用户感受体验更好些。

  • 这里主要关注的是客观性能指标



性能测试指标

  • 不同视角下有不同的性能标准,不同的标准有不同的性能测试指标,网站性能测试的主要指标有响应时间、并发数、吞吐量、性能计数器等。

  • 响应时间、并发数、吞吐量是核心的反映性能的主要指标,性能计数器通常是关于系统资源利用的一些辅助指标。



响应时间

  • 指应用系统从发出请求开始到收到最后响应数据所需要的时间。响应时间是系统最重要的性能指标,直观的反映了系统的“快慢”。

  • 从服务器端角度说就是,从收到请求开始到返回响应花费的时间

  • 响应时间越短,系统越快,性能越好;响应时间越长,系统越慢,系统体验越差

并发数

  • 系统能够同时处理请求的数目(比如10台服务器,某一时间点,同时正在处理的请求的数目,是个瞬时值,比如100个请求正在处理,每台服务器有10个请求在处理,在这一时刻时间点的并发数就是100),这个数字也反映了系统的负载特性。对于网站而言,并发数即系统并发用户数,指同时提交请求的用户数目,于此相对应,还有在线用户数(当前登录系统的用户数)和系统用户数(可能访问系统的总用户数)。

  • 淘宝虽然使用用户数可达几亿,但是淘宝双十一最高峰的某个瞬间并发用户数大概也就是百万级别的。

  • 我们的系统性能,消耗系统资源的是并发用户,只有它发送请求,我们正在处理的时候,它才会消耗我们的计算资源,给我们系统带来负载压力,需要我们用分布式系统的集群等各种技术手段来处理这个并发请求

吞吐量

  • 单位时间内系统处理的请求的数量,体现了系统的处理能力。对于网站,可以用“请求数/秒”或是“页面数/秒”来衡量,也可以用“访问人数/天”或是“处理的业务数/小时”等来衡量。

  • TPS(每秒事务数)也是吞吐量的一个指标,此外还有HPS(每秒HTTP请求数), QPS(每秒查询数)等。

吞吐量和并发数的关系

  • 并发数是正在处理的,吞吐量TPS是单位时间的,如果说响应时间是1秒钟,发送请求1秒处理完了,吞吐量和并发数就相等,如果响应时间是500ms,那么吞吐量就是并发数的两倍了

  • 吞吐量 = ( 1000 / 响应时间ms ) × 并发数

性能计数器

  • 是描述服务器或操作系统性能的一些数据指标。包括 System Load、对象与线程数、内存使用、CPU 使用、磁盘与网络 I/O 等指标。这些指标也是系统监控的重要参数,描述系统当前的性能状况,当这些指标比较高的时候,可能系统资源占用比较多,系统性能可能就出了问题,所以通常监控的时候,会对这些指标设置报警阀值,当监控系统发现性能计数器超过阀值的时候,就向运维和开发人员报警,及时发现处理系统异常(如系统负载太高,压力太大,用户请求多,系统出现故障等异常),降低系统可用的的损失或问题。



二、性能测试方法

性能测试方法

  • 通过性能测试去获取性能指标,从而对系统的性能有个整体的认知,客观上量化系统的性能

  • 性能测试是一个总称,具体可细分为性能测试、负载测试、压力测试、稳定性测试。

性能测试

  • 以系统设计初期规划的性能指标为预期目标,对系统不断施加压力,验证系统在资源可接受范围内,是否能达到性能预期。

负载测试

  • 对系统不断地增加并发请求以增加系统压力,直到系统的某项或多项性能指标达到安全临界值,如某种资源已经呈饱和状态,这时候继续对系统施加压力,系统的处理能力不但不能提高,反而会下降。

压力测试

  • 超过安全负载的情况下,对系统继续施加压力,直到系统崩溃或不能再处理任何请求,以此获得系统最大压力承受能力

稳定性测试

  • 被测试系统在特定硬件、软件、网络环境条件下,给系统加载一定业务压力,使系统运行一段较长时间,以此检测系统是否稳定。在生产环境,请求压力是不均匀的,呈波浪特性,因此为了更好地模拟生产环境,稳定性测试也应不均匀地对系统施加压力

性能测试方法和效果展示



  • 上图展示了随着并发数的增加,系统响应时间和吞吐量TPS的变化趋势,体现了系统资源的消耗从增加到耗尽的过程。

  • 一开始随着并发数的增加TPS近似线性的增加,过了b点以后,TPS的增加开始变缓了,到了c点TPS达到最大值,然后进一步增加并发请求数,TPS反而下降了,只至d点系统失去响应,TPS突降为0。

  • 一开始没有并发请求的时候,服务器资源时空闲的,TPS为0,随着并发的增加,服务器会创建线程来处理每个方法请求,每个线程可以获得CPU调度,且有足够的内存空间供它使用,访问磁盘访问网络资源都是够用的,所以TPS快速的被处理完了,并发数增加资源还都是够用的,TPS也在快速增加;但是过了某个点b,资源可能就不足了,就会存在处理线程等待资源的情况,等待的线程没有得到处理,响应时间就会变长,TPS增加的速度就慢了,但是它还是在增加;到了某个点c,某些系统资源已经消耗到了极限了,并发数再增加,处理能力反而会下降,比如内存耗尽,需要使用硬盘虚拟内存,CPU会消耗在虚拟内存置换,唤醒线程的反复切换过程中,处理能力会大幅下降,TPS也对应减少;到了最后d点,到了最后CPU什么也处理不了了,一堆线程都在等待资源,资源被耗尽了,所有的请求都失去了响应,系统看起来就崩溃了。

  • 分布式系统集群就是希望通过增加服务器,把每个服务器上的资源消耗降低,从而提升性能

  • 在线上运行中,系统服务器是应该运行在哪个点之间呢(ab、bc、cd),假设部署服务器,10台运行状态为a到b点,7台运行状态为b到c点,5台服务器是c到d点,那么应该部署几台服务器呢?需要找到成本和收益的平衡点,越少用服务器,系统的风险就越高。是花更多的成本获得更多的系统安全边界呢?还是用更低的成本,为公司节约资源呢?是需要架构师考量的。放在哪里都有道理,但是需要我们清晰知道我们为什么要这么多服务器,做决策的依据是什么。

分析性能测试结果

  • 系统中每个点系统资源消耗情况,哪个资源先被耗尽(硬盘,内存,CPU等),通过一些指标值,看出当前系统资源的一些瓶颈,并根据资源消耗的情况及合理性作出一些分析和判断,进一步的去优化系统(如垂直伸缩提升硬件,使用更好的中间件,优化系统代码,用缓存节省计算资源等各种优化策略)



基于Flower的应用重构性能测试

  • 重构后,TPS增加了一倍多,响应时间也快了很多,使用Flower对应用系统重构,带来的性能优势还是非常明显的

性能测试压测可用性

  • 可以通过性能测试压测服务间的级联影响

  • 采用同步网关时,服务1涉及数据库慢查询服务阻塞时,同步网关线程耗尽,也会被阻塞,无法接收和处理其他请求,会导致其他级联服务的失败

  • 采用Flower异步网关重构后,服务1涉及数据库慢查询服务阻塞时,异步网关不会阻塞当前线程,还可以继续接收和处理其他请求,其他服务不受影响可以继续正常服务,系统有了更好的性能优势

  • 性能测试是性能优化的前提和基础,通过性能测试去分析问题,发现问题,同时通过性能测试去检查优化的效果是否达到预期目标

三、性能优化:系统性能优化的分层思想

我们在获得了性能测试结果以后,性能测试结果是让我们去了解我们系统的性能状况,了解状况的目的主要还是为了进行性能优化,如果发现这些性能指标不合理,没有达到期望,就必须要进行性能优化,这些主要看如何对系统进行性能优化



当我们说性能优化的时候,我们通常不能泛泛的说如何如何的优化,所以我们通常是有针对性的或者有目的性的,这一节我们主要去讲性能优化的一些思想方法和思路



软件性能优化的两个基本原则

  • 你不能优化一个没有进行过性能测试的软件

  • 你要对一个软件进行性能优化,你不能上来就说我要进行优化,你必须要先让它进行性能测试,了解它的性能指标是什么样子的,响应时间,吞吐量,并发数,各种性能计数器,内存CPU各种资源消耗是什么样子的,然后发现它有性能瓶颈,有性能问题,性能不符合期望,然后你才能对它进行优化

  • 性能测试是性能优化的一个前提,是它的基础,也是它优化完了的一个验证

  • 你不能优化一个你不了解的软件

  • 如果你对一个软件不太了解,这个软件是做什么的,整体架构什么样子的,内部的一些关键细节是如何实现的,仅仅凭借着一些了解的知识或技术,就要用这些技术去优化你的软件,这样不是不可以,但是从事情的基本规律出发,还是建议了解软件,了解系统的架构,了解系统的关键设计,然后知道问题在哪里,然后有的放矢的进行优化



性能测试的主要指标

  • 响应时间:完成一次任务花费的时间 

  • 并发数:同时处理的任务数 

  • 吞吐量:单位时间完成的任务数 

  • 性能计数器:System Load,线程数,进程数,CPU、内存、磁盘、网络使用率



Spark应用性能测试

  • 通过工具可视化的获得Spark的各项性能指标,通过对这些性能指标的分析,我们去发现性能问题,进而对它进行优化。

  • 学会通过可视化的性能曲线、性能图形进行性能分析

  • 最核心的指标依然是CPU的使用率、内存的使用率、网络的吞吐量、磁盘的吞吐量,以及Spark运行器自身的作业调度运行状况

  • 在Spark运行器的作业调度运行状况图中,粗的实线表示Spark的一个job,细的实线表示Spark的一个stage,红色的看起来一块一块的实际上它是一条线一条线组成的,每一条线都是一个Spark的task一个任务,多个任务看起来就变成一坨了一组了,这里面有几十个上百个task在执行,当它执行完一个stage结束进入下一个stage,有的task执行时间比较长,就拖得比较长,整个最后一个task执行完了,才会进入下一个stage。同样这些stage和job的隔离,也会在资源的利用的图上也会绘制出来,然后我们去分析在不同的作业的运行阶段,它的资源使用情况是什么样子的,这些资源为什么会是这样一个利用情况,是不是有一些性能问题呢,以此来进行分析,发现性能问题,然后继续优化。











性能优化的一般方法(接收任务后的上手方法)

  • 性能测试,获得性能指标

  • 指标分析,发现性能与资源瓶颈点或问题点(数据指标不正常,与预期不符)

  • 架构与代码分析,寻找性能与资源瓶颈关键所在(什么原因导致数据指标不正常,如架构设计问题,代码里不恰当的锁等问题)

  • 架构与代码优化,优化关键技术点,平衡资源利用(针对分析找到的问题进行优化,如对架构进行重构,使用缓存,使用消息队列异步的写入,在代码中进行并发的代码执行,异步的数据处理,硬件上使用其他的硬件,对操作系统,对某个中间件,对数据库连接池进行优化,中间件版本不符合性能要求,或中间件已经落伍了需要进行升级等,然后得到一个优化后的结果)

  • 性能测试,进入性能优化闭环(针对优化后的结果,再进行性能测试,看性能指标是不是变得更好了,是不是达到了性能优化的目标。如响应时间变快了,吞吐量变高了,资源节约出来了等性能优化的结果)

  • 你觉得这样的优化已经达到了目标,就可以把优化前优化后提升的百分比几倍,作为一个成绩向老板汇报,向其他人展示,如果还没有达到期望,还可以进行进一步的优化,同样的再回到前面拿着新的指标再进行分析,寻找新的瓶颈点,或性能问题的关键点,对这些瓶颈点和关键点进一步进行优化,优化完了以后再进行测试,看是不是又提升了,这样不断的迭代下去,直到你觉得优化可以结束了,然后拿到一个最终的结果,然后去向老板汇报,向其他人展示,作为一个成绩的交付

性能优化是一个架构师的基本能力,因为你做了很多的设计,画了很漂亮的架构图,最后功能也做出来了,但是很慢就没法用,特别是互联网应用,大部分互联网应用无法忍受慢的,架构师要完成交付的系统,一定要对性能有一些基本功,基本能够解决性能问题。我们学习软件开发很多时候都是跟性能相关的,操作系统、数据库、网络,都是讲如何高性能的去开发我们的软件,那么真正优化的时候,就要用到这些知识,怎么把这些知识系统有方法的整个的去组织起来,有条理的进行性能优化,这里给出了一个基本的一般方法,可以借鉴。



系统性能优化的分层思想

  • 如果要是通过性能测试,发现了问题,怎么解决这些问题,如果发现处理速度就是慢怎么去优化,进行优化的时候手段、方法、思路又有哪些呢?大多数直观的思路是通过代码进行优化,因为东西都是代码写的,但实际上,代码是整个系统的一个部分,整个系统是由非常多因素组成的,那么每一个元素每一个组成部分都有可能对系统的性能产生影响,所以优化的时候,主要还是看代码,但是其他的一些方面也不能忽视。

  • 机房与骨干网络性能优化(最上层)

  • 异地多活的多机房架构,多个地方多个城市部署多个数据中心(异地),都活跃着对外提供服务(多活),用户访问时就近的连接到某个数据中心机房里面去,目的是为了解决高可用问题,如果只有一个机房,机房发生了火灾的事件,整个公司系统就完蛋了,如果多个机房都能够对外提供服务,那么系统在多个机房同时部署,数据通过数据复制的方式在多个机房都存在,这样的话,用户才能够连接到任何一个机房,任何一个机房出现极端情况,机房的服务器都丢掉了,但是不会影响整个系统的正常运行,也不会影响公司的命运。异地多活主要是为了解决高可用问题,但事实上也解决了一些性能问题,最典型的物理距离的网络传输时间,可以通过多机房去解决,使用户就近的访问离他最近的机房,特别是一些全球级的互联网应用,比如中美之间的海底光纤,跨太平洋的海底网络通信,光纤通信,以光的速度进行通信,一来一去300ms,300ms已经是一个用户请求能够感知到的一个时间长度了响应延迟了,所以如果全球只有一个机房,要对全球用户提供服务,在地球另一端的用户,就能够明显的感觉到响应时间的延迟,多机房架构可以提供更快速的,给用户尽快提供的一个服务,也能够提供更好的性能服务

  • 专线网络和自主CDN建设,淘宝的全链路压测就是利用自己建在全国各地的CDN服务器发起的,这些CDN自主可控,它就可以更进一步的在这些CDN服务器上进行专项的一些优化,这些CDN是部署在全国各地的,像这样的资源投入也可能对性能带来较大的提升

  • 关于代码的性能优化代码的执行时间通常是微妙甚至是纳秒级的,你再优化,对于一个像跨太平洋这样一个300ms的网络延迟,都很难优化出来,它不在一个数量级上,如果真正的是异地的网络通讯方面的延迟或者是缓冲服务方面的延迟,通过在最高层面上的机房或网络CDN这个层面上的优化,可以带来极大的性能提升

  • 服务器与硬件性能优化

  • 使用更优的 CPU,磁盘,内存,网卡,对软件的性能优化可能是数量级的,有时候远远超过代码和架构的性能优化。

  • 比传统的机械式的硬盘和固态硬盘它们之间的性能可能就是一个数量级的性能差距,对一些对性能比较敏感,数据量也不是特别大的一些数据访问,通过使用SSD硬盘,加快数据的读写操作,可能对系统的性能产生一个数量级的优化

  • 硬件优化案例

  • Spark 作业过程需要传输大量数据,进行资源瓶颈分析,发现大量时间消耗在网络传输上。

  • 在Spark的运行过程中,它需要传输大量的数据,因为Spark是要进行大数据计算的,在不同的stage之间,数据要进行shuffle,因为跨服务器的传输的时候,服务器之间要进行网络通信,看一下网络通信的性能曲线,红色的曲线表示的是网卡接收的数据量,蓝色的是网卡发送出去的数据量,大部分时候红色和蓝色都是比较重叠的,因为它在发数据的时候同时也要接收数据,作业时间是花了230多秒钟的时间完成了这个作业,在某些情况下,数据的读写或发送和接收,它达到了整个网卡的最高端,整个网卡的极限瓶颈就是120多兆这样一个极限,当要读写的数据请求,超过了网卡能传输的极限,它就只能在这个极限上进行数据传输了,这里面都是跑平了的,在最高峰进行数据读写,但是不管你有多少数据,或性能怎么样子的,你再怎么优化,数据都是要通过这么长的时间,才能够传输过去,我们看到最长的读写这段,175到220秒将近50多秒的时间,在进行数据的读写操作,这显然对性能会造成巨大的影响,整个作业将近1/5的时间都是在通过网络对数据进行读和写,那么网络读写的性能瓶颈,就成为整个作业运行过程中的一个重要的瓶颈,我们需要对网络传输进行性能优化。

  • 如何进行性能优化呢?我们可以减少传输量,如何减少传输量呢?可以进行数据压缩,但是数据压缩了以后,传输量可能是变少了,但是数据压缩和解压缩,它需要消耗大量的CPU时间,实际上整个Spark的作业周期内对CPU的利用率也极高,也许通过压缩以后,网络通信时间变少了,但CPU的执行时间又变长了,最后此消彼长,整个的作业时间还是差不多,性能并没有什么改善,那么还有其他的办法吗?我们可以通过硬件来进行性能优化,当前是1G的网卡,跑最多只能传送125兆的数据,为什么1G网卡是125兆的最大传输数据呢?因为1G网卡是按照比特位进行传输的,而网卡的操作系统的监控是按照byte(8个比特1个字节)作为统计指标的,所以这里操作系统统计出来是125兆byte,1G比特位进行传输的。我们要做性能优化,可以用10G网卡代替1G网卡,直接进行硬件的升级。

  • 优化方案:升级网卡,10G 网卡代替1G 网卡

  • 换了10G网卡以后,最快的情况下它有900多兆,实际上整个网络的读写,它几乎没有触达它的最高点,或者一触及到最高点立即就降下来了,网路阐述速度提高了10倍,900兆实际上是性能绘制曲线这个软件绘制出来的最大值,也是整个的请求响应时候,或者发送接收过程中的最大值,事实上这张网卡的最大值是1.25G,整整扩大了10倍,整个网络通信的过程中,我们可以看到连它的最大值都没有达到,就立刻传输完了。以前我们需要50多秒的时间,到了这里只需要十几秒的时间就传完了,整个的作业时间,由原来的230多秒到了这里的150多秒就结束了,整个的作业时间缩短了,整个的处理性能提高了40%,仅仅是换了一张网卡,就达到了这样一个显著的性能提升

  • 操作系统性能优化

  • Spark在运行期,CPU的资源利用率情况,红色的区域为用户态,我们的作业使用的CPU时间,紫色部分为操作系统使用CPU的占比,绿色部分为空闲的,在某些时候紫色的色块比红色的色块多很多,实际上是没有道理的,CPU在进行密集的Spark的作业执行,CPU应该大量地处于Spark的作业任务执行,为什么有大量的时间去执行操作系统自身的一些指令呢?这些指令到底在做什么呢?这里就是问题,是程序的问题呢,还是操作系统自身的问题?

  • 资源利用分析,发现大量CPU操作为sys类型,消耗大量计算资源

  • 调查原因,发现是Linux在某些版本的时候缺省打开了transparent huge page,就会导致sys部分CPU使用占比就会急剧的升高

  • 优化方案,关闭transparent huge page

  • 蓝色部分也就是操作系统占用的比重急剧下降,整个的作业时间从210多秒优化到150秒,依然是提升了30%左右

  • 我们不需要修改代码,优化架构,我们只需要去寻找到操作系统本身存在的一些问题

  • 虚拟机性能优化

  • 以Java虚拟机为例,不同的垃圾回收的算法(回收线程运行期的情况),造成了对性能的影响。

  • 基础组件性能优化(Tomcat,数据库连接池等)

  • 不同的基础组件不同的版本,它们的性能差别也很大。例子中,同样的代码系统的部署,同样的性能测试20个并发测试,去测试不同的部署方式

  • 我们发现不用修改代码,不用修改架构,不用修改操作系统,不用修改硬件,什么都不用改,但是中间件jboss、jetty还有DBCP的不同版本,通过修改中间件,基础组件,通过基础组件版本升级或使用更优的基础组件,进行调优,也会带来数倍的性能优化和提升,核心就是用jetty代替jboss,这样一个基础组件的升级,进行性能优化,也产生了巨大的性能优化收益。最终的收益性能大幅提升,因为性能提升了,所以大量的服务器用不着了,现在更少的服务器就可以支撑更高的并发,所以下线了1/3的服务器,全年不需要再采购新机器,给公司节约了几百万上千万的成本,同时还带来了一些其他方面的优势,更加安全,更加容易开发和维护,配置也更加简单,架构也更加的轻量,带来了各种各样的好处

  • 软件架构性能优化

  • 在基础组件之下,才是我们软件系统自身的性能架构优化。我们前面讨论了各种分布式技术,这些分布式技术主要解决的就是,在高并发的情况下,如何提供更高的性能特性,支撑更高的并发,实际上也是关于性能优化的,如缓冲、异步、负载均衡、NoSQL、分布式数据库,搜索引擎,都是关于性能优化的,在架构级的性能优化。

  • 核心的关于架构的性能优化,总结了三板斧:缓存、异步和集群

  • 缓存:优化读的性能,应用程序从缓存读取数据比从数据库读取数据,性能要高几个数量级

  • 从内存获取数据,减少响应时间

  • 减少数据库访问,降低存储设备负载压力

  • 缓存结果对象,而不是原始数据,减少 CPU 计算

  • 缓存主要优化读操作

  • 异步:优化写的性能,通过异步的方式,通过消息队列进行异步操作,请求先写入到消息队列服务器,消息队列服务器快速的进行响应,消息队列异步的将消息写入到数据库,或同步到其他系统里面,以此来提升系统的性能,除了提升系统的响应性能,还有削峰填谷的作用,降低系统的负载压力,使它在高并发的情况下,不会直接被压垮,请求操作缓存在消息队列中,慢慢的进行处理

  • 即时响应,更好的用户体验

  • 控制消费速度,合适的负载压力

  • 异步主要优化写操作



  • 集群:用更多的服务器,提供更多的处理能力,负载均衡是集群,分布式缓存也是集群,分布式消息队列,分布式数据库,NoSQL它们其实都是提供更多的服务器,构建一个集群,然后对外提供服务,以此来提升自己的处理能力,进而提升性能

  • 古老谚语:如果一匹马拉不动车,无需换一匹更强的马,而是用两匹马拉车。

  • 互联网技术的发展路径就是:更多的用户访问需要消耗更多的计算资源,单一服务器计算资源的增加是有极限的,所以需要增加更多的服务器。关键是如何利用起来这些服务器。

  • 集群的技术目标只有一个:如何使很多台服务器对使用者而言看起像一台服务器。

  • 软件代码性能优化(最下层)

  • 关于代码的性能优化,并不是并发、多线程、异步这些东西是能够优化性能的,清晰的易于阅读和维护的代码,对性能的优化是最重要的,也就是说,遵循面向对象的设计原则和设计模式进行编程,很多时候程序的性能不好,不是因为性能上有什么技术挑战,仅仅就是因为代码太烂了,没必要的逻辑,没必要的业务,没必要的调用在那里反反复复,想要对它进行优化也无处下手,这样的一些高耦合的,边界不清晰的,互相耦合,互相调用,互相依赖的代码,一堆不清晰的代码放在那里,也不知道有什么用,也不敢删,也不敢改,乱糟糟的一套代码,有问题也不敢改,也无法优化,通常这些代码还是最容易产生性能问题的。所以按照设计原则和设计模式,编写清晰的易于复用的易于扩展易于维护的代码,不管是本身开发过程,维护,需求变更,还是进行性能优化的时候都很有用的。

  • 除此之外并发编程,使用多线程的时候,就要关注锁了。还有资源复用,线程池,对象池。重复的使用数据库连接、线程这些资源,它们本身建立起来就比较耗资源,重复使用,通过资源复用的方式,池化的方式进行访问。还有就是异步编程,生产者消费者这样的方式。还有就是关于数据结构,使用合适的数据结构,比如哈希表,它的访问时间速度就是O(1)的,链表的访问速度就慢一点了,但是不同的场景下使用不同的数据结构,针对性的对代码进行优化

  • 并发编程,多线程与锁

  • 资源复用,线程池与对象池

  • 异步编程,生产者消费者

  • 数据结构,数组、链表、hash表、树



代码优化案例:Spark 任务文件初始化调优

  • 资源分析,发现第一个 stage 时间特别长,耗时长达14s,CPU 和网络通信都有一定开销, 不符合应用代码逻辑。

  • 去分析代码,为什么执行了14秒,发现代码什么也没做,既没有网络传输,也没有复杂计算,它只是初始化了一个空值数组,用空值数组进行下一步的迭代计算,初始化空值数据为什么花了14秒的时间?我们看下整个分析问题的过程:

  • 打开 Spark 作业 log,分析这段时间的 Spark 运行状况。

  • 根据 log 分析结果,阅读 Spark 相关源码。

  • 发现 Spark 在任务初始化加载应用代码的时候,每个Executor(执行器,Spark执行任务的进程)都加载一次应用代码(把可执行的代码加载到Executor上面去执行业务逻辑,每个Executor都要加载一次这个代码包), 当时每台服务器最多可启动48个 Executor,每个应用代码包17M大小,每个服务器就要去下载48*17M这么大的数据量,整个集群有4台服务器,再乘以4,它们都要通过一台Driver服务器去加载,就会导致Driver服务器的网络通讯称为瓶颈(要把4*48*17这么大的数据包分发出去,网络称成为瓶颈),导致加载开销巨大。

  • 并不是我们作业的应用程序代码性能有问题,初始化数据没有问题,而是Spark自己的代码有问题,它的问题是什么呢,它就不应该每一台服务器分别去加载这样大的一个文件,重复加载造成了网络瓶颈。也就是说Spark的源代码,在这里面它的性能是有优化空间的,怎么优化?

  • 优化方案:Executor 加载应用程序包启用本地文件缓存模式。[SPARK-2713](每个Executor去加载的时候,看看本地文件中有没有缓存的应用代码包,如果有缓存,使用本地文件就可以了,如果没有的话,才远程加载,这样的话48个Executor,只有一个去加载,其他的47个Executor通过第一个加载过的包,然后从本地去读取就可以了,这样每个服务器加载1次就可以了。具体的优化提交到了Spark源代码里)

  • 优化效果:Stage1运行时间从14s下降到不到1s。



发布于: 2020 年 11 月 07 日阅读数: 50
用户头像

piercebn

关注

还未添加个人签名 2019.07.24 加入

还未添加个人简介

评论

发布
暂无评论
架构师训练营 1 期第 7 周:性能优化(一)- 总结