记录生产一次linux负载高cpu使用率低的分析 [操作系统入门]
目录
- 前言
- load average定义
- 平均负载与CPU使用率关系
- case1:CPU密集型java应用
- case2:IO密集型java应用
- case2.1.磁盘IO密集型应用
- case2.2.网络IO密集型应用
- case3:线程上下文大量切换也会导致cpu使用率增高,平均负载也变高
- 总结
前言
本文记录下生产一次cpu使用率低,但是load average高的情况,如下两图,load average很高,但是cpu使用率很低
先说下这个机器配置:16C16G,用于jenkins构建服务器
通常指的load average是和cpu有关,cpu越高,load average越高,但是本次问题情况正好相反,问题出现在哪里? 是不是对平均负载理解的不正确呢?
load average定义
平均负载是指单位时间内,系统处于可运行状态和不可中断状态的平均进程数,也就是平均活跃进程数,它和CPU使用率并没有直接关系。
可运行状态的进程,是指正在使用CPU或者正在等待CPU的进程,也就是我们常用ps命令看到的,处于R状态(Running 或 Runnable)的进程。
不可中断状态的进程则是正处于内核态关键流程中的进程,并且这些流程是不可打断的,比如最常见的是等待硬件设备的I/O响应。
比如,当一个进程向磁盘读写数据时,为了保证数据的一致性,在得到磁盘回复前,它是不能被其他进程或者中断打断的,这个时候的进程就处于不可中断状态。如果此时的进程被打断了,就容易出现磁盘数据与进程数据不一致的问题。
因此前面自己的理解是错误的,比如1min内的平均负载load average指的是1min内正在使用CPU进程+正在等待CPU的进程+等待IO的进程,同理5min、15min也是如此计算。
但是,我们平时是java应用,一个应用开启多个线程,这个就涉及到线程和进程的关系了。
linux内进程就是我们ps -fe 看到的,线程是属于进程的,一个进程至少有一个线程,对于我们java应用来说,一个java进程通常有多个线程。线程又称为Light—Weight Process,cpu处理线程是使用分片法,线程也涉及到使用cpu资源和IO(线程向磁盘读写数据),因此平均负载也简单定义为1min内正在使用CPU线程+正在等待CPU的线程+等待IO的线程。
平均负载与CPU使用率关系
case1:对于CPU密集型java应用,并发高的情况下,cpu使用率飚高,此时load average也高,此时平均负载与CPU使用率是一致的。
case2:对于IO密集型java应用,由于等待IO响应的线程数增加,导致平均负载高,但是CPU使用率不一定高。
case3:线程上下文大量切换也会导致平均负载升高,此时的CPU使用率也会比较高。
下面对这三种情况以实际例子说明:
case1:CPU密集型java应用
对于case1,比如写个使用fastjson循环解析json字符串的应用,使用jmeter压测,cpu很容易飚高,查看到load average也变高。
比如下面这个代码,直接就把cpu打满了,在2C2G服务器上使用jmeter并发线程2,测试,load average在1,5min内是4.15, 2.29。
/** * 使用正则表达式让cpu达到100%,这个结果计算要15s
*/
@Override
public void cpuRegex() {
String regex = "(w+,?)+";
String val = "abcdefghijklmno,abcdefghijklmno+";
log.info("正则结果->{}", val.matches(regex));//val.matches耗费cpu
}
case2:IO密集型java应用
case2.1.磁盘IO密集型应用
对于case2,写个频繁写入和读取磁盘数据的应用,使用jmeter压测,使用iostat检测磁盘,查看到load average也变高。
测试代码如下
@Override public void io() {
try {
ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
URL url = (classLoader != null ?
classLoader.getResource("test-service.2020-01-09.log") :
ClassLoader.getSystemResource("test-service.2020-01-09.log"));
String logText = IOUtils.toString(url, Charset.forName("utf8"));//读取resources下的test-service.2020-01-09.log文件内
File targetFile = null;
String os = System.getProperty("os.name");
if (StrUtil.containsIgnoreCase(os, "linux")) {
targetFile = new File("/data/log/allocate/test-service-"+number.getAndIncrement()+".log");
} else {
targetFile = new File("D:dataallocate est-service-"+number.getAndIncrement()+".log");
}
boolean exists = targetFile.exists();
if (!exists) {
targetFile.createNewFile();
}
FileOutputStream out = new FileOutputStream(targetFile);
out.write(logText.getBytes("utf8"));//阻塞io操作,每次请求都写文件,而且是同步写的方式,这样磁盘IO就很大了
out.close();
}
catch (IOException ex) {
throw new IllegalArgumentException("Unable to load factories from location [" +
"test-service.2020-01-09.log" + "]", ex);
}
}
case2.2.网络IO密集型应用
上面是磁盘IO阻塞,那么如果是网络IO阻塞,是否会对平均负载造成影响呢?测试如下
测试代码
@Override public void socketIO() {
Socket socket = new Socket();
try {
socket.setSoTimeout(60000);//设置读取超时时间为60s
socket.setTcpNoDelay(true);
socket.connect(new InetSocketAddress("xxx.xxx.xxx.xxx", 80));//连接另外一个nginx服务器的80端口
InputStream in = socket.getInputStream();
byte[] b = new byte[1024];
int read = in.read(b);//阻塞在读上
} catch (IOException e) {
log.error("读取超时,异常{}", e.getMessage());
} finally {
try {
socket.close();
} catch (IOException e) {
log.error("socket关闭异常", e.getMessage());
}
}
}
在使用jmeter压测,发现此时平均负载很低,cpu也很低,说明网络阻塞并不会影响平均负载。
case3:线程上下文大量切换也会导致cpu使用率增高,平均负载也变高
比如下面这样代码,一次请求内线程阻塞了2次,释放了2次cpu资源使用,这样在并发下就会导致上下文切换频繁,线程上下文频繁切换可通过vmstat查看cs指标,这个在我并发200的测试条件下,线程上下文切换为3w多。
@Override public void cpuSwitch() {
try {
//业务代码
Thread.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
int i = 1+1;
//业务代码
Thread.yield();
int j = 1+1;
}
总结
平均负载可以基本认为=正在使用CPU+者正在等待CPU的进程+磁盘IO,对于一个4C8G的服务器,如果负载低于2.8,说明正常,超过的不多,先看cpu,再看io,通常cpu100%虽然平均负载高,但是不会高的很离谱,高的离谱了,比如自己测试的磁盘IO例子(同步向文件写数据),那么基本说明是磁盘IO问题。cpu高,可以通过jstack命令或show-busy-java-threads脚本来定位,io高只能通过iostat、iotop来定位。
总结下磁盘IO高的几个原因:
1.频繁的向磁盘写入或读取大量数据
2.磁盘坏了,磁盘性能不好(碎片太多,nfs磁盘)
对于我们生产这次平均负载增高,原因是虚机所在的母机上的一块磁盘坏了导致平均负载增高。
具体的cpu和io实战分析,请看另外的笔记 CPU和磁盘IO实战笔记总结
记录生产一次linux负载高cpu使用率低的分析
以上是 记录生产一次linux负载高cpu使用率低的分析 [操作系统入门] 的全部内容, 来源链接: utcz.com/z/519442.html