CPU-优化问题
一、优化前的思考
-
做性能优化,要怎么判断它有效呢?特别是优化后,到底能提升多少性能?
-
确定性能的量化指标:
- 性能的量化指标有很多,比如 CPU 使用率、应用程序的吞吐量、客户端请求的延迟等,都可以评估性能。但是不要局限在单一维度的指标上,至少要从应用程序和系统资源这两个维度,分别选择不同的指标,因为应用程序和系统资源这两者间相辅相成的关系。好的应用程序是性能优化的最终目的和结果,系统优化总是为应用程序服务的,而系统资源的使用情况是影响应用程序性能的根源。
-
测试优化前的性能指标:
-
要避免性能测试工具干扰应用程序的性能;
-
避免外部环境的变化影响性能指标的评估。
-
-
测试优化后的性能指标:
-
要避免性能测试工具干扰应用程序的性能;
-
避免外部环境的变化影响性能指标的评估。
-
-
-
性能问题通常不是独立的,如果有多个性能问题同时发生,应该先优化哪一个呢?
-
并不是所有的性能问题都值得优化;动手优化之前,先把所有这些性能问题给分析一遍,找出最重要的、可以最大程度提升性能的问题,从它开始优化;
-
如果发现是系统资源达到了瓶颈,比如 CPU 使用率达到了 100%,那么首先优化的一定是系统资源使用问题;完成系统资源瓶颈的优化后,我们才要考虑其他问题;
-
针对不同类型的指标,首先去优化那些由瓶颈导致的,性能指标变化幅度最大的问题;
-
-
提升性能的方法并不是唯一的,当有多种方法可以选择时,你会选用哪一种呢?是不是总选那个最大程度提升性能的方法就行了呢?
-
考虑性能优化的成本;
-
考虑性能优化后带来的影响,性能优化通常会带来复杂度的提升,降低程序的可维护性,还可能在优化一个指标时,引发其他指标的异常。也就是说,很可能你优化了一个指标,另一个指标的性能却变差了。
-
二、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 上。
-
-
避免过早优化
-
优化会带来复杂性的提升,降低可维护性;
-
需求不是一成不变的。针对当前情况进行的优化,很可能并不适应快速变化的新需求;这样,在新需求出现时,这些复杂的优化,反而可能阻碍新功能的开发;
-
性能优化最好是逐步完善,动态进行,不追求一步到位,而要首先保证能满足当前的性能要求。当发现性能不满足要求或者出现性能瓶颈时,再根据性能评估的结果,选择最重要的性能问题进行优化。
-