解决性能问题的目的,自然是想得到一个性能提升的效果。为了评估这个效果,我们需要对系统的性能指标进行量化,并且要分别测试出优化前,后的性能指标,用前后指标的变化来对比呈现效果。这个方法叫做性能评估“三步走”
1.确定性能的量化指标
2.测试优化前的性能指标
3.测试优化后的性能指标
以web应用为例:
。应用程序的维度,我们可以用吞吐量和请求延迟来评估应用程序的性能
。系统资源的维度,我们可以用cpu使用率来评估系统的cpu使用情况 之所以从这两个不同维度选择指标,主要是因为应用程序和系统资源这两者间相辅相成的关系
。好的应用程序是性能优化的最终目的和结果,系统优化总是为应用程序服务的。所以,必须要使用应用程序的指标,来评估性能优化的整体效果
。系统资源的使用情况是影响应用程序性能的根源。所以,需要用系统资源的指标,来观察和分析瓶颈的来源
cpu优化
清楚了性能优化最基本的三个问题后,我们接下来从应用程序和系统的角度,分别来看看如何才能降低CPU使用率,提高CPU的并行处理能力。
应用程序优化
首先,从应用程序的角度来说,降低cpu使用率的最好方法当然是,排除所有不必要的工作,只保留最核心的逻辑。比如减少循环的层次,减少递归,减少动态内存分配等等。 除此之外,应用程序的性能优化也包括很多种方法。
。编译器优化:很多编译器都会提供优化选项,适当优化开启它们,在编译阶段你就可以获得编译器的帮助,来提升性能。比如,gcc就提供了优化选项-o2,开启后会自动对应程序的代码进行优化。
。算法优化:使用复杂度更低的算法,可以显著加快处理速度。比如,在数据比较大的情况下,可以用O(nlogn)的排序算法(如快排,归并排序等),代替O(n^2)的排序算法(如冒泡,插入排序等)
。异步处理:使用异步处理,可以避免程序因为等待某个资源而一直阻塞,从而提升程序的并发处理能力。比如,把轮询替换为事件通知,就可以避免轮询耗费cpu的问题
。多线程代替多进程:前面讲过,相对于进程的上下文切换,线程的上下文切换并不切换进程地址空间,因此可以降低上下文切换的成本。
。善用缓存:经常访问的数据或者计算过程中的步骤,可以放到内存中缓存起来,这样下次用时就能直接从内存中获取,加快程序的处理速度。
系统优化
从系统的角度来说,优化CPU的运行,一方面要充分利用CPU缓存的本地性,加速缓存访问;另一方面,就是要控制进出的CPU使用情况,减少进程间的相互影响。 具体来说,系统层面的CPU优化方法也有不少。
。CPU绑定:把进程绑定到一个或者多个cpu上,可以提高CPU缓存的命中率,减少跨cpu调度带来的上下文切换问题
。CPU独占:跟cpu绑定类似,进一步将CPU分组,并通过cpu亲和性机制为其分配进程。这样,这些cpu就由指定的进程独占,换句话说,不允许其他进程再来使用这些cpu
。优先级调整:使用nice调整进程的优先级,正值调低优先级,负值调高优先级。在这里,适当降低非核心应用的优先级,增高核心应用的优先级,可以确保核心应用得到优先处理。 。为进程设置资源限制:使用linux cgroups 来设置进程的CPU使用上限,可以防止由于某个应用自身的问题,而耗尽系统资源。
。NUMA(Non-Uniform Memory Access)优化:支持NUMA的处理器会被划分为多个node,每个node都有自己的本地内存空间。NUMA优化,其实就是让CPU尽可能只访问本地内存。
。中断负载均衡:无论是软中断还是硬中断,它们的中断处理程序都可能会耗费大量的cpu。开启irqbalance服务或者配置smp_affinity,就可以把中断处理过程自动负载均衡到多个CPU上。