1. 性能优化
1.1性能指标
高并发和响应快对应着性能优化的两个核心指标 :吞吐和延时。
性能问题的本质就是系统资源已经到达瓶颈,但请求的处理还不够快,⽆法⽀撑更多的请求。性能分析实际上就是 找出应⽤或系统的瓶颈,设法去避免或缓解它们。
1.2 平均负载
平均负载:单位时间内,系统处于可运⾏状态和不可中断状态的平均进程数,也就是平均活跃进程数。它和我们传 统意义上理解的CPU使⽤率并没有直接关系。 其中不可中断进程是正处于内核态关键流程中的进程(如常⻅的等待设备的I/O响应)。不可中断状态实际上是系 统对进程和硬件设备的⼀种保护机制。
平均负载在生产环境基本是重点监控对象,根据历史数据判断负载的变化趋势。当负载存在明显升⾼趋势时,及时进⾏分析和调查。理论上平均负载不能超过cpu总数的1.5倍以上,工作时有人会混淆平均负载和CPU使⽤率的概念,其实两者并不完全对等:
CPU密集型进程,⼤量CPU使⽤会导致平均负载升⾼,此时两者⼀致
I/O密集型进程,等待I/O也会导致平均负载升⾼,此时CPU使⽤率并不⼀定⾼
⼤量等待CPU的进程调度会导致平均负载升⾼,此时CPU使⽤率也会⽐较高
注意: 平均负载⾼时可能是CPU密集型进程导致,也可能是I/O繁忙导致。具体分析时可以结合mpstat/pidstat⼯具辅助 分析负载来源
2.cpu
2.1 cpu上下文切换
CPU上下⽂切换,就是把前⼀个任务的CPU上下⽂(CPU寄存器和PC)保存起来,然后加载新任务的上下⽂到这些 寄存器和程序计数器,最后再跳转到程序计数器所指的位置,运⾏新任务。其中,保存下来的上下⽂会存储在系统 内核中,待任务重新调度执⾏时再加载,保证原来的任务状态不受影响。
按照任务类型,CPU上下⽂切换分为:
进程上下⽂切换
线程上下⽂切换
中断上下⽂切换
进程上下⽂切换
Linux进程按照等级权限将进程的运⾏空间分为内核空间和⽤户空间。从⽤户态向内核态转变时需要通过系统调⽤ 来完成
首先,先解释一下用户态与内核态
-
用户态:当应用程序运行时,它们通常运行在用户模式下。在这个模式下,应用程序不能直接访问硬件或执行某些需要高级权限的操作,如修改其他进程的内存或执行I/O操作。这是为了系统的安全和稳定。
-
内核态:内核是操作系统的核心,负责管理硬件、内存、进程等。内核运行在内核模式下,具有执行任何操作的权限,包括访问硬件、管理内存和进程等。
系统调用是用户程序请求操作系统内核服务的接口。⼀次系统调⽤过程其实进⾏了两次CPU上下⽂切换,当用户程序需要执行一些只有内核才能进行的操作时(如文件读写、进程控制、网络通信等),它会通过系统调用来请求内核的服务。
当系统调用发生时,会发生以下步骤:
-
用户模式到内核模式的切换:CPU的当前状态(包括寄存器的值、程序计数器等)被保存,然后CPU切换到内核模式。这是通过执行一个特定的指令(如x86架构中的
int
指令或sysenter
/syscall
指令)来实现的。 -
执行系统调用服务:内核根据系统调用的编号(通常作为参数传递给系统调用指令)来查找并执行相应的服务例程。
-
内核模式到用户模式的切换:系统调用完成后,内核将结果返回给用户程序,并恢复之前保存的CPU状态,使CPU回到用户模式继续执行用户程序。
系统调⽤过程中并不会涉及虚拟内存等进程⽤户态资源,也不会切换进程。和传统意义上的进程上下⽂切换不同。 因此系统调⽤通常称为特权模式切换。
进程是由内核管理和调度的,进程上下⽂切换只能发⽣在内核态。因此相⽐系统调⽤来说,在保存当前进程的内核 状态和CPU寄存器之前,需要先把该进程的虚拟内存,栈保存下来。再加载新进程的内核态后,还要刷新进程的虚 拟内存和⽤户栈。
进程只有在调度到CPU上运⾏时才需要切换上下⽂,有以下⼏种场景:CPU时间⽚轮流分配,系统资源不⾜导致进 程挂起,进程通过sleep函数主动挂起,⾼优先级进程抢占时间⽚,硬件中断时CPU上的进程被挂起转⽽执⾏内核 中的中断服务。
线程上下文切换
线程上下⽂切换分为两种:
前后线程同属于⼀个进程,切换时虚拟内存资源不变,只需要切换线程的私有数据,寄存器等;
前后线程属于不同进程,与进程上下⽂切换相同。
同进程的线程切换消耗资源较少,这也是多线程的优势。
中断上下⽂切换
中断上下⽂切换并不涉及到进程的⽤户态,因此中断上下⽂只包括内核态中断服务程序执⾏所必须的状态(CPU寄 存器,内核堆栈,硬件中断参数等)。
中断处理优先级⽐进程⾼,所以中断上下⽂切换和进程上下⽂切换不会同时发⽣。
观察上下文切换情况
通过vmstat可以查看系统总体的上下⽂切换情况
cs (context switch) 每秒上下⽂切换次数
in (interrupt) 每秒中断次数
r (runnning or runnable)就绪队列的⻓度,正在运⾏和等待CPU的进程数
b (Blocked) 处于不可中断睡眠状态的进程数 要查看每个进程的详细情况,需要使⽤pidstat来查看每个进程上下⽂切换情况
cswch 每秒⾃愿上下⽂切换次数 (进程⽆法获取所需资源导致的上下⽂切换)
nvcswch 每秒⾮⾃愿上下⽂切换次数 (时间⽚轮流等系统强制调度)
测试:
vmstat 1 1 #⾸先获取空闲系统的上下⽂切换次数
sysbench --threads=100 --max-time=300 threads run #模拟多线程切换问题
vmstat 1 1 #新终端观察上下⽂切换情况
此时发现cs数据明显升⾼,同时观察其他指标:
r列: 远超系统CPU个数,说明存在⼤量CPU竞争
us和sy列:sy列占⽐60%,说明CPU主要被内核占⽤
in列: 中断次数明显上升,说明中断处理也是潜在问题
说明运⾏/等待CPU的进程过多,导致⼤量的上下⽂切换,上下⽂切换导致系统的CPU占⽤率⾼
pidstat -w -u 1 #查看到底哪个进程导致的问题 从结果中看出是sysbench导致CPU使⽤率过⾼,但是pidstat输出的上下⽂次数加起来也并不多。分析sysbench模 拟的是线程的切换,因此需要在pidstat后加-t参数查看线程指标。
另外对于中断次数过多,我们可以通过/proc/interrupts⽂件读取
watch -d cat /proc/interrupts
发现次数变化速度最快的是重调度中断(RES),该中断⽤来唤醒空闲状态的CPU来调度新的任务运⾏。分析还是 因为过多任务的调度问题,和上下⽂切换分析⼀致。
2.2 cpu使用率100%
Linux作为多任务操作系统,将CPU时间划分为很短的时间⽚,通过调度器轮流分配给各个任务使⽤。为了维护 CPU时间,Linux通过事先定义的节拍率,触发时间中断,并使⽤全局变了jiffies记录开机以来的节拍数。时间中断 发⽣⼀次该值+1.
CPU使⽤率,除了空闲时间以外的其他时间占总CPU时间的百分⽐。可以通过/proc/stat中的数据来计算出CPU使 ⽤率。因为/proc/stat时开机以来的节拍数累加值,计算出来的是开机以来的平均CPU使⽤率,⼀般意义不⼤。可 以间隔取⼀段时间的两次值作差来计算该段时间内的平均CPU使⽤率。性能分析⼯具给出的都是间隔⼀段时间的平 均CPU使⽤率,要注意间隔时间的设置。
CPU使⽤率可以通过top 或 ps来查看。分析进程的CPU问题可以通过perf,它以性能事件采样为基础,不仅可以分 析系统的各种事件和内核性能,还可以⽤来分析指定应⽤程序的性能问题。 perf top / perf record / perf report (-g 开启调⽤关系的采样)
sudo docker run --name nginx -p 10000:80 -itd feisky/nginx
sudo docker run --name phpfpm -itd --network container:nginx feisky/php-fpm
ab -c 10 -n 100 http://XXX.XXX.XXX.XXX:10000/ #测试Nginx服务性能
发现此时每秒可承受请求给⻓少,此时将测试的请求数从100增加到10000。在另外⼀个终端运⾏top查看每个CPU 的使⽤率。发现系统中⼏个php-fpm进程导致CPU使⽤率骤升。
接着⽤perf来分析具体是php-fpm中哪个函数导致该问题。
perf top -g -p XXXX #对某⼀个php-fpm进程进⾏分析
发现其中sqrt和add_function占⽤CPU过多, 此时查看源码找到原来是sqrt中在发布前没有删除测试代码段,存在 ⼀个百万次的循环导致。将该⽆⽤代码删除后发现nginx负载能⼒明显提高
2.3 系统cpu使用率很高,但是找不到占用的进程
sudo docker run --name nginx -p 10000:80 -itd feisky/nginx:sp
sudo docker run --name phpfpm -itd --network container:nginx feisky/php-fpm:sp
ab -c 100 -n 1000 http://XXX.XXX.XXX.XXX:10000/ #并发100个请求测试
实验结果中每秒请求数依旧不⾼,我们将并发请求数降为5后,nginx负载能⼒依旧很低。 此时⽤top和pidstat发现系统CPU使⽤率过⾼,但是并没有发现CPU使⽤率⾼的进程。 出现这种情况⼀般时我们分析时遗漏的什么信息,重新运⾏top命令并观察⼀会。发现就绪队列中处于Running状 态的进⾏过多,超过了我们的并发请求次数5. 再仔细查看进程运⾏数据,发现nginx和php-fpm都处于sleep状态, 真正处于运⾏的却是⼏个stress进程。 下⼀步就利⽤pidstat分析这⼏个stress进程,发现没有任何输出。⽤ps aux交叉验证发现依旧不存在该进程。说明 不是⼯具的问题。再top查看发现stress进程的进程号变化了,此时有可能时以下两种原因导致: 进程不停的崩溃重启(如段错误/配置错误等),此时进程退出后可能⼜被监控系统重启; 短时进程导致,即其他应⽤内部通过exec调⽤的外⾯命令,这些命令⼀般只运⾏很短时间就结束,很难⽤top 这种间隔较⻓的⼯具来发现 可以通过pstree来查找 stress的⽗进程,找出调⽤关系。 pstree | grep stress 发现是php-fpm调⽤的该⼦进程,此时去查看源码可以看出每个请求都会调⽤⼀个stress命令来模拟I/O压⼒。之前 top显示的结果是CPU使⽤率升⾼,是否真的是由该stress命令导致的,还需要继续分析。代码中给每个请求加了 verbose=1的参数后可以查看stress命令的输出,在中断测试该命令结果显示stress命令运⾏时存在因权限问题导 致的⽂件创建失败的bug。 此时依旧只是猜测,下⼀步继续通过perf⼯具来分析。性能报告显示确实时stress占⽤了⼤量的CPU,通过修复权限问题来优化解决即可.
2.4 系统有不可中断进程
进程状态分析
在Linux系统中,进程的状态是理解和诊断系统性能问题的重要方面。常见的进程状态包括:
- R (Running/Runnable): 表示进程正在CPU的就绪队列中,正在运行或等待运行。
- D (Disk Sleep): 不可中断状态,通常表示进程正在与硬件交互,且交互过程中不允许被其他进程中断。这种状态一般短暂,但长时间保持可能指示I/O性能问题。
- Z (Zombie): 僵尸进程,表示进程已结束但父进程尚未回收其资源。大量僵尸进程会耗尽PID资源,影响新进程的创建。
- S (Interruptible Sleep): 可中断睡眠状态,进程因等待某个事件而被挂起,事件发生时会被唤醒并进入运行状态。
- I (Idle): 空闲状态,主要用于内核线程,不会导致系统平均负载增加。
- T (Stop/Traced): 进程处于暂停或跟踪状态,可能由SIGSTOP/SIGCONT信号或GDB调试引起。
- X (Dead): 进程已消亡,不会在top/ps等工具中看到。
磁盘I/O问题与优化
当遇到系统性能瓶颈,特别是平均负载升高和iowait较高时,首先需要怀疑是否存在磁盘I/O问题。使用Docker容器运行的应用可能会因为磁盘I/O操作不当而受到影响。例如,使用O_DIRECT
标志进行磁盘读写时,会绕过文件系统缓存,直接访问磁盘,这可能导致较高的iowait。
通过top
、dstat
、pidstat
等工具可以监控和分析系统资源使用情况,包括CPU、内存和I/O。dstat
特别有用,因为它能同时显示CPU和I/O使用情况。通过pidstat -d
可以查看特定进程的磁盘I/O统计信息,有助于定位哪些进程在进行大量磁盘读写。
僵尸进程处理
僵尸进程通常是由于父进程未能正确回收子进程资源造成的。这些进程虽然已经结束,但仍占用系统资源。使用pstree
等工具可以帮助定位僵尸进程的父进程,并检查父进程是否正确地调用了wait()
或waitpid()
来回收子进程资源。同时,确保父进程注册了SIGCHLD信号的处理函数,以便在子进程结束时得到通知。
分析与优化步骤
- 确认问题:使用
top
、dstat
等工具查看系统平均负载、CPU使用率、iowait等指标,确认是否存在性能瓶颈。 - 定位问题:通过
pidstat
等工具查看哪些进程在进行大量磁盘读写,特别是注意处于D状态的进程。 - 深入分析:对于特定进程,使用
strace
(注意权限问题)或perf
等工具跟踪系统调用,分析进程行为。 - 优化代码:根据分析结果,优化代码中的磁盘I/O操作,避免不必要的直接I/O操作。
- 处理僵尸进程:检查并修改父进程的代码,确保正确回收子进程资源,减少僵尸进程的产生。
2.5 CPU性能指标
CPU 使用率
-
用户CPU使用率:这包括用户在应用程序中的正常执行时间(user mode)和调低了优先级的执行时间(nice mode)。如果用户CPU使用率过高,通常意味着应用程序正忙于处理任务。
-
系统CPU使用率:指的是CPU在内核模式下运行的时间百分比(不包括处理中断的时间)。系统CPU使用率高,表明内核正在忙于处理系统级任务,如进程调度、设备驱动等。
-
等待I/O的CPU使用率(iowait):这个指标高表明CPU花费了大量时间在等待I/O(输入/输出)操作完成,这通常是因为系统与硬件设备之间的交互时间较长。
-
软/硬中断CPU使用率:高比例的中断CPU使用率表明系统中发生了大量中断。这些中断可以是硬件引起的(如设备完成操作),也可以是软件触发的(如系统调用)。
-
Steal CPU / Guest CPU:Steal CPU指的是在虚拟化环境中,宿主机的CPU时间被虚拟机占用的百分比;而Guest CPU则是指运行在虚拟机中的操作系统所使用的CPU时间百分比。
平均负载
- 理想情况下,平均负载应与逻辑CPU的数量相等,这表示每个CPU都得到了充分的利用。如果平均负载大于逻辑CPU的数量,则说明系统负载较重,可能需要更多的CPU资源来处理当前的任务。
进程上下文切换
- 进程上下文切换是Linux系统保证多任务正常执行的核心机制,包括自愿切换(如进程因等待资源而主动让出CPU)和非自愿切换(系统为了平衡负载或响应更高优先级的进程而强制进行的切换)。虽然上下文切换是必需的,但过多的切换会消耗原本用于运行进程的CPU时间,在寄存器、内核栈及虚拟内存等数据的保存和恢复上造成额外开销。
CPU缓存命中率
- CPU缓存命中率是衡量CPU缓存复用效率的重要指标。命中率越高,说明CPU能够更多地从缓存中读取数据,减少对内存的访问,从而提高性能。L1和L2缓存常用于单核处理器,而L3缓存则更多地在多核处理器中使用,以提高核心间的数据共享效率。
2.6 cpu性能案例
平均负载案例
首先,通过uptime
命令查看系统的平均负载,以初步判断系统当前的负载状况。若发现负载持续升高,接下来使用mpstat
命令详细查看每个CPU的使用情况,以判断是否是某个或某些CPU过载。同时,利用pidstat
工具监控各个进程的CPU使用情况,特别是那些占用CPU资源较高的进程,从而识别出导致平均负载升高的具体进程。
上下文切换案例
在怀疑系统上下文切换频繁导致性能问题时,首先使用vmstat
命令查看系统的上下文切换次数和中断次数。随后,通过pidstat
工具分别观察进程的自愿(如等待I/O)和非自愿(如优先级调整)上下文切换情况,以进一步分析哪些进程或线程是上下文切换的主要贡献者。最后,使用pidstat
针对线程级别的上下文切换进行详细分析,以便更精确地定位问题。
进程CPU使用率高案例
面对进程CPU使用率高的情况,首先使用top
命令查看系统和各进程的CPU使用情况,快速定位到占用CPU资源较高的进程。接着,利用perf top
工具深入分析该进程的函数调用链,从而找到消耗CPU资源最多的具体函数或代码段。
系统CPU使用率高但无明显高CPU进程案例
有时系统CPU使用率很高,但top
或pidstat
等工具却找不到明显的CPU高占用进程。此时,需要重新审视top
的输出,特别关注那些CPU使用率不高但长时间处于Running状态的进程。这可能是因为存在大量短生命周期的进程频繁创建和销毁,导致CPU忙于进程调度。使用perf record
和perf report
工具可以帮助捕捉这类短时进程的行为,而execsnoop
工具则能实时监控到新进程的创建情况,从而辅助定位问题。
不可中断和僵尸进程案例
当top
显示iowait升高,并发现大量不可中断和僵尸进程时,直接使用strace
跟踪这些进程的系统调用可能会因权限或状态问题而失败。此时,应使用perf
工具深入分析进程的调用链,重点关注与磁盘I/O直接相关的操作。如果发现是磁盘直接I/O(如使用了O_DIRECT
标志)导致的问题,应考虑优化应用程序的I/O策略。
软中断案例
对于系统软中断CPU使用率高的情况,首先通过top
命令观察到这一现象。接着,查看/proc/softirqs
文件,分析各种软中断类型的处理次数及其变化速率,以找到处理负担较重的软中断类型。使用sar
命令可以进一步分析系统活动的历史数据,帮助确认是否存在网络小包等特定问题。最后,利用tcpdump
等网络分析工具捕获并分析网络帧的类型和来源,以确定是否存在如SYN FLOOD等网络攻击导致的软中断激增。
2.7 QPS与TPS与BPS
1. TPS(Transactions Per Second)
定义:
TPS,即每秒事务数,是软件测试结果的测量单位。一个事务是指一个客户机向服务器发送请求然后服务器做出反应的过程。客户机在发送请求时开始计时,收到服务器响应后结束计时,以此来计算使用的时间和完成的事务个数。
特点:
- 包括用户请求服务器、服务器内部处理以及服务器返回给用户三个过程。
- 每秒能够完成的事务数(N)即为TPS的值。
- 衡量了系统每秒处理事务的能力,是评价系统性能的重要指标之一。
2. QPS(Queries Per Second)
定义:
QPS,即每秒查询率,是一台服务器每秒能够响应的查询次数。它是对一个特定的查询服务器在规定时间内所处理流量多少的衡量标准。
特点:
- 衡量了服务器处理查询请求的能力。
- 与TPS类似,但更侧重于查询操作,而不一定是完整的事务。
- 在因特网上,作为域名系统服务器的机器的性能经常用每秒查询率来衡量。
3. BPS(系统吞吐量)
定义:
BPS是指单位时间内计算机的处理能力,包括单位时间内数据的输入输出能力、主机处理能力以及主机与外设之间或主机与主机之间的信息交换能力。它通常用单位时间内处理的请求数或事务数来表示,如RPS(requests per second)或TPS(transactions per second)。
特点:
- 衡量了系统单位时间内处理请求或事务的能力。
- 高吞吐量表示系统能够快速处理大量请求,而低吞吐量可能表示系统存在性能瓶颈或资源限制。
- 除了吞吐量外,还需要考虑响应时间、并发用户数、错误率等其他指标来全面评估系统性能。
区别总结
指标 | 定义 | 特点 |
---|---|---|
TPS | 每秒事务数 | 衡量系统每秒处理事务的能力,包括完整的请求-响应过程 |
QPS | 每秒查询率 | 衡量服务器每秒响应查询请求的能力,侧重于查询操作 |
BPS | 单位时间内处理能力 | 综合衡量系统单位时间内处理请求或事务的数量,是系统性能的重要指标之一 |
总的来说,TPS和QPS都是衡量系统处理能力的具体指标,但TPS更侧重于事务的完整性,而QPS更侧重于查询操作。BPS则是一个更广泛的性能指标,包括了单位时间内系统处理的所有请求或事务的数量。在评估系统性能时,通常会综合考虑这些指标以及其他相关因素。
2.8 Linux性能优化
一、CPU优化
- 监控和分析CPU使用情况
- 使用
top
、htop
、ps
等命令监控CPU使用率,找出占用CPU资源过高的进程。 - 使用
perf
、sysstat
等工具进行更深入的性能分析,定位瓶颈。
- 使用
- 优化进程和应用程序
- 关闭不必要的服务和进程,释放CPU资源。
- 对占用CPU资源高的应用程序进行代码和算法优化。
- 使用
nice
或renice
命令调整进程的优先级,确保重要进程获得更多的CPU时间。
- 调整CPU调度策略
- 根据应用场景选择合适的CPU调度器(如CFS、deadline、cfq等)。
- 对于实时性要求高的应用程序,考虑使用实时调度策略。
- CPU缓存优化
- 理解和优化CPU缓存的使用,提高缓存命中率。
- 考虑调整内核参数以优化缓存行为。
二、系统优化
- 内存管理
- 确保物理内存足够大,以支持运行的应用程序。
- 对于需要大量内存的应用程序,考虑使用64位操作系统。
- 监控和优化进程的内存使用,防止内存泄漏和过度占用。
- 磁盘I/O优化
- 使用SSD替代传统硬盘,提高磁盘读写速度。
- 对磁盘进行分区和格式化时,选择合适的文件系统类型(如ext4、XFS等)和挂载选项(如noatime等)。
- 定期清理无用的文件和日志,保持磁盘空间充足。
- 网络性能优化
- 调整TCP/IP参数,如TCP窗口大小、TCP连接数等,以提高网络传输效率。
- 使用更快的网络接口和网线,减少网络延迟和丢包率。
- 配置网络负载均衡,分散网络请求的压力。
- 系统配置和内核参数调整
- 根据硬件配置和应用程序需求,调整Linux内核参数,如文件系统缓存大小、进程调度策略等。
- 关闭不必要的系统服务和功能,以减少资源占用和提高安全性。
- 定期更新系统和应用程序的补丁和安全更新,保持系统的稳定性和安全性。
- 使用性能监控工具
- 利用Linux自带的性能监控工具(如
top
、vmstat
、iostat
等)或第三方工具(如Percona Monitoring and Management、New Relic等),实时监控系统的性能指标。 - 根据监控数据调整系统配置和优化策略,以达到最佳性能状态。
- 利用Linux自带的性能监控工具(如
- 安全性增强
- 使用强密码和安全的认证机制。
- 定期更新系统安全补丁和防火墙规则。
- 限制用户权限,遵循最小权限原则。
- 电源管理
- 对于笔记本电脑或具有节能需求的服务器,合理设置电源管理策略,如CPU频率调整、硬盘休眠等。