全国服务热线:18888889999
在线报名
欧陆注册CURRICULUM
欧陆资讯 NEWS CENTER
联系我们 CONTACT US
手机:
18888889999
电话:
0898-66889888
邮箱:
admin@youweb.com
地址:
海南省海口市玉沙路58号
欧陆资讯
你的位置: 首页 > 欧陆资讯
性能优化篇-理论基础
2024-04-22 14:17:45 点击量:

业务功能向用户提供各种基本操作,比如查看商品、下单支付是电商平台的业务功能,评论点赞是社区平台的业务功能。而服务性能则反映了系统的使用体验,假如A电商平台打开一个商品详情页的时间是毫秒级,B电商平台打开一个商品详情页的时间是秒级别的,它们带给用户的体验肯定是不同的。

从服务诞生的那天开始,性能优化就伴随着其整个生命周期。服务的性能在随着用户量的增加,用户访问时长的增加,网站的业务功能增加的时候,都在面临中不同程度的挑战,因此,性能优化是伴随着服务发展的整个生命周期。

体现一个服务性能的指标通常有:TPS、RT、并发数、错误率

TPS:系统每秒处理交易数,单位是笔/秒。系统处理能力通过系统每秒钟能够处理的交易数量来评价。

RT:Response Time。响应时间是指用户从客户端发起一个请求开始,到客户端接收到从服务器端返回的响应结束,整个过程所耗费的时间,单位一般为秒或毫秒。完成一项任务所需要的时间可以分成两部分:执行时间和等待时间

并发用户:并发用户数指在同一时刻内,登录系统并进行业务操作的用户数量。对于长连接系统来说最大并发用户数即是系统的并发接入能力。

错误率:错误率指系统在负载情况下,失败交易的概率。错误率=(失败交易数/交易总数)*100%。稳定性较好的系统,其错误率应该由超时引起,即为超时率

做性能问题分析之前,应该通过线上的监控、服务的日志、压测都手段找到影响服务性能的瓶颈点,而不是盲目的分析,如果服务本身代码写的比较差导致性能不佳,但是你却花大量时间去优化数据库,可能结果并不如意。

一个大型网站的系统是比较复杂,而性能问题又是一个较为难排查和优化的事情,因此我们必须采用分而治之的思想,将复杂的问题简单化,然后各个击破,才不至于像无头的苍蝇,到处乱撞。

大型网站系统一般都采用分层思想,所以我们可以先在系统的水平分层上逐个分析和优化。典型分布式微服务系统如下图所示,包括了接入层(Nginx、API网关),API服务层(负责处理客户端请求和拼接响应并发送给客户端),RPC服务层(负责业务逻辑的处理和最大限度的复用),缓存服务层,数据库服务层,有的系统在大量写库时还会使用消息队列来异步写库(比如聊天消息)。因此,在实际业务中进行性能优化时,我们可以从上至下进行分析和优化,也可以从下至上进行分析和优化,同时也可以根据自己对系统的掌握熟悉度,从宏观上判断哪个层最可能出现性能问题就优先分析和优化哪一层。一般来说接入层(Nginx和API 网关)的性能都很高,因此可以放在最后去分析。

除了水平分层外,大型网站还会将系统进行垂直分割,如下图所示,一个电商网站会将系统切分为用户服务,商品服务、订单支付服务等,因此,在性能优化的时候,可以查看系统是用户服务出现了性能问题,还是订单支付服务出现了性能问题,最后针对单服务进行性能问题分析。

通过水平和垂直的分层分割思想,我们可以把复杂的性能分析问题简单化,其实这是解决任何问题的思想,否则我们将无从下手。如果你所在的业务没有做水平分层或者垂直分割,那也没关系,采用这种思想就好了,比如你可以先进行数据库分析和优化,再进行缓存分析和优化,再对应用层代码进行分析和优化。

假设我们现在有一条单车道,道路长度是10km,车速是50km/h,如下图所示,那么1h时间,从A点出发,达到B点的车辆,最多只有5辆车,假设现在出现了堵车问题,我们应该如何解决呢?

第一种解决思路是将车道拓宽,比如现在只有1个车道,那么我们就拓宽为4车道,这样,1h时间,从A点出发,达到B点的车辆,最多可以达到5x4,从原来的5辆车提升到了20辆车,大大缓解了堵车问题。

第二种解决思路是将慢车道变成快车道,我们将原来的普通公路变成高速公路,于是车速提升到了原来的2倍,变成了100km/h,那么1h时间,从A点出发,达到B点的车辆就从原来的5辆车提升到了10辆车,也能缓解堵车问题。

提升服务的并发能力就好比将车道拓宽,可以整体提升服务性能

1)采用多核CPU。多核CPU在一个处理器芯片上集成了多个处理核心,应用能够充分利用多个处理核心并行执行多个任务。

2)集群部署。集群部署可以将系统由一个节点提供服务扩展为多个节点同时提供服务,并通过负载均衡策略,将客户端的请求分摊到不同的节点进行处理,因此也可以提升服务的性能。

