系统平均负载高(load average)

问题现象

  • 两个案例都是:系统平均负载高,但cpu,内存,磁盘io都正常

什么是系统平均负载

  • 平均负载是指单位时间内,系统处于可运行状态不可中断状态的平均进程数,也就是平均活跃进程数,它和CPU使用率并没有直接关系。

  • 可运行状态的进程,是指正在使用CPU或者正在等待CPU的进程,也就是我们常用ps命令看到的,处于R状态(Running 或 Runnable)的进程

  • 不可中断状态的进程则是正处于内核态关键流程中的进程,并且这些流程是不可打断的,比如最常见的是等待硬件设备的I/O响应,也就是我们在ps命令中看到的D状态(Uninterruptible Sleep,也称为Disk Sleep)的进程

负载高的常见情况

  • 我们常见的负载高一般有这几种情况引起,一个是cpu密集型,使用大量cpu会导致平均负载升高;

  • 另外一个就是io密集型等待I/O会导致平均负载升高,但是CPU使用率 不一定很高;

  • 还有就是大量等待CPU的进程调度也会导致平均负载升高,此时的CPU使用率也会比较高

问题分析

1、top:

2、vmstat:

可以看到r,cs和us较高

procs:

​ r 表示运行和等待CPU时间片的进程数,这个值如果长期大于系统CPU个数,说明CPU不足。

​ b 表示等待资源的进程数,比如正在等待I/O、或者内存交换等。

memory:算是正常

swap:

​ si 每秒从磁盘读入虚拟内存的大小,如果这个值大于0,表示物理内存不够或者内存泄露了,要查找耗内存进程解决掉。

​ so 每秒虚拟内存写入磁盘的大小,如果这个值大于0,同上。

​ 一般情况下,si、so的值都为0,如果si、so的值长期不为0,则表示内存不足。

IO:

​ bi 块设备每秒接收的块数量,这里的块设备是指系统上所有的磁盘和其他块设备,默认块大小是1024byte

​ bo 块设备每秒发送的块数量

​ 设置的bi+bo参考值为1000,如果超过1000,而且wa值较大,则表示系统磁盘IO有问题,应该考虑提高磁盘的读写性能。

system:

​ in 每秒CPU的中断次数,包括时间中断。(较高)

​ cs 每秒上下文切换次数(较高)

​ 这两个值越大,内核消耗的CPU就越多

cpu:

​ us 用户进程消耗的CPU时间百分比,us的值比较高时,说明用户进程消耗的cpu时间多,但是如果长期大于50%,就需要考虑优化程序或算法

​ sy 内核进程消耗的CPU时间百分比,sy值如果太高,说明内核消耗CPU资源很多,例如是IO操作频繁。

​ id CPU处于空闲状态的时间百分比。(cpu空闲)

​ wa io等待所占用的时间百分比,wa值越高,说明IO等待越严重,根据经验,wa的参考值为20%,如果wa超过20%,说明IO等待严重,引起IO等待的

​ 原因可能是磁盘大量随机读写造成的,也可能是磁盘或者磁盘控制器的带宽瓶颈造成的(主要是块操作)

通过上面的分析,发现主要是cpu每秒中断次数以及 上下文切换较高

3、iostat查看io情况

io无问题

4.1、使用pidstat分析上下文切换

上下文切换并没有发现特别高的进程,这与vmstat的现象不太吻合,没有找到是哪个进程导致的负载高

4.2使用pidstat -wt 1

pidstat -wt 1可以看到子进程的上下文切换,但并发现上下文切换较高的进程

解决问题

1、怀疑是docker引起的

但是将所有的docker停了以后并没有效果

过程中比较奇怪的是,使用df会一直卡住,但是df -lh可以正常访问

可以看到挂载了许多k8s的tmpfs

tmpfs默认的大小是RM的一半,假如你的物理内存是32GB,那么tmpfs默认的大小就是16GB。

tmpfs 的另一个主要的好处是它闪电般的速度。因为典型的tmpfs文件系统会完全驻留在内存RAM中,读写几乎可以是瞬间的。同时它也有一个缺点tmpfs数据在重新启动之后不会保留,这点与内存的数据特性是一致的。

2、分析进程信息

因为df打不开,怀疑是磁盘的问题

使用ps -aux,可以看到大量的D状态的进程,而且都是nfs文件系统的

仔细观察可以发现,这些D状态的进程基本都是在挂载 /var/lib/kublet/pods,就是在挂载k8s,但是一直是D状态,后面我们详细分析这个状态(TASK_UNINTERRUPTIBLE 不可中断的睡眠状态。)

3、kill掉D状态进程

kill掉D状态进程后load average就降下来了。但是df还是打不开,重启服务器后,df能正常打开。

