性能调优基础
Load与CPU利用率
这两个指标是衡量CPU繁忙程度的关键指标。load表示当前系统正在运行和等待运行的进程队列长度。load越高,表示对cpu资源竞争越激烈,处理器越多,可以支持load越高。 CPU利用率表示一定时间内使用CPU的效率,使用CPU的时间与占用CPU的时间的比值。 处理器核数增加,可以支持的load越高,处理能力越强;而CPU利用率主要与软件的实现有关,具体而言,与软件实现的并发度(开启线程数目,串行度)有关。
同步与异步(编程模型)
同步方式下,阻塞的线程比例会很高,而阻塞线程不被操作系统调度,不占有CPU,导致单位时间内,使用CPU降低,因此IO密集型的应用,CPU利用率普遍比较低。但是同步和异步的方式本身,不会对CPU使用率造成差别,传统的一线程一请求模式可以通过增加线程的方式提高CPU的利用率, 并且在线程数不是太多的情况下比异步方式性能更好,但异步方式的好处在于线程不会因为IO而处于阻塞状态(增加阻塞状态线程的比例), 最终能够用更少的线程达到高吞吐量,线程过多会因为线程间切换和内存开销而产生瓶颈。
QPS与RT
QPS:系统每秒处理的请求数,衡量系统吞吐量的指标。
RT:一个请求的响应时间,也可以是一段时间的平均值。
对于一个具体的系统而言,自然是希望RT越低越好,QPS越高越好。为了更高的QPS,最简单的办法是增加处理线程数,提高程序的并发度。但是线程数增加到一定程度,会由于各种原因:上下文开销增大,线程栈占用更多的内存,CPU-CACHE的命中率下降导致QPS无法继续上升,而且RT也会继续增加,导致不满足业务需求,因此会有一个最佳线程数概念。
最佳线程数:刚好消耗完服务器瓶颈资源的临界线程数(得到最大QPS的线程数)
QPS、RT与最佳线程数关系
RT = CPU Time + Wait Time
最佳线程数=((Wait Time + CPU Time)/CPU Time) * CPU cores * CPU利用率
单线程模型:QPS=1000/RT
多线程模型:QPS = 最佳线程数*1000/RT
= (1000/CPU Time)*(CPU cores * CPU利用率)
如何得到最佳线程数
通过逐步添加线程数,当刚好消耗完服务器的资源时,则到达最佳压测线程数,此时会有以下特征: 线程数继续递增,QPS不变,RT变长,继续增加,则QPS开始下降,资源瓶颈,可以是CPU,可以是内存,也可以是IO或同步锁。公式是冷冰冰的,但实际运行的系统没那么简单,否则系统工程师也不必费劲去找系统瓶颈去调优了。 随着线程数上升,导致上下文开销增大,线程栈占用更多的内存,CPU-CACHE的命中率下降, 可能达到最佳线程数之前,RT已经不符合业务的期望,满足一定RT的QPS才是有意义的。
线程池与QPS
前面提到,随着线程数的递增,导致上下文开销增大,线程栈占用更多的内存,CPU-CACHE的命中率下降,从而影响系统的 整体性能。通过线程池(一个线程服务多个请求)可以有效地降低线程数量,缓解上述问题。 所以现在无论是DB服务器(比如mysql),还是应用服务器(比如nginx),实质都是有线程池的。采用线程池,特别对于高并发 场景有很大的意义,线程数量也可以维持在较低的水平。采用线程池模型,使得较少的线程服务请求,可以提高CPU利用率, 同时缓解RT的上升。下图是mysql启用线程池与关闭线程池在纯读和读写两种场景下,系统吞吐量的对比。
CPU密集型应用
主要消耗在CPU,减少单次请求的CPU使用时间(比如函数调用量变少),加大并发度(多线程,充分利用多核), 单位时间内可以处理更多的请求,可以提升QPS。当线程数加到一定程度时,大大超过CPU核数,导致大量的 上下文切换,增大RT。
IO密集型应用
1.这种应用比如数据库,主要时间消耗在IO,假设CPU利用率没有达到瓶颈,单位时间内请求数目一定
(1)减少IO操作(减少读写IO次数),可以减少RT,则QPS基本不变;
(2)减少CPU操作(减少函数调用),可以降低CPU利用率;同时可以减少RT,但不如减少IO明显。
2.在RT满足应用需求的情况下,比如每秒10w次请求,RT是10ms,则QPS就是10w,有意义的QPS一定与RT相关。理论上,继续加 大请求数,QPS还可以继续往上,同时RT也会继续往上。当超过1s时,则请求再多,也无法提升QPS。因为一个请求在1s内无法处理完毕。
软中断与硬中断
中断是指由于接收到外围硬件(相对于CPU与内存而言)的异步信号或者来自软件的同步信号而进行相应的硬件/软件处理。硬中断是指外围硬件发给CPU或者内存的异步信号就是硬中断信号;而软中断是软件本身发给操作系统内核的信号,通常由硬中断处理程序或系统调用对操作系统内核的中断。区别软中断和硬中断的一个关键点:是否有中断控制器参与,外设侦测到变化,通过中断控制器来中断CPU,是一种随机的行为。软中断直接以一个CPU指令,调用相应的中断处理程序,是程序可以控制的。一般来说,磁盘IO和网卡IO中断处理都包含硬中断和软中断两个部分,硬中断处理那些可以短时间完成的工作,而将需要较长时间处理的事情交给软中断处理。举个栗子,比如网卡中断,当网卡收到一个数据包后,通知操作系统外设状态变化,这时候就是发起了一个硬中断。操作系统处理中断,调用网卡中断处理程序会把数据复制到缓冲区,并设置一个标记位,然后告诉网卡可以继续接收数据了。操作系统中断返回时,会检查标记位,若有,则回调软中断的处理函数。
网卡吞吐量优化
由于目前CPU都是多核,可以将网卡设置为多队列,提高网卡处理效率。当某个队列收到报文时,触发相应的中断,收到中断的核,对其进行处理。为了避免不同的核处理同一个队列的报文引起混乱,将每个队列绑定到唯一的一个核心上。
参考文档
http://blog.csdn.net/pxz_002/article/details/7327668
http://www.cnblogs.com/cchust/p/3354570.html