CPU高负载排查
本文将介绍如何排查 Linux 系统中 CPU 负载过高的问题。当系统的 CPU 负载过高时,可能会导致系统响应变慢、进程无响应等问题,影响系统的稳定性和性能。本文将从系统监控、进程分析、资源限制等方面介绍如何定位和解决 CPU 负载过高的问题。通过本文的介绍,读者将了解如何使用常用的工具和技术来排查 CPU 负载过高的问题,提高系统的稳定性和性能。
初级方法
进入系统中查看所有进程占用资源的详细情况,可以使用kubectl exec命令进入pod中的容器,并使用top或ps命令查看进程信息。
以下是具体步骤:
使用kubectl exec命令进入pod中的容器,例如:
kubectl exec -it <pod-name> -c <container-name> -- /bin/bash
这个命令可以进入pod中的指定容器,并打开一个交互式的bash终端。
在容器中使用top或ps命令查看进程信息,例如:
top
或者
ps aux
这些命令可以显示容器中所有进程的详细信息,包括进程ID、CPU和内存使用情况、进程状态等。
如果需要查看某个进程的详细信息,可以使用ps命令结合grep命令来查找进程,例如:
ps aux | grep <process-name>
这个命令可以查找容器中指定名称的进程,并显示其详细信息。
通过以上步骤,可以进入pod中查看所有进程占用资源的详细情况,并找出可能的性能瓶颈和优化方案。注意,在进入pod中查看进程信息时,需要确保容器中已经安装了相应的工具和命令,例如top和ps命令。
从监控上看cpu占用很高95%+,但是使用上面的top命令和ps aux都没有找到占用CPU比率超过5%的进程
如果从监控上看到CPU占用很高,但是使用top命令和ps aux命令没有找到占用CPU比率超过5%的进程,可能有以下几种情况:
- CPU占用率高的进程已经结束:在top命令和ps aux命令执行期间,可能有一些CPU占用率高的进程已经结束了,导致无法在进程列表中找到。可以使用历史监控数据来查看CPU占用率高的时间段,以找到可能的进程。
- CPU占用率高的进程是短暂的:有些进程可能只是短暂地占用了CPU资源,例如一些周期性的任务或者瞬时的请求处理。这些进程可能无法在top命令和ps aux命令中被捕捉到。可以使用更高级的监控工具来捕捉这些短暂的进程,例如perf和strace。
- CPU占用率高的进程是内核进程:有些CPU占用率高的进程可能是内核进程,例如中断处理、IO操作等。这些进程可能无法在用户空间的进程列表中被捕捉到。可以使用更高级的监控工具来查看内核进程的CPU占用率,例如sar和vmstat。
- CPU占用率高的进程是被隐藏的:有些恶意软件或者攻击可能会隐藏自己的进程,以避免被发现。这些进程可能无法在top命令和ps aux命令中被捕捉到。可以使用更高级的安全工具来检测和清除这些恶意进程,例如rkhunter和chkrootkit。
可以使用以下工具进一步跟踪:
perf命令:perf是一个Linux性能分析工具,可以用来分析CPU、内存、磁盘和网络等方面的性能问题。可以使用以下命令来查看CPU占用率高的进程:
perf top
这个命令可以显示CPU占用率高的进程和函数,以及相应的CPU时间和调用次数等信息。
strace命令:strace是一个Linux系统调用跟踪工具,可以用来跟踪进程的系统调用和信号处理等操作。可以使用以下命令来跟踪CPU占用率高的进程:
strace -p <pid>
这个命令可以显示进程的系统调用和信号处理等操作,以帮助你找出可能的性能瓶颈和优化方案。
sar命令:sar是一个Linux系统性能监控工具,可以用来收集和分析系统的CPU、内存、磁盘和网络等性能数据。可以使用以下命令来查看CPU占用率高的时间段:
sar -u <start-time> <end-time>
这个命令可以显示系统的CPU使用率和负载情况,以帮助你找出可能的性能瓶颈和优化方案。
vmstat命令:vmstat是一个Linux虚拟内存统计工具,可以用来收集和分析系统的CPU、内存、磁盘和网络等性能数据。可以使用以下命令来查看CPU占用率高的时间段:
vmstat <interval> <count>
这个命令可以显示系统的CPU使用率、内存使用率和磁盘IO情况等,以帮助你找出可能的性能瓶颈和优化方案。
htop命令:htop是一个交互式的进程监控工具,可以用来查看进程的CPU、内存和IO等使用情况。可以使用以下命令来查看CPU占用率高的进程:
htop
这个命令可以显示进程的CPU使用率、内存使用率和IO情况等,以帮助你找出可能的性能瓶颈和优化方案。
在 htop
命令中,time+
列显示的是进程的累计 CPU 时间,包括用户态和内核态的 CPU 时间。当进程的累计 CPU 时间超过1小时时,htop
会将时间格式化为 1h08:30
的形式,其中 1h
表示1小时,08:30
表示剩余的分钟和秒数。
例如,如果一个进程的 time+
列显示为 1h08:30
,表示该进程的累计 CPU 时间为1小时8分30秒。如果一个进程的 time+
列显示为 00:01:30
,表示该进程的累计 CPU 时间为1分30秒。
需要注意的是,htop
中的 time+
列显示的是累计 CPU 时间,并不是实际的运行时间。如果一个进程在某个时间段内没有占用 CPU,那么它的 time+
列也不会增加。因此,time+
列并不能完全反映进程的运行时间,只能作为一个参考指标。
磁盘和内存占用情况
在 Linux 系统中,可以使用以下命令来查看文件的磁盘占用情况:
ls
命令:该命令可以列出文件的详细信息,包括文件大小和修改时间等。例如,使用以下命令可以列出当前目录下所有文件的详细信息:ls -l
在输出结果中,第5列为文件大小,以字节为单位。
du
命令:该命令可以查看文件或目录的磁盘占用情况。例如,使用以下命令可以查看当前目录下所有文件的磁盘占用情况:du -h
在输出结果中,第1列为文件或目录的磁盘占用大小,以人类可读的格式显示(例如,KB、MB、GB 等)。
df
命令:该命令可以查看文件系统的磁盘占用情况。例如,使用以下命令可以查看当前系统中所有文件系统的磁盘占用情况:df -h
在输出结果中,第3列为文件系统的总容量,第4列为已使用的容量,第5列为可用的容量,第6列为使用率。
需要注意的是,以上命令都可以通过参数来指定要查看的文件或目录。例如,使用 ls -l /path/to/file
命令可以查看指定文件的详细信息,使用 du -h /path/to/directory
命令可以查看指定目录的磁盘占用情况。
你可以使用 du
命令来按目录维度展示内存占用情况。du
命令可以查看文件或目录的磁盘占用情况,并支持按照目录层级展示结果。
以下是按目录维度展示内存占用的示例命令:
du -h --max-depth=1 /path/to/directory
在上面的命令中,-h
选项表示以人类可读的格式显示结果,--max-depth=1
选项表示只展示一级目录的结果,/path/to/directory
是要查看的目录路径。
如果要展示多级目录的结果,可以将 --max-depth
选项的值设置为相应的层级数。例如,要展示两级目录的结果,可以使用以下命令:
du -h --max-depth=2 /path/to/directory
需要注意的是,du
命令默认会递归地查看目录下所有子目录的磁盘占用情况,因此在查看大型目录时可能需要等待一段时间。如果只想查看目录本身的磁盘占用情况,可以使用 -s
选项。例如,使用以下命令可以查看 /path/to/directory
目录本身的磁盘占用情况:
du -h -s /path/to/directory
/sys/fs/cgroup
目录是 Linux 内核中的一个虚拟文件系统,用于管理 cgroup。cgroup 是一种 Linux 内核特性,用于限制和隔离进程的资源使用,包括 CPU、内存、磁盘等资源。
在 /sys/fs/cgroup
目录下,每个子目录都代表一个 cgroup,其中包含了该 cgroup 的资源限制和统计信息。例如,/sys/fs/cgroup/memory
目录下包含了内存限制和统计信息,/sys/fs/cgroup/cpu
目录下包含了 CPU 限制和统计信息,/sys/fs/cgroup/blkio
目录下包含了磁盘 I/O 限制和统计信息等。
因此,/sys/fs/cgroup
目录中的信息反映的是 cgroup 中的资源使用情况,包括内存、CPU、磁盘等资源。在上面的代码中,/sys/fs/cgroup/memory
目录用于获取容器的内存使用情况,包括内存限制、内存使用量和内存统计信息。
/sys/fs/cgroup
目录下的内存信息只能代表当前 cgroup 的内存使用情况,不能代表整个 pod 的内存使用量。一个 pod 可能包含多个容器,每个容器都有自己的 cgroup,因此需要分别获取每个容器的内存使用情况,才能得到整个 pod 的内存使用量。
在 Kubernetes 中,可以通过 kubectl top pod
命令来获取 pod 的 CPU 和内存使用情况。该命令会返回每个容器的 CPU 和内存使用量,以及整个 pod 的 CPU 和内存使用量。该命令的实现原理是通过调用 Kubernetes API 获取容器的 CPU 和内存使用情况,然后将其汇总计算得到整个 pod 的 CPU 和内存使用量。
因此,如果需要获取整个 pod 的内存使用量,建议使用 kubectl top pod
命令或者调用 Kubernetes API 来获取容器的内存使用情况,并将其汇总计算得到整个 pod 的内存使用量。
如果您从当前 pod 的控制台进入 /sys/fs/cgroup
目录,那么您所看到的 /sys/fs/cgroup/memory
目录下的内存信息将代表当前 pod 的内存使用量。这是因为在 pod 内部,每个容器都会有自己的 cgroup,并且 pod 的 cgroup 会包含所有容器的 cgroup。
因此,当您在当前 pod 的控制台中查看 /sys/fs/cgroup/memory
目录下的内存信息时,您将看到当前 pod 中所有容器的内存使用情况的汇总。这包括每个容器的内存限制、内存使用量和内存统计信息。
请注意,这仅适用于当前 pod 内部的视角。如果您想获取整个 pod 的内存使用量,您需要在 pod 所在的宿主机上查看相应的资源使用情况,或者使用 Kubernetes API 或相关工具来获取整个 pod 的内存使用量。
cgroup 是 Linux 内核中的一种特性,用于限制和隔离进程的资源使用,包括 CPU、内存、磁盘等资源。cgroup 可以将一组进程组织成一个 cgroup,然后对该 cgroup 中的进程进行资源限制和统计。
在 Linux 中,cgroup 通过虚拟文件系统来实现。cgroup 的虚拟文件系统通常被挂载在 /sys/fs/cgroup
目录下。该目录下的子目录代表不同的 cgroup 类型,例如 cpu
、memory
、blkio
等。每个 cgroup 类型下又包含了多个 cgroup,每个 cgroup 代表一个 cgroup 实例。
在 /sys/fs/cgroup
目录下,每个 cgroup 实例都有自己的一组虚拟文件,用于限制和统计该 cgroup 中进程的资源使用情况。例如,在 memory
cgroup 中,可以通过 memory.limit_in_bytes
文件来限制 cgroup 中进程的内存使用量,通过 memory.usage_in_bytes
文件来统计 cgroup 中进程的内存使用量。
/sys/fs
目录是 Linux 中的一个虚拟文件系统,用于提供文件系统相关的信息和接口。/sys/fs/cgroup
目录下的虚拟文件系统是 sysfs
文件系统的一个子目录,用于提供 cgroup 相关的信息和接口。因此,fs
在 /sys/fs/cgroup
中代表 sysfs
文件系统。
在 Linux cgroup 中,当进程的内存使用率高时,所指的内存通常是虚拟内存,而不一定是系统实际的物理内存。
虚拟内存是一种抽象概念,它将进程的地址空间划分为多个虚拟页面,每个页面可以映射到物理内存、磁盘交换空间或其他设备。进程使用的内存可以超过系统实际可用的物理内存大小,因为虚拟内存允许将未使用的页面交换到磁盘上,以释放物理内存供其他进程使用。
在 cgroup 中,内存使用率通常是基于虚拟内存的统计。例如,memory.usage_in_bytes
文件中记录的是进程使用的虚拟内存大小,而不是实际占用的物理内存大小。因此,当 cgroup 中进程的内存使用率高时,表示进程正在使用较多的虚拟内存资源。
要了解系统实际的物理内存使用情况,需要综合考虑所有进程的虚拟内存使用情况、系统缓存、内核使用的内存等因素。可以使用工具如 free
、top
、htop
等来查看系统的物理内存使用情况。
分析实例
htop工具分析出以下数据
op - 10:12:52 up 3 days, 5:29, 0 users, load average: 12.97, 13.51, 13.64
Tasks: 8 total, 1 running, 7 sleeping, 0 stopped, 0 zombie
%Cpu0 : 39.9/60.1 100[|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||] %Cpu1 : 37.7/62.3 100[|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||]
GiB Mem : 34.8/3.8 [ ]
GiB Swap: 0.0/0.0 [ ]
PID USER PR NI VIRT RES %CPU %MEM TIME+ S COMMAND
1 root 20 0 0.8m 0.0m 0.0 0.0 0:03.46 S tini -- docker-entrypoint.sh
7 root 20 0 2.3m 1.7m 0.0 0.0 0:00.00 S `- /bin/bash /bin/docker-entrypoint.sh
83 root 20 0 1.6m 0.0m 0.0 0.0 0:03.60 S `- tail -f /dev/null
82 root 20 0 1.6m 0.7m 0.0 0.0 0:01.28 S `- crond
99542 root 20 0 700.1m 16.3m 0.0 0.4 0:04.83 S `- ./bin/zhiyan-log-docker-conf -config-file config/system/confd.toml
99558 root 20 0 756.9m 72.8m 0.0 1.9 0:06.59 S `- ./bin/zhiyan-log-docker-agent -c ./config/user/filebeat.yaml
134993 root 20 0 2.5m 2.2m 0.0 0.1 0:00.00 S /bin/bash
从top命令输出来看,CPU占用率非常高,,负载均衡也很高,也就是load average的值非常高,分别为12.97、13.51和13.64。load average是系统负载的一个指标,它表示在过去1分钟、5分钟和15分钟内,系统中平均有多少个进程处于就绪状态或者等待资源状态。一般来说,load average的值越高,表示系统的负载越大,CPU利用率也越高但是没有一个进程占用了大量的CPU资源。这种情况可能是由于多个进程共同占用了CPU资源,导致CPU占用率高但是没有一个进程占用大量CPU资源。
正常的load average的值的区间取决于系统的硬件配置、负载情况和应用程序的特性等因素。一般来说,如果系统的load average值在CPU核心数的1-2倍之间,表示系统的负载比较正常。例如,如果系统有4个CPU核心,那么load average值在4-8之间是比较正常的。如果load average值超过了CPU核心数的2倍,表示系统的负载比较高,需要进一步分析和优化。
另外,从%Cpu(s)的输出来看,CPU利用率也非常高,us和sy的值分别为38.1%和61.5%,表示CPU的大部分时间都在处理用户进程和系统进程。这也说明了为什么load average的值非常高。
详细分析进程
在Linux系统中是如何区分区分系统进程和用户进程的呢?每个进程都有一个UID,用来标识进程所属的用户。系统进程通常是由root用户或其他系统用户启动的,它们的UID为0或其他系统用户的UID。这些进程通常是用来管理系统资源、执行系统任务、提供系统服务等,例如init进程、systemd进程、sshd进程等。用户进程通常是由普通用户启动的,它们的UID为普通用户的UID。这些进程通常是用来执行用户任务、运行应用程序等,例如浏览器进程、编辑器进程、编译器进程等。
可以使用ps命令或top命令来查看进程的UID和其他信息,例如:
ps aux | grep <进程名>
其中,<进程名>是要查找的进程名。执行该命令后,会输出进程的UID、PID、CPU占用率、内存占用率等信息。通过查看进程的UID,可以区分系统进程和用户进程。
我们看到python进程占有CPU相对高,那么进一步排查它,我们先在inux查看python进程占用端口的进程活跃情况,是否有请求进来
使用netstat命令来查看某个端口的进程活跃情况和是否有请求进来。下面是netstat命令的使用方法:
查看某个端口的进程活跃情况:
netstat -tlnp | grep <port>
其中,
是要查看的端口号。执行该命令后,会输出所有监听该端口的进程信息,包括进程的PID、进程名、协议等。 查看某个端口的请求情况:
netstat -anp | grep <port>
其中,
是要查看的端口号。执行该命令后,会输出所有与该端口建立的连接信息,包括本地IP地址、本地端口号、远程IP地址、远程端口号、连接状态等。
由于端口8000正在被Python进程占用,并且该进程正在监听该端口。这意味着该端口已经被占用,但是当前并没有任何连接建立。
如果你想查看该端口是否有请求进来,可以使用类似以下命令:
复制tcpdump -i any port 8000
该命令会在终端中输出所有与端口8000建立的连接信息,包括本地IP地址、本地端口号、远程IP地址、远程端口号、连接状态等。需要注意的是,tcpdump命令需要root权限才能执行。
[root@postpay-lifecyclemgr-intl-2255-0 /]# tcpdump -i any port 8000
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on any, link-type LINUX_SLL (Linux cooked), capture size 262144 bytes
19:58:01.665950 IP localhost.59584 > localhost.irdmi: Flags [S], seq 985772684, win 65535, options [mss 65495,sackOK,TS val 3005806978 ecr 0,nop,wscale 9], length 0
19:58:01.665969 IP localhost.irdmi > localhost.59584: Flags [S.], seq 2185908257, ack 985772685, win 65535, options [mss 65495,sackOK,TS val 3005806978 ecr 3005806978,nop,wscale 9], length 0
19:58:01.665985 IP localhost.59584 > localhost.irdmi: Flags [.], ack 1, win 128, options [nop,nop,TS val 3005806978 ecr 3005806978], length 0
19:58:01.666064 IP localhost.59584 > localhost.irdmi: Flags [P.], seq 1:83, ack 1, win 128, options [nop,nop,TS val 3005806978 ecr 3005806978], length 82
19:58:01.666072 IP localhost.irdmi > localhost.59584: Flags [.], ack 83, win 128, options [nop,nop,TS val 3005806978 ecr 3005806978], length 0
19:58:01.667408 IP localhost.irdmi > localhost.59584: Flags [P.], seq 1:175, ack 83, win 128, options [nop,nop,TS val 3005806980 ecr 3005806978], length 174
19:58:01.667418 IP localhost.59584 > localhost.irdmi: Flags [.], ack 175, win 131, options [nop,nop,TS val 3005806980 ecr 3005806980], length 0
据tcpdump命令输出来看,该端口正在接收来自本地IP地址为localhost、本地端口号为59584的TCP连接请求。该连接请求的目的地是本地IP地址为localhost、目标端口号为irdmi的TCP端口。同时,该连接请求的标志位为S,表示该连接请求是一个同步请求。
如果你想查看更多关于该连接请求的信息,可以使用类似以下命令:
tcpdump -i any port 8000 -nnvvS
该命令会在终端中输出更详细的关于连接请求的信息,包括源IP地址、源端口号、目的IP地址、目的端口号、标志位等。需要注意的是,该命令的输出比较详细,可能会比较难以理解。
从
tcpdump命令输出的结果可以看到端口的请求并不活跃,由此可得出CPU高的原因可能不是它
分析定时任务
在Linux系统中,可以使用crontab命令来管理定时任务。下面是一些常用的crontab命令:
查看当前用户的定时任务:
crontab -l
该命令会列出当前用户的所有定时任务。
编辑当前用户的定时任务:
crontab -e
该命令会打开当前用户的定时任务配置文件,你可以在该文件中添加、修改或删除定时任务。
删除当前用户的所有定时任务:
crontab -r
该命令会删除当前用户的所有定时任务。
需要注意的是,crontab命令只能管理当前用户的定时任务,如果你想查看其他用户的定时任务,需要使用root权限执行crontab命令。另外,定时任务的配置文件通常位于/var/spool/cron目录下,你可以使用类似以下命令来查看该目录下的所有定时任务文件:
ls -l /var/spool/cron
据定时任务配置,以下是每个任务的周期和频率:
/1 * * * *
表示每分钟执行一次,即每分钟的第0秒执行/usr/local/bin/cpu_usage_updater.py &>/dev/null
命令。/1 * * * *
表示每分钟执行一次,即每分钟的第0秒执行chmod a+w /dev/shm/.pkgadmin.cron.lck
命令。*/2 * * * *
表示每2分钟执行一次,即每2分钟的第0秒执行bash /data/release/bill-assistant/console_health_check.sh
命令。* * * * *
表示每分钟执行一次,即每分钟的第0秒执行chown -R user_00:users /data/release/postpay-lifecyclemgr-intl/
和chown -R user_00:users /data/log/postpay-lifecyclemgr-intl/
命令。0 0 * * *
表示每天的0点0分执行一次,即每天的0点0分执行cat /dev/null > /data/log/php-7_2_1-swoole_4_5_1_qbilling-1.0/php_errors.log
命令。
需要注意的是,定时任务的周期和频率可以通过修改crontab配置文件来调整。如果你想修改定时任务的周期和频率,可以使用 crontab -e
命令编辑crontab配置文件,并按照crontab语法修改相应的定时任务配置。
要修改crontab并使其生效,你需要执行以下步骤:
- 使用
crontab -e
命令编辑当前用户的定时任务配置文件。 - 修改定时任务的周期和命令,并保存文件。
- 确认定时任务配置文件已经保存,并退出编辑器。
重启cron服务,使新的定时任务配置生效。你可以使用以下命令重启cron服务:
sudo systemctl restart cron
如果你的系统不是基于systemd的,可以使用以下命令重启cron服务:
sudo service cron restart
重启cron服务后,新的定时任务配置就会生效。
需要注意的是,修改定时任务配置文件后,新的定时任务不会立即生效,而是要等待cron服务下一次执行定时任务时才会生效。如果你想立即执行新的定时任务,可以手动执行一次定时任务,或者重启cron服务。另外,如果你修改了root用户的定时任务配置文件,需要使用root权限执行以上操作。
查看日志技巧
在Linux系统中,可以使用以下命令来查看日志文件:
tail
命令:该命令可以实时查看日志文件的最新内容。例如,使用以下命令可以查看/var/log/messages
文件的最后10行内容:复制tail /var/log/messages
如果想实时查看日志文件的最新内容,可以使用
-f
选项。例如,使用以下命令可以实时查看/var/log/messages
文件的最新内容:复制tail -f /var/log/messages
less
命令:该命令可以分页查看日志文件的内容,并支持搜索。例如,使用以下命令可以查看/var/log/messages
文件的内容:复制less /var/log/messages
在
less
命令中,可以使用/
命令来搜索关键字。例如,输入/error
可以搜索包含error
关键字的内容。grep
命令:该命令可以搜索指定文件中包含指定关键字的行。例如,使用以下命令可以搜索/var/log/messages
文件中包含error
关键字的行:复制grep "error" /var/log/messages
如果想搜索多个文件,可以使用通配符
*
。例如,使用以下命令可以搜索/var/log
目录下所有以messages
开头的文件中包含error
关键字的行:复制grep "error" /var/log/messages*
需要注意的是,日志文件通常存储在 /var/log
目录下,不同的日志文件对应不同的应用程序或系统组件。在查看日志文件时,需要根据实际情况选择相应的日志文件,并使用合适的命令进行查看和搜索。