想起上周排查的一个问题,也是各项指标都很正常,但是负载高达300+,当时排查时主要去分析状态为R的进程了,由于当时没有发现有R状态的进程也就没有排查出原因,后面陈老师说kill了一个系统的exporter进程后面负载就降下来了,今天分析日志发现原来这个node_exporter的进程状态也是一直为D状态。

4、系统日志

通过系统日志/var/log/messages可以看到确实有大量的nfs映射错误

Apr 10 04:48:12 node-1722516126 nfsidmap[11838]: nss_getpwnam: name 'root@nfs-provisioner.nfs-provisioner.svc.cluster.local' does not map into domain 'localdomain' Apr 10 04:48:12 node-1722516126 nfsidmap[11852]: nss_name_to_gid: name 'root@nfs-provisioner.nfs-provisioner.svc.cluster.local' does not map into domain 'localdomain' Apr 19 16:05:24 node-1722516126 kubelet: E0419 16:05:24.039993 43275 kubelet_volumes.go:154] orphaned pod "033d41bc-502b-4142-bfb4-deac0330dd8b" found, but volume paths are still present on disk : There were a total of 5 errors similar to this. Turn up verbosity to see them. Apr 19 16:05:26 node-1722516126 kubelet: E0419 16:05:26.054950 43275 kubelet_volumes.go:154] orphaned pod "033d41bc-502b-4142-bfb4-deac0330dd8b" found, but volume paths are still present on disk : There were a total of 5 errors similar to this. Turn up verbosity to see them. Apr 19 16:05:28 node-1722516126 kubelet: E0419 16:05:28.054644 43275 kubelet_volumes.go:154] orphaned pod "033d41bc-502b-4142-bfb4-deac0330dd8b" found, but volume paths are still present on disk : There were a total of 5 errors similar to this. Turn up verbosity to see them. Apr 19 16:05:30 node-1722516126 kubelet: E0419 16:05:30.054966 43275 kubelet_volumes.go:154] orphaned pod "033d41bc-502b-4142-bfb4-deac0330dd8b" found, but volume paths are still present on disk : There were a total of 5 errors similar to this. Turn up verbosity to see them. Apr 19 16:05:32 node-1722516126 kubelet: E0419 16:05:32.040576 43275 kubelet_volumes.go:154] orphaned pod "033d41bc-502b-4142-bfb4-deac0330dd8b" found, but volume paths are still present on disk : There were a total of 5 errors similar to this. Turn up verbosity to see them.

什么是D状态的进程

进程为什么会被置于uninterruptible sleep(D)状态呢?处于uninterruptible sleep(D)状态的进程通常是在等待IO,比如磁盘IO,网络IO,其他外设IO,如果进程正在等待的IO在较长的时间内都没有响应,那么就很会不幸地被 ps看到了,同时也就意味着很有可能有IO出了问题,可能是外设本身出了故障,也可能是比如挂载的远程文件系统已经不可访问了,我这里遇到的问题就是由 down掉的NFS服务器引起的。

正是因为得不到IO的相应,进程才进入了uninterruptible sleep状态,所以要想使进程从uninterruptible sleep状态恢复,就得使进程等待的IO恢复,比如如果是因为从远程挂载的NFS卷不可访问导致进程进入uninterruptible sleep状态的,那么可以通过恢复该NFS卷的连接来使进程的IO请求得到满足,除此之外,要想干掉处在D状态进程就只能重启整个Linux系统了。

关于进程状态

一、R TASK_RUNNING 可运行状态。如果一个进程处于该状态,那么说明它立刻就要或正在CPU上运行。不过运行的时机是不确定的,这有进程调度器来决定。

二、S TASK_INTERRUPTIBLE. 可中断的睡眠状态。当进程正在等待某个事件(比如网络连接或者信号量)到来时,会进入此状态。这样的进程会被放入对应事件的等待队列中。当事件发生时,对应的等待队列中的一个或者多个进程就会被唤醒。(大部分进程处于该状态)

三、D TASK_UNINTERRUPTIBLE 不可中断的睡眠状态。

与TASK_INTERRUPTIBLE状态类似,进程处于睡眠状态,但是此刻进程是不可中断的。不可中断,指的并不是CPU不响应外部硬件的中断,而是指进程不响应异步信号。

绝大多数情况下,进程处在睡眠状态时,总是应该能够响应异步信号的。否则你将惊奇的发现,kill -9竟然杀不死一个正在睡眠的进程了!于是我们也很好理解,为什么ps命令看到的进程几乎不会出现TASK_UNINTERRUPTIBLE状态,而总是TASK_INTERRUPTIBLE状态。

