CPU 使用率很高,怎么排查?
首先通过
top、ps等命令,定位占用 CPU 最高的进程。使用
top -Hp <PID>,定位进程中占用 CPU 最高的线程。导出并分析线程堆栈。以 Java 为例,可以将线程 ID 转换为十六进制,再在
jstack输出中匹配对应的线程,定位具体的方法和类。1 2printf "%x\n" 1235 jstack <PID>常见原因及处理方式:
- 死循环或密集计算: 代码中存在
while (true)等没有退出条件的循环,或复杂的递归与大规模计算,需要优化算法或修复代码逻辑。 - 频繁垃圾回收(GC): 内存不足或对象创建过于频繁,导致 Full GC 频繁触发,CPU 花费大量时间在垃圾回收上,可以使用
jstat -gcutil进一步确认。 - 高并发请求冲击: 系统本身没有故障,只是瞬时流量过大,超出了服务器的负载能力,需要考虑限流、扩容或优化请求处理逻辑。
- 死循环或密集计算: 代码中存在
CPU 性能指标速查
| 字段 | 含义 | 高负载场景 | 常见原因 | 排查工具与解决思路 |
|---|---|---|---|---|
us | 用户态 CPU 时间占比 | 应用程序本身消耗了大量 CPU | 大量计算、QPS 增加、死循环、频繁 GC | 使用 top -H -p <PID>、perf top 及语言自带工具(如 Go 的 pprof、Java 的 jstack);优化算法、修复死循环或横向扩容 |
sy | 内核态 CPU 时间占比 | CPU 主要消耗在内核层面 | 大量系统调用(open/read/write/futex)、频繁创建和销毁线程、上下文切换过多 | 使用 strace -c -p <PID>、vmstat 1、pidstat -w;减少锁竞争,使用连接池/线程池,批量处理 I/O |
ni | 由 nice 调整过的用户态进程所消耗的 CPU | 低优先级后台任务占用 CPU | 批处理任务、备份脚本等 | 通常属于预期行为;可通过调整任务执行时间或 Nice 值进行控制 |
id | 空闲 CPU 时间占比 | id 很低表示 CPU 忙 | CPU 容量不足或存在突发流量 | 结合 us、sy、wa 等指标判断 CPU 忙碌原因 |
wa | 等待 I/O 的 CPU 时间占比 | CPU 主要在等待 I/O 完成 | 磁盘 IOPS 瓶颈、同步刷盘、磁盘故障导致延迟升高 | 使用 iostat -xz 1、pidstat -d、iotop;排查磁盘、存储和 I/O 调用 |
hi | 硬件中断时间占比 | CPU 花费大量时间处理网卡、磁盘等硬件中断 | 网络流量或硬件中断过多 | 使用 cat /proc/interrupts 查看中断分布;配置网卡多队列和 irqbalance |
si | 软件中断时间占比 | CPU 花费大量时间处理软件中断 | 常见于网络包量大、TCP 连接建立和销毁频繁,也可能与定时器或块设备 I/O 有关 | 使用 mpstat -I SUM -P ALL 1、sar -n DEV 1;优化网络连接复用、RPS/RFS 和相关内核参数 |
st | 被虚拟机宿主机占用的 CPU 时间占比 | 虚拟机拿不到足够的 CPU | 宿主机超卖或其他虚拟机争抢资源 | 联系云厂商排查宿主机负载,或迁移到其他节点/独占实例 |
CPU 使用率不高,但 Load 很高
CPU 使用率不高但 Load 很高,通常说明有大量进程处于可运行状态(R),或处于不可中断睡眠状态(D)。D 状态通常与磁盘、网络存储等 I/O 等待有关,也需要关注锁竞争、NFS 和文件系统问题。
| |
I/O 排查
| |
进程、线程、协程
- 进程:操作系统分配资源的基本单位,一个进程可以拥有多个线程,并拥有独立的地址空间和资源。
- 线程:进程内的执行单位,同一进程中的线程共享进程的大部分资源,但拥有独立的栈和寄存器状态。
- 协程:由用户态运行时调度的轻量级执行单元,不直接由内核调度,通常运行在线程之上。
Linux 中的进程优先级与设置方法
进程的优先级决定了其获取 CPU 时间片的顺序。优先级更高(数值更低)的进程会优先获取 CPU 时间片。 对于普通进程,Nice 值会影响其调度优先级,范围是 -20(最高优先级)到 19(最低优先级)。实时进程还使用独立的实时优先级。 默认情况下,进程的 Nice 值为 0。
- nice 命令:nice 命令用于启动一个进程,并设置其 Nice 值。例如,nice -n 10 command 会以 Nice 值为 10 来启动 command。
- renice 命令:renice 命令用于修改已经在运行的进程的 Nice 值。例如,
renice +5 -p 1234会将 PID 为 1234 的进程的 Nice 值增加 5。需要注意的是,只有 root 用户或具备CAP_SYS_NICE权限的进程才能降低 Nice 值、提高调度优先级。 - 在代码中调用 nice() 或 setpriority() 函数:如果你正在编写一个程序,你可以在代码中调用 nice() 或 setpriority() 函数来改变你的进程的优先级。
什么是僵尸进程
僵尸进程是指一个已经终止运行、但父进程尚未回收其退出状态的进程。此时内核仍会保留少量进程描述信息,供父进程通过 wait() 等系统调用读取;进程占用的大部分资源已经释放。
什么是中断
中断是系统用来响应硬件设备请求的一种机制,会打断进程的正常调度和执行,然后调用内核的中断处理程序来响应设备的请求。 取外卖案例,不用苦苦等待,打电话的动作就是中断。 中断是一种异步处理机制,可以提高系统的并发处理能力。
软中断、硬中断、不可中断进程
Linux 通常将中断处理分为上半部分和下半部分: 上半部分直接处理硬件请求,特点是快速执行(硬中断)。 下半部分延后处理耗时工作,特点是延迟执行(软中断或其他下半部机制)。 不可中断进程(D 状态)表示进程正在等待某些不可中断的内核操作,常见于 I/O 等待。进程长时间处于 D 状态,通常需要排查存储、网络文件系统或驱动问题。
进程间通信的方式及其使用场景
- 管道(Pipe)和命名管道(Named pipe):管道通常用于具有父子关系的进程间通信;命名管道可以用于没有亲缘关系的进程。它们主要用于数据的流式传输,双向通信通常需要两个管道或使用 Socket。
- 消息队列(Message Queue):消息队列是一种列表结构,可以存储要发送的消息。进程可以向消息队列中添加消息,也可以从中读取消息。消息队列常用于不同进程间的数据交换和同步。
- 共享内存(Shared Memory):共享内存是最快的 IPC 方式,它允许两个或多个进程访问同一块内存区域。这种方式常用于大量数据的交换。
- 信号(Signal):信号是一种异步的通信方式,用于通知接收进程某个事件已经发生。例如,当一个进程结束时,它会发送一个 SIGCHLD 信号给其父进程。
- 套接字(Socket):套接字可以用于不同机器之间的进程通信,也可以用于同一机器上的进程通信。它支持 TCP、UDP 等多种协议,常用于网络通信。
- 信号量(Semaphore):信号量主要用于解决竞态条件,保护关键资源的访问。当多个进程需要访问同一资源时,可以使用信号量进行同步。
- 文件锁(File Locking):文件锁可以用于控制多个进程对同一文件的访问。当一个进程正在访问某个文件时,其他进程必须等待,直到该进程释放了文件锁。
cgroup 中限制 CPU 的方式有哪些
cgroups 是 control groups(控制组)的缩写,是 Linux 内核提供的资源管理机制,可以限制、控制和隔离进程使用的 CPU、内存、磁盘 I/O 等资源。 常见的 CPU 限制方式有两种:
- 基于 CPU 配额的硬限制:cgroup v1 使用
cpu.cfs_quota_us和cpu.cfs_period_us,cgroup v2 使用cpu.max,限制进程在一个周期内最多使用的 CPU 时间。 - 基于相对权重的限制:cgroup v1 使用
cpu.shares,cgroup v2 使用cpu.weight,用于 CPU 竞争时按比例分配资源,并不是绑定到固定的 CPU 核心。
内存中的 Buffers 与 Cached 的区别
设计目的是提升系统的 I/O 性能。
Buffers 是内核块设备缓冲区使用的内存,对应 /proc/meminfo 中的 Buffers 值。
Cache 是内核页缓存和可回收 Slab 使用的内存,对应 /proc/meminfo 中的 Cached 与 SReclaimable 等字段。
Buffers 是用于临时存储待写入硬盘的数据,而 Cached 是用于存储已经从硬盘读取的数据,以便快速访问。 Buffer 是对磁盘数据的缓存。而 Cache 是文件数据的缓存,它们既会用在读请求中,也会用在写请求中。
Linux是尽可能使用内存原则,内存会把剩余的空间申请为cache,而cache不属于free,当系统运行时间很长,我们会发现cache很大。
当我们看到系统内存使用率很高,free几乎为0时,并不代表系统内存容量有瓶颈!只是系统充分发挥了内存作用。而当有进程需要申请大文件内存时,内核会将部分cache空间回收,回收的内存再分配给进程程序使用。
栈内存和堆内存的区别
- 栈内存(Stack) 特点:栈内存是自动分配和释放的,具有先进后出(LIFO,Last In First Out)的特性。栈内存中的变量会在函数调用时创建,并在函数返回时自动销毁。其管理由编译器控制,因此效率较高。 用途:通常用于存储局部变量、函数参数等临时数据。栈内存的分配通常很快,因为它只是调整一个指针来跟踪当前的栈顶位置。 优点:内存分配和释放速度快,不容易产生内存碎片。 缺点:栈内存的大小通常有限,不能用于存储大量数据或长时间使用的数据。
- 堆内存(Heap) 特点:堆内存是动态分配的,大小不固定,需要程序员手动分配和释放。如果忘记释放,可能会导致内存泄漏。它没有严格的先进后出的顺序,可以在程序的任何位置请求内存分配。 用途:用于存储需要动态分配的大量数据,如对象、全局数据等。通过 malloc() 或 new 等操作分配,通过 free() 或 delete 等操作释放。 优点:适合长时间使用的数据或较大的数据结构,比如链表、树等。堆内存的大小相对栈来说几乎是无限的(受制于物理内存和系统限制)。 缺点:由于需要手动管理,堆内存分配和释放速度较慢,且容易导致内存碎片。
区别总结:
- 生命周期:栈内存中的数据在函数调用期间有效,而堆内存的数据在手动释放前一直有效。
- 分配方式:栈是由系统自动分配和管理,堆是由程序员动态分配和管理。
- 效率:栈内存效率高,堆内存分配和释放较慢
进程最大数、最大线程数、进程打开的文件数,怎么调整
查看当前限制
以下限制针对当前 Shell 或当前用户会话:
| |
调整最大文件数
临时生效 ulimit -n 65535
永久生效 sudo vim /etc/security/limits.conf
添加如下内容
- soft nofile 65535
- hard nofile 65535
调整最大进程数 / 最大线程数
临时生效 ulimit -u 65535
永久生效 sudo vim /etc/security/limits.conf
添加如下内容
- soft nproc 65535
- hard nproc 65535
注意事项
soft 软限制:当前会话实际生效的限制,用户可以将它提高到 hard 限制以内。 hard 硬限制:软限制可以达到的上限,通常只有 root 或具备相应权限的用户才能提高。
/etc/sysctl.conf 用于配置系统级内核参数,可通过 sysctl -p 立即加载,通常不需要重启。
/etc/security/limits.conf 用于配置用户级限制,通常需要重新登录才能对新会话生效;systemd 服务还需要在 unit 中配置对应的 LimitNOFILE、TasksMax 等参数。
Load 和 CPU 使用率的区别
Load 平均负载是指一段时间内,处于可运行状态(R)和不可中断睡眠状态(D)的任务数的平均值。 CPU 使用率是指一段时间内,CPU 用于处理任务的时间占总时间的比例。
最理想的情况:平均负载接近 CPU 核心数,每个核心上都有一个可运行任务。
| |
两者之间关系
- CPU 密集型进程,使用大量 CPU 会导致平均负载升高,此时这两者是一致的
- I/O 密集型进程,等待 I/O 也会导致平均负载升高,但 CPU 使用率不一定很高
- 大量等待 CPU 的进程调度也会导致平均负载升高,此时的 CPU 使用率也会比较高
du、df 查看磁盘结果不一致
系统中可能存在大量被删除的文件(僵尸文件),且有运行的进程在使用这些文件的句柄。
当一个文件被删除后,如果有进程仍然打开着该文件,du 不会统计这部分空间,因为文件已经从目录结构中移除;然而,df 会统计这部分空间,因为磁盘空间实际上还被占用。
解决方法
- 重启相关服务:重启仍持有文件句柄的进程,释放已删除文件占用的空间。生产环境应优先采用平滑重启。
- 查找并关闭进程:使用 lsof 或 fuser 等工具查找并关闭使用僵尸文件的进程。
1lsof | grep deleted - 如果暂时不能重启进程,可以结合业务情况,通过进程自身的日志切割或文件截断机制释放空间;不要重复删除已经显示为
deleted的文件。
硬链接和软链接的区别
硬链接和软链接是两种不同类型的文件系统链接,用于在目录之间共享文件。
硬链接:
a. 具有相同inode节点号的多个文件互为硬链接文件; b. 硬链接文件是文件的另一个入口 c. 可以通过给文件设置硬链接文件来防止重要文件被误删; d. 删除硬链接文件或者删除源文件,文件实体不会被删除,只有都删除才会生效
软连接:
a. 软链接类似windows系统的快捷方式 b. 软链接里面存放的是源文件的路径,指向源文件 c. 删除源文件,软链接依然存在,但无法访问源文件内容 d. 软链接和源文件是不同的文件,文件类型也不同,inode号也不同;
LVM 怎么划分
- 创建物理卷(PV)
- 创建卷组(VG)
- 创建逻辑卷(LV)
- 格式化逻辑卷(LV)
- 挂载逻辑卷(LV)
在公有云运维中,很少见到使用 LVM 划分云盘,这属于常见情况。
- 云盘可以直接扩容,不需要 LVM 的 PV/VG/LV
- 传统环境中,LVM 与 RAID 可以配合使用,但二者职责不同;云盘底层通常已经提供多副本和冗余能力
- Kubernetes 弱化了主机侧 LVM 的使用,容器数据通常通过 PVC 管理
常见的 RAID 有哪些,使用场景是什么
常见的 RAID 级别有以下几种:
- RAID 0:striping(条带化),将数据分成多个块,并行写入多个磁盘,提高读写速度。但不提供数据冗余,一旦磁盘故障,数据将丢失。
- RAID 1:mirroring(镜像),将数据在多个磁盘上进行镜像备份,提供数据冗余。但写入速度受限于较慢的磁盘。
- RAID 5:striping with parity(条带化加校验),将数据分成多个块,并行写入多个磁盘,同时存储校验信息,可容忍一块磁盘故障,但写入会产生额外的校验开销。
- RAID 6:striping with double parity(条带化加双校验),在 RAID 5 的基础上增加一组校验信息,可容忍两块磁盘故障。
使用场景:
- RAID 0:用于对性能要求较高的场景,如数据库、视频编辑等。
- RAID 1:用于对数据冗余要求较高的场景,如企业关键数据存储。
如何创建和管理自定义 systemd 服务
自定义服务配置文件位置:/etc/systemd/system/
创建或者修改单元文件后需要重新加载配置生效 sudo systemctl daemon-reload
Linux 系统中 /proc 是做什么的
用户和内核交互的接口,性能工具数据(top、free、ps)的来源
| |
/proc 中的部分文件使用 NUL 字符分隔内容,例如 cmdline,需要转换后才能按行阅读:
| |
lsof 命令使用场景
- 查看某个进程打开的文件 lsof -p 1234
- 查看哪个进程正在使用特定端口 lsof -i :80
- 查看所有网络连接 lsof -i
- 查看某个用户打开文件 lsof -u username
- 文件已经被删除,但仍然被某个进程占用 lsof | grep deleted
