最近看了zee老弟的文章,通过分析网络流量来分析性能问题,于是也想写一篇。
我早期做性能测试,大概在99年。给一个银行做性能测试,因为其中很大的一个部分是我们开发的。于是自己写了一个程序,来给后台系统加压。
大概在2001年,我们做了两外一个系统,跑在aix上面,性能很差,我帮开发团队去看一下问题,结论是调度过度,架构不合理(组件模块划分的过细)。调优之后,性能提升了大概100倍。后来去给客户做poc,客户还嫌慢,说明调优还不到位。再后来又做了一次调优,性能才正常。所谓的正常,就是跟使用tuxedo相比,基本上性能持平,一个数量级。
从性能问题来看,大概分成几种情况:1,网络带宽问题;2,某个节点处理能力(就是tps差)不行;3,流量配置不合理;4,链路设计问题。
先说网络带宽问题。以前的老系统,特别是银行的,一般情况下oltp都不会有带宽问题,因为根据oltp的标准,一个请求包在1-2k,响应报文在4k之内,除非线路很差,一般都不会有。从现在的情况来看,更不会有网络问题。
我遇到一次网络问题,是由于病毒占用了大量的带宽,阻塞了。特殊的情况在于报表下载。如果所有的用户,在某个时间点上都下载报表呢?也会有拥堵。
实际上,只要根据tps和一次请求占用的流量大小,来计算一下,就知道整个的带宽是不是有问题。
比如,一次请求的数据,假设是50k,tps是1000,那么带宽需求是:1000*50k=50M。还要考虑上行带宽还是下行带宽,请求是上行带宽。
此外就是一些网络上传输的图片很容易占用带宽。
再说流量分配不合理。某个客户有多个节点,使用nginx来做负载均衡,由于配置错误,导致90%以上的流量都分配到其中一个节点,导致性能严重不达标。这种就需要使用全链路分析,看两个不同节点的cpu占用、带宽,很容易发现问题。流量分配不合理,主要是配置问题。因此全链路跟踪监控工具非常重要。
近些年,由于系统越来越复杂,已经从C/S、B/S架构的两层结构,发展到三层结构、多层结构。
在业务处理的每一层,如果出现问题,都可能出现性能瓶颈,所以,我们首先要定位,是哪一层出现了问题。
链路设计问题。有时候,由于应用系统设计不当,导致产生了很多多余的链路。比如可以使用三次通讯来解决的问题,结果使用了5次,多出来的两次很容易造成错误和性能问题。当然性能测试只能够发现问题,解决问题还要看设计链路的人。
这里面就涉及到一个问题:架构。网络架构、系统架构、IT架构等等。话题太大,就不展开赘述了。
最后,我们看节点处理能力问题。其实,节点又分成很多种类,比如存储、比如数据库。这一类的问题,一个要看数据库的配置和资源情况,另外一个就要看表结构、索引,重要的一点是程序。
数据库问题,常用的是看资源是否占满,比如io,比如cpu等资源是否过高。如果不高,但是又很慢,大多数是程序和结构问题。
最后看代码,也就是应用程序。应用程序优化,往往是系统的核心,绝大多数的性能问题,都是由于代码编写不当引起的。
从我自己的经验来看,主要是几大类:
1,错误的数据结构和算法。
某个项目,做了一个插入操作,结果花费了一分钟。我仔细看了一下代码,其实算法并不是很复杂,就是在数据库中构建了一个tree,然后把某个节点插入。
但是很慢。本质的问题在于,程序员把数据库当作内存来使用。内存的访问速度很快,数据库查了几个量级。
所以使用错误的数据结构,是很多问题的核心。这种情况就需要修改架构和算法才能够解决。
2,算法问题。
另外一个项目,也是操作很慢。去看了一下,没有架构问题。但是,有很多循环嵌套。关键是,在循环里面去访问database。
千万不要在循环里面去访问db,几乎是百分之百的慢。
循环嵌套。就是多层循环,里面还嵌套数据库访问,程序员是想作死。
3,block和轮询。
block,阻塞和轮询,是我们访问资源的两个方式。block的问题会造成程序挂起,但是挂起并不消耗cpu,但是会占住一个线程/进程。
轮询很快,但是频繁的轮询会导致cpu上升。
所以要评估你的算法,当访问资源的时候,是使用block还是轮询。
好像这一直是个问题,需要大量编码经验才能解决。
这也就是说,为什么没有大量的编码经验,吹嘘做架构师,很容易犯低级错误。
4,资源忘了释放。
这是很多板砖程序员容易犯的错。
5,分清楚系统调用和一般的调用。
系统调用,system call,会调用操作系统的核心,访问核心资源。所以,你看起来是一个函数,但是这个函数会导致你的系统很慢。
当然现在使用的语言远比c这样原始的语言高级,使得程序员分不清系统调用和一般函数。
经常遇到的问题是,内存分配。当你频繁访问内存,一些算法是从操作系统的堆来申请内存的,导致系统很慢,而且会产生很多内存碎片。
所以分清楚系统调用和一般函数,非常重要,尽量避免使用系统调用,特别是频繁的调用。
6,程序执行效率不高。
这个其实有很多算法,比如循环展开等等。你需要去了解编译器、cpu的指令序列是如何工作的。
cpu最怕的指令是jump,就是程序里面的循环和判断(if-else)。
如果知道这些,解决大多数性能问题应该不困难。
推荐阅读