四、T TASK_STOPPED. 暂停状态或者跟踪状态。 向进程发送SIGSTOP信号,就会使该进程转入暂停状态,除非该进程正处于不可中断的睡眠状态。向正处于暂停状态的进程发送SIGCONT信号,会使该进程转向可运行状态。处于该状态的进程会暂停,并等待另一个进程(跟踪它的那个进程)对它进行操作。例如,我们使用调试工具GDB在某个程序中设置一个断点,然后对应的进程中运行到该断点处就会停下来。这时,该进程就处于跟踪状态。跟踪状态与暂停状态非常类似。但是,向处于跟踪状态的进程发送SIGCONT信号并不能使它恢复。只有当调试进程进行了相应的系统调用或者退出后才能恢复。

五、Z TASK_DEAD-EXIT_ZOMBIE 僵尸状态,处于此状态的进程即将结束运行,该进程占用的绝大多数资源也都已经被回收,不过还有一些信息未删除,比如退出码以及一些统计信息。之所以保留这些信息,可能是考虑到该进程的父进程需要这些信息。由于此时的父进程主体已经被删除而只留下一个空壳,故此状态才称为僵尸状态。

六、X TASK_DEAD-EXIT_DEAD 退出状态 在进程退出的过程中,有可能连退出码和统计信息都不需要保留。造成这种情况的原因可能是显式地让该进程的父进程忽略掉SIGCHILD信号,也可能是改进程已经被分离。分离后的子进程不会再使用和执行副进程共享的代码段中的指令,而是加载并运行一个全新的程序。在这些情况下,该进程的退出的时候就 不会转入僵尸状态,而会直接转入退出状态。处于退出状态的进程会立即被干净利落的结束掉,它占用的系统资源也会被操作系统自动回收。

在进程对某些硬件进行操作时(比如进程调用read系统调用对某个设备文件进行读操作,而read系统调用最终执行到对应设备驱动的代码,并与对应的物理设备进行交互),可能需要使用TASK_UNINTERRUPTIBLE状态对进程进行保护,以避免进程与设备交互的过程被打断,造成设备陷入不可控的状态。这种情况下的TASK_UNINTERRUPTIBLE状态总是非常短暂的,通过ps命令基本上不可能捕捉到。

进程为什么会被置于uninterruptible sleep状态呢?处于uninterruptiblesleep状态的进程通常是在等待IO,比如磁盘IO,网络IO,其他外设IO,如果进程正在等待的IO在较长的时间内都没有响应,那么就很会不幸地被ps看到了,同时也就意味着很有可能有IO出了问题,可能是外设本身出了故障,也可能是比如挂载的远程文件系统已经不可访问了(由down掉的NFS服务器引起的D状态)。

正是因为得不到IO的相应,进程才进入了uninterruptible sleep状态,所以要想使进程从uninterruptiblesleep状态恢复,就得使进程等待的IO恢复,比如如果是因为从远程挂载的NFS卷不可访问导致进程进入uninterruptiblesleep状态的,那么可以通过恢复该NFS卷的连接来使进程的IO请求得到满足。

D状态,往往是由于 I/O 资源得不到满足,而引发等待,在内核源码 fs/proc/array.c 里,其文字定义为“ "D (disk sleep)", /* 2 */ ”(由此可知 D 原是Disk的打头字母),对应着 include/linux/sched.h 里的“ #define TASK_UNINTERRUPTIBLE 2 ”。举个例子,当 NFS 服务端关闭之时,若未事先 umount 相关目录,在 NFS 客户端执行 df 就会挂住整个登录会话,按 Ctrl+C 、Ctrl+Z 都无济于事。断开连接再登录,执行 ps axf 则看到刚才的 df 进程状态位已变成了 D ,kill -9 无法杀灭。正确的处理方式,是马上恢复 NFS 服务端,再度提供服务,刚才挂起的 df 进程发现了其苦苦等待的资源,便完成任务,自动消亡。若 NFS 服务端无法恢复服务,在 reboot 之前也应将 /etc/mtab 里的相关 NFS mount 项删除,以免 reboot 过程例行调用 netfs stop 时再次发生等待资源,导致系统重启过程挂起。

参考资料:

https://unix.stackexchange.com/questions/16738/when-a-process-will-go-to-d-state

https://blog.csdn.net/chinalinuxzend/article/details/4288784

https://www.cnblogs.com/embedded-linux/p/7043569.html

https://developer.aliyun.com/article/25448

https://blog.csdn.net/arkblue/article/details/46862751

