随着互联网时代的发展,用户量自增迅猛,应用程序性能要求日益增大。如果一个页面用户打开需要超过3秒,大部分用户等待的意愿减少,等待的时间越长,减少的用户量也会越多。所以我们应用程序的性能、调优变得越来越重要。这里介绍应用程序性能调优相关方案。
调优从宏观的思维来看,分为网络、应用程序、数据库。这篇文章不会介绍应用程序代码上的调优,因代码及其使用框架上有很大的区别。
性能优化的想法
在介绍具体操作性能优化前,需要给大家理清一下思路。性能优化是很大很复杂的东西,如果要做到极致,没有一个专业化的团队是根本不可能的,在绝大部分公司来说是很难有经费去支撑这一个团队。而且性能优化的人懂得的东西不仅要全面,而且又要有深度,这些人大部分都是一些民间高手。
我们首先理清性能优化的目标,目标是优化到什么程度。如做一些活动,用户量最高峰大约在10w的并发访问,那么性能优化一般都需要做到比2-3倍的用户量优化。比如并发访问达到20w-30w之间,这样系统性能才会有保障。
然后根据实际情况,来确定性能优化怎么做。因为有些系统单机的性能瓶颈就在那里,再怎么优化都是浪费时间。第一种是整个系统重构广度的优化,如你的系统吞吐量是1000/S,如果要达到10W/S,那么可能再深入性能优化就浪费时间,因为你的单机系统最高吞吐量是1W/S,如果要增加10倍,只能改造程序,分布式处理。再来第二种是深度的优化,如果你的系统吞吐量是100/S,要提升到300/S,那么通常是可以的,通过网络、数据库、前后端、系统思路去优化即可。
这篇文章更多讲的是深度的优化,广度的优化网络上很多,分布式、微服务等。
确定好优化怎么做后,我们需要短板木桶原理,优化导致性能最慢的。即把最短的木板优化、加长,再找最短的再优化加长。
总的一点来说,性能优化的想法的流程是:理清优化的目标->确定怎么做->短木板原理优化最慢的。
网络
网络的性能优化可以分为多方面,可分为应用程序外网、应用程序内网。如图:
程序外网
程序外网可通过PC、手机等不同的客户终端发起访问,经过外部网络最终落入到程序内部。如上图的灰色区域以外的部分表示外网,灰色区域表示内部局域网,下面分别列出外网带宽需要考虑的点。
1)外网首先要考虑的是带宽,带宽越大才能经过更多的数据包、更多的数据量。这里要注意带宽的单位:Mbps、MB/S。Mbps*8=MB/S,即1MB/S=8Mbps。
2)DNS。在前后端分离的应用程序中,前端发起请求填写相关的域名即可。我们也知道,域名要通过DNS解析找到相应的IP才能把数据包发送到相应的服务器,因为在TCP/IP协议传输过程中,网络层需要IP地址。那么DNS就为我们提供了IP与域名的映射关系,通过域名找到相应的IP地址。
在程序发起请求解析映射的过程中,优先级是这样的:程序(浏览器、服务器等)找到内部域名与IP的映射或代理 -> 本机Host文件 -> 局域网DNS服务器 -> 英特网DNS服务器,如下图。
所以在DNS优化上面,可在局域网中建立DNS,用来映射IP与域名。
3)尽量减少数据包大小。在网络传输中,免不了发送数据包。减少数据包的大小可增加网络传输效率。
4)允许的话,可使用HTTP2.0,并且不要使用HTTP1.0。HTTP2.0带来的极致的性能优化,HTTP经过1.0->1.1的发展。HTTP1.1比1.0加了长连接与keepalive方式,连接过程中无需每次都中断。而HTTP2.0加了多路复用,让所有数据流可公用同一个连接,大大提升连接效率,很适合目前大用户量的程序。鉴于目前客户端、浏览器支持不足,大部分在默认是使用HTTP1.1,或者更旧的1.0。
程序内网
一般在服务化程序中,或者一些中间件都会使用到内网程序的访问。内网的带宽一般无问题,至少可达GB级别。在Linux环境中,发起网络请求有文件读取数量,也有maxconn的限制,加相应的配置即可。
应用程序
现今的应用程序一般都是前后端分离,这里的性能优化包括前端应用程序及后端应用程序。应用程序优化有很多方面,有很多是代码死循环或底层了解不透彻引起的,也有是其它方面。
前端应用程序
首先前端的性能优化代码上不做讨论。代码上有很多的优化地方,如渲染页面的优化。前端除了代码上的优化,还有缓存与压缩。
1)缓存。
B/S应用中,用户第一次访问我们的应用程序时,会默认把静态文件如js、css等文件保存在浏览器中,无需下次再打开浏览器时再获取服务器的静态文件。浏览器的缓存分为强缓存与协商缓存,一般的静态文件如css、html等都是强缓存。强缓存与协商缓存都是服务器指定的,区别在于协商缓存请求一次服务器来证明是否获取浏览器缓存,而强缓存没过期的话都会获取浏览器本地缓存。所以要把文件的缓存归类好,哪些是基本不会变化的,哪些是变化很大的,最后做出相应的缓存处理。
然后是CDN。一般部署用户量大的应用都需要把前端部署到CDN上面,以减轻服务器压力及快速响应页面到用户终端。
最后是后端缓存。后端缓存主要是通过反向代理服务器来缓存,如闻名的Nginx。当前端需要请求后端时,后端首先经过Nginx等反代,然后判断是否需要向下一层请求。这里的Nginx会判断服务器有无更改过内容,如果无则从Nginx直接返回,无需经过下层的服务器。
2)压缩。
压缩最直接的做法。通过压缩JS、CSS等文件,以达到减少网络上的数据传输的目的。
后端应用程序
1)工具。
可通过一些工具上的使用,分析代码有哪些值得优化的地方。这些工具包括C#的dotTrace、PrefCollect、VTune等,java的JProfiler、ZProfiler等。
能使用工具最好是使用工具分析出来,使用这些工具是最直观快捷的做法,有时候这些工具直接分析出代码的不足地方,问题也就帮助你解决了。
2)中间件、SLB、缓存。
有时候,你会遇到API访问慢的问题。此API可能是需要大量耗时,也可能是用户量访问大引起的。这时候你可以通过异步处理的方式来进行优化。这里的异步处理通常是用中间件来解决,如队列。
我们经常访问数据库都知道,数据库的请求压力一般都是很大的。如果多人同时请求数据库可能发生拥挤的情况,并且一般服务器的性能瓶颈都在数据库。如何优化数据库呢?这个下一点做讨论,我们可以从减少数据库访问的方向来入手,可以通过缓存的方式来减少数据库的访问。即在数据库访问上面加一层一级缓存来做处理,减少直接访问数据库的压力。
有时候是应用瓶颈性能到了,这时候我们就需要部署多个应用实例了,通过负载均衡SLB来分发请求到应用,加大应用的访问力。
3)CPU、内存。
应用程序的CPU与内存分析,通过上面介绍的工具分析即可。一般工具可以看出上下文的切换,减少这种不必要的切换能大大提升程序的性能。有时候单线程比多线程性能更优。
内存通过分析可以得到哪些对象是释放不了的,通过减少内存的使用来提高应用的稳定性。
4)业务调优。
最后在后端优化上说的是应用上的调优。业务上的调优是很关键的因素,可以通过与客户、产品经理的沟通,来达到业务调优的目的。有些功能是边界功能,会影响应用性能的话那么建议是去掉;有些功能绕了几圈,程序处理性能很低,那么简化其功能。很多时候通过业务上沟通,加快程序上的性能,减轻技术人员的压力。
5)接口合并
有些页面,因为多次的请求而导致后端请求过多。所以我们在页面上,尽量的就行接口的合并。一个简单的页面,应该就对应一个接口即可。如有些页面根据用户体验的不同而需要不同的加载方式,即有些元素需要先加载,有些是后加载,则这些页面可多个接口。
6)分治
在后端的应用程序中,单体应用是有瓶颈的。在单体应用中,部署在一台机器,机器的性能包括CPU、网络读取、内存都有相应的瓶颈。所以要使用分治的思想,把系统拆分成多个子系统或服务,如现流行的微服务或者服务化。至少让高并发的应用服务化。
7)keepalive
上述也介绍过,keepalive是http1.1固有的,用来保持连接,减少重新请求的握手动作。对于经常发起请求的,考虑用长连接的方式。
数据库
性能优化上,先优化最慢的效果是最明显的,往往是最慢的影响着性能。在应用程序中,数据库是性能提升的关键因素。
1)配置优化。
数据库的提升,首先是配置上的优化。数据库很耗内存及CPU,CPU与内存上去了那么你的数据库性能档次也会相应地得到提升。
2)索引及慢SQL。
然后是建立合适的索引及避免慢SQL的查询。索引从来都是直接提升查询的方法,所以不是建立得越多越好,越多的索引会导致硬盘空间占用过大并且写性能低下。合适的在表中建立查询较多字段的索引是关键。
其次要避免慢sql的查询。慢sql可通过explain关键字就行sql的调优,也可根据经验来避免全表的扫描。经常是因为写慢sql导致全表的扫描,最终导致性能的低下。
3)数据清理
一个表的数据量有它的极限,太大的数据量为以后数据的读写埋下炸弹。无用的数据需要定时地做清理。这里的清理不是说数据删除了即可,不同的数据库规则不同,大部分直接delete from表是删除了表的数据,这是表面上的删除,硬盘空间还会占用着。需要做数据的定时清理,清理硬盘空间。办法有很多,最简单粗暴的方法是建立临时表与原表的数据做临时迁移。
4)分表分库
分表分库是很大众的做法,目前的公司数据量过大的情况下都会使用到。在数据量过多的情况下,会导致性能的低下,这时候分表分库虽然会用一些中间件多一层的方式,但是性能比原来的也会好很多。分表分库这里不详细讨论,可上网搜索一些使用方法。
操作系统
操作系统的优化,主流是linux开源系统的优化,windows一般很少做优化。所以这里只介绍linux的优化。会分为CPU、内存、磁盘、内核参数、文件系统方面优化。
1)CPU
CPU是系统运行效率的保障,市面上的CPU一般都是多核的,效率也得到大大提升。在linux上多核的cpu会看成一个一个核。例如你的cpu是四核,那么在linux上看成是四个单核cpu。
据权威报告,cpu多核分开比整合在一起性能快20%左右。即一个四核的cpu比四个1核的cpu慢20%。
2)内存
内存分两种,分别为物理内存、虚拟内存。在以前配置虚拟内存一般为物理内存的两倍,因物理内存容量比较小。现在随着物理内存费用不再像以前那么高,很多机器的内存都可以升到很高了,所以建议高内存的服务器不开通虚拟内存。例如流行的k8s就禁止用虚拟内存。
在系统方面,一般安装64位的操作系统,因为32位的操作系统有内存的限制。8G左右的内存已经是32位操作系统的上限,如果内存再多也无用。而64位的无限制。在应用程序方面,32位操作系统每个应用程序内存支持最大4G,而64位的没有限制。
这些内存都需要理解好,因为配置部署系统时很关键,大内存的应用尤为关键,如mongodb、redis。
3)磁盘
磁盘是影响着IO读写的关键,有些应用的IO读写很重要。提升磁盘性能的有RAID等。在市场上买磁盘时有固态、磁盘。有些应用比较依赖磁盘,这种一般都采用固态硬盘,如数据库都比较依赖硬盘。
4)内核参数
内核参数包括共享段、文件句柄等。网上很多这方面的调优,这里不详细介绍。
5)文件系统
其实文件系统是一个很重要的东西,因为不同的文件系统性能是不同的。较流行的有EXT4、XFS。
总结
我们分析了性能优化的一些思路,这些思路是你应用程序遇到瓶颈时都可思考。我们从大方向上分别是网络、应用程序、数据库、操作系统分析了性能优化的思路,最后从这些方面入手细分。下图是我们这篇文章性能优化思路的脑图,可供参考。
可以关注本人的公众号,多年经验的原创文章共享给大家。