3)多活部署。与集群部署类似的是多活部署,集群部署是将服务部署在同一个机房内,但是一个机房的带宽存在限制,因此大型网站系统还通过多活来提升服务性能,即在多个机房部署相同的服务,并在域名解析时根据用户的源ip地址,将不同的用户分配到不同的机房。

4)分布式服务。分布式服务是将系统进行垂直分割,比如文章前面提到的将电商系统分割为用户服务、商品服务、订单支付服务等,然后这些服务部署在不同的机器上,也相当于是对请求的流量进行了分摊,提升了对外提供服务的能力。

5)多线程。多线程可以最大限度的利用CPU,提升单个服务的并发能力,详细的可以查看《Java基础篇-多线程》文章中提到的多线程的意义。

6)锁优化。由于锁会让多线程并行执行编程串行执行,而且锁的竞争也存在性能开销等,因此如果服务内部不得不使用锁,需要对锁进行优化,最大限度的提升单服务的并发能力,锁的优化可以查看文章《Java基础篇-并发编程之锁的优化》。

完成一项任务所需要的时间包括执行时间和等待时间,如下图所示,如果一个服务每秒钟处理的请求数是10,那么如果在1秒内同时到达的请求有11个,则有1个请求必须先等待前面10个处理完毕后才能被处理,因此这1个请求的响应时间是1秒+11秒=2秒。因此降低请求时延也是从这两方面入手。

1)提升硬件性能。采用主频更高的CPU可以在单位时间内执行更多的指令,使用更好的存储介质可以降低CPU和存储之间的读写时间,因此提升硬件性能可以大大缩短请求的执行时间

2)使用缓存。由于网络传输大数据时比较耗时,因此使用CDN将图片、视频等数据量比较大的静态资源缓存在距离用户最近的地方,减少网络传输带来的时间延迟。CPU从数据库读取数据需要进行磁盘操作和网络传输,因此使用本地缓存和分布式缓存减少CPU的等待时间。因此使用缓存可以大大降低请求响应的等待时间

3)异步处理。在某些场景下,未处理完成之前我们可以让请求先返回,在数据准备好之后再通知请求方,这样可以在单位时间内处理更多的请求。比如像即时聊天业务场景,A用户给B用户发送一天聊天消息,服务断收到A的请求后,可以先把消息暂存起来,然后个A用户发送操作成功的响应,然后再使用异步线程将消息发送给B用户。使用异步处理方式,可以缩短请求响应的执行时间

4)减少网络传输数据包。由于网络传输受限与带宽和网络拥塞等,因此网络传输视频、图片、大文件等大数据量的时候都有可能加大请求响应的等待时间。因此,我们可以使用各种压缩技术,分段传输技术等减少网络传输的数据包,从而降低请求响应的等待时间。比如图片传输可以使用webp格式,视频的分段和压缩传输等等。请求响应的序列化方式,使用字节长度更小的序列化方式,如protostuff。

5)使用池化技术。使用池化技术可以在需要时就直接拿来使用,减少了对象创建的时间开销,从而降低了请求的执行时间。比如数据库连接池、redis连接池、线程池、单例模式等。

6)使用合适的数据结构。在不同的业务场景下,使用不同的数据结构能够降低请求的执行时间,比如读多写少的情况下使用数组,而写多读少的情况下使用链表,经常查找数据的情况下使用HashMap数据结构,经常变更又需要排序的情况下使用二叉树数据结构。

以上只是列举的一些通用思路,针对不同的语言和服务也有不同的优化措施,比如Java语言可以对JVM参数调优,顺序写磁盘会比随机写磁盘更快,单线程的redis尽量减少时间复杂度高的集合操作,使用NIO可以减少读写等待时间,使用零拷贝技术可以减少无意义的拷贝时间。

性能优化是一个复杂的问题,在不同阶段服务的性能瓶颈点也不一样,比如初期可能是数据库成为系统瓶颈,那么通过索引优化、读写分离和增加缓存等措施就解决了,而随着网站访问量越来越大,可能这个时候机房的网络带宽成为了瓶颈点,这个时候不论你怎么优化数据库,服务集群部署等都可能解决不了问题,此时可能就需要做多机房建设了,将流量分摊到多个机房。

性能问题一般比较难分析和定位,因此可以采用分而治之,各个击破的方法,将复杂的问题简单化,然后逐个分析和优化。

性能优化的措施有很多,但是核心思路就两点,提升并发处理能力和降低请求响应时间,因此在你的实际工作中,如果出现性能问题,你可以可以尝试从这两方面入手进行问题分析和性能调优。

性能优化也遵循“二八原则”,一个系统的性能问题,可能主要是由于某几个主要的瓶颈点导致的,抓住主要矛盾,因此你可以先花时间去解决这些性能问题,做到用 20% 的精力解决 80% 的性能问题。

最后不能为了性能优化而优化,做每一件事情都是有成本的,因此需要结合当前的业务情况,各项性能指标,未来一段时间内预估的增长量等判断当前阶段是否需要做性能优化,如果当前业务根本不需要做性能优化,而投入大量时间和人力去做性能优化是收益极低的,那么更应该把时间和人力投入在做用户增长上