linux系统平均负载高(load average)的更多相关文章

  1. Linux系统平均负载3个数字的含义

    越来越多人开始接触Linux操作系统,从VPS到无线路由的刷机系统(如OpenWRT.Tomato),同时也必不可少地会在各式各样的探针和系统监测界面上看到"系统平均负载"或者&q ...

  2. 【转】Linux系统平均负载3个数字的含义

    文章作者:姜南(Slyar) 文章来源:Slyar Home (www.slyar.com) 转载请注明,谢谢合作. 越来越多人开始接触Linux操作系统,从VPS到无线路由的刷机系统(如OpenWR ...

  3. Linux系统下CPU使用(load average)梳理

    在平时的运维工作中,当一台服务器的性能出现问题时,通常会去看当前的CPU使用情况,尤其是看下CPU的负载情况(load average).对一般的系统来说,根据cpu数量去判断.比如有2颗cup的机器 ...

  4. 平均负载(Load average)

    load average 的含义平均负载(load average)是指系统的运行队列的平均利用率,也可以认为是可运行进程的平均数. top命令中load average显示的是最近1分钟.5分钟和1 ...

  5. 理解 Linux 的平均负载和性能监控

      在本文中,我们将解释 Linux 系统中最关键的管理任务之一——关于系统 / CPU 的负载load和平均负载Load average的性能监控. 首先来看所有的类 UNIX 系统中两个重要的表述 ...

  6. linux之平均负载(学习笔记非原创)

    什么是平均负载 [root@111 ~]# uptime 11:03:33 up 149 days, 17:34, 1 user, load average: 0.08, 0.05, 0.01 最后三 ...

  7. 【Linux性能调优一】观大局:系统平均负载load average

    要测试linux系统性能及调优,首先要从全局检查linux的平均负载 1.什么是平均负载 load average 系统平均负载,平均负载是指单位时间内,系统处于可运行状态和不可中断状态的平均进程数, ...

  8. 什么是系统平均负载(Load average)

    一.什么是系统平均负载(Load average)? 在Linux系统中,uptime.w.top等命令都会有系统平均负载load average的输出,那么什么是系统平均负载呢? Load Aver ...

  9. 怎么理解linux的平均负载及平均负载高后的排查工具

    什么是平均负载 平均负载可以对于我们来说及熟悉又陌生,但我们问平均负载是什么,但大部分人都回答说平均负载不就是单位时间内CPU使用率吗?其实并不是这样的,如果可以的话,可以 man uptime 来了 ...

随机推荐

  1. JS的箭头函数this作用域

    name="小刚"; let student={ name:"小明", printLog:function(){ // 这里绑定了顶层作用域,可以使用变量与方法 ...

  2. 转载:STL四种智能指针

    转载至:https://blog.csdn.net/K346K346/article/details/81478223 STL一共给我们提供了四种智能指针: auto_ptr.unique_ptr.s ...

  3. 那么如何使用WebSQL?

    我们需要做的第一步是通过使用"OpenDatabase"函数开放数据库,如下图所示.第一个参数是数据库的名称,接下来是版本,然后一个简单的文本标题,最后的是数据库的大小. var ...

  4. BGD(批量梯度下降)--学习笔记

    函数凸凹性: 用到的范数知识: 详细解释:每一个元素的平方再开方.补充损失函数: Huber Loss知识点 loss函数可以通过loss参数进行设置.SGDRegressor支持以下的loss函数: ...

  5. 洋桃电子之STM32

    1.ARM内核与分类 作者:知乎用户链接:https://www.zhihu.com/question/52915983/answer/258507276来源:知乎著作权归作者所有.商业转载请联系作者 ...

  6. [FireshellCTF2020]ScreenShooter 1

    此题关键在于理清逻辑,本地将url发送给服务器,服务器请求sereenshooter以后将结果返回 所以应该在服务器查看日志. 发现了PhantomJS 引擎一下 <!DOCTYPE html& ...

  7. 解决vscode开发react项目没有html标签自动补全

    怎么设置自动补全: 左下角齿轮按钮--设置-- 在搜索框中输入Include Languages,选择Emmet,并在Emmet:include language下点击在setting.json中编辑 ...

  8. js,nodejs如何判断文件是什么编码格式

    nodejs编码只支持utf8的编码方式,无论是打开某个文件或者写.js脚本都得以utf8的编码方式保存,不然程序无法运行,读出来的文件是乱码. 如果是在前台,读取文件是通过FileReader或者F ...

  9. JAVASE Scanner

    package com.huang.boke.flowPath;import java.util.Scanner;public class test01 { public static void ma ...

  10. Java学习day7

    Java继承不同与c++,格式为: public class 子类名 extends 父类名{ 语句体; } 继承提高了代码的复用性与维护性 在子类方法中访问一个变量时,首先在子类局部范围查找,其次到 ...