CPU、Load、内存及网络等系统指标异常的排查

背景

日常工作中,在衡量服务器的性能时,经常会涉及到几个系统指标,load、cpu、mem、qps、rt等。每个指标都有其独特的意义,很多时候在线上出现问题时,往往会伴随着某些指标的异常。大部分情况下,在问题发生之前,某些指标就会提前出现异常。

对于这些指标的理解、查看以及异常解决方法是程序员的必备技能。本文主要介绍一下这几个系统指标——系统负载(load)、cpu利用率、内存使用率、网络指标。

系统指标异常分类

  • CPU使用率分析和异常排查
  • 系统负载(load)分析和异常排查
  • 内存使用率分析和异常排查
  • 网络IO分析和异常排查

1 CPU使用率分析和异常排查

1.1 什么是CPU使用率

什么是CPU时间片?我们现在所使用的Windows、Linux、Mac OS X都是“多任务操作系统”,就是说他们可以“同时”运行多个程序,比如一边打开Chrome浏览器浏览网页还能一边听音乐。但是,实际上一个CPU内核在同一时刻只能干一件事,那操作系统是如何实现“多任务”的呢?大概的方法是让多个进程轮流使用CPU一小段时间,由于这个“一小段时间”很短(在linux上为5ms-800ms之间),用户感觉不到。就好像是几个程序同时在运行了。上面提到的“一小段时间”就是我们所说的CPU时间片,CPU的现代分时多任务操作系统对CPU都是分时间片使用的。

CPU使用率,就是程序对CPU时间片的占用情况,即CPU使用率 = CPU时间片被程序使用的时间 / 总时间。比如A进程占用10ms,然后B进程占用30ms,然后空闲60ms,再又是A进程占10ms,B进程占30ms,空闲60ms,如果在一段时间内都是如此,那么这段时间内的CPU占用率为40%。

大多数操作系统的CPU占用率分为用户态CPU使用率和系统态CPU使用率。用户态CPU使用率是指执行应用程序代码的时间占总CPU时间的百分比。相比而言,系统态CPU使用率是指应用执行操作系统调用的时间占总CPU时间的百分比。系统态的CPU使用率高意味着共享资源有竞争或者I/O设备之间有大量的交互

1.1.1 TOP命名查看CPU使用率

参数详解

top命令中常用列的排序方式如下,CPU和内存是实践中最常用的排序方式

  • M 根据驻留内存大小进行排序。
  • P 根据CPU使用百分比大小进行排序。

注意以上字母都是大写。

注:96.0id,表示空闲CPU,即CPU未使用率,100%-96.0%=4%,即系统的cpu使用率为4%。

如果要查看每个处理器核心的CPU占用情况,在top页面按下数字1即可展示每个核的CPU占用率,如下图所示共有4个核。

1.1.2 查看CPU信息

总核数 = 物理CPU个数 X 每颗物理CPU的核数
总逻辑CPU数 = 物理CPU个数 X 每颗物理CPU的核数 X 超线程数

查看物理CPU个数
cat /proc/cpuinfo| grep “physical id”| sort | uniq| wc -l

查看每个物理CPU中core的个数(即核数)
cat /proc/cpuinfo| grep “cpu cores” | uniq

查看逻辑CPU的个数
cat /proc/cpuinfo| grep “processor”| wc -l

1.2 CPU使用率突然飙升怎么办

常见原因大约有三类

  • 宿主机CPU超卖
  • 内存问题,导致大量Full GC
  • 代码存在死循环

1.2.1 宿主机CPU超卖排查

top结果信息中的cpu st的值,即宿主机cpu时间片分配给宿主机上其他虚拟机时间占比。如果st使用率较大,则cpu占用飙升是由于宿主机超卖导致,联系运维解决。

1.2.2 Full GC排查

打开应用监控,查看Full GC与Young GC次数,如果发现的确存在频繁的Full GC,Dump应用的堆内存,对零内存进行分析,定位异常代码,jmap及jstat命令查看jvm的GC情况。

查看进程堆使用概况

使用jmap -heap pid命令查看进程堆内存使用情况,包括使用的GC算法、堆配置参数和各代中堆内存使用情况。示例如下:

jmap -heap 2294

using parallel threads in the new generation. ##新生代采用的是并行线程处理方式
using thread-local object allocation.
Concurrent Mark-Sweep GC ##同步并行垃圾回收

可以发现以上示例中老年代的的内存使用率为18.6%

通过./jinfo -flags pid命令可以查看FGC(老年代垃圾回收)的阈值,示例如下:

./jinfo -flags 4289

根据以上结果可知,80%是FGC的触发阈值,只要老年代的内存超过80%就会触发FGC。

查看GC次数及时间

jstat -gc 2294
  • S0C:第一个幸存区的大小 (字节)
  • S1C:第二个幸存区的大小 (字节)
  • S0U:第一个幸存区的使用大小 (字节)
  • S1U:第二个幸存区的使用大小 (字节)
  • EC:伊甸园区的大小 (字节)
  • EU:伊甸园区的使用大小 (字节)
  • OC:老年代大小 (字节)
  • OU:老年代使用大小 (字节)
  • MC:方法区大小 (字节)
  • MU:方法区使用大小 (字节)
  • CCSC:压缩类空间大小 (字节)
  • CCSU:压缩类空间使用大小 (字节)
  • YGC:年轻代垃圾回收次数
  • YGCT:年轻代垃圾回收消耗时间(s)
  • FGC:老年代垃圾回收次数
  • FGCT:老年代垃圾回收消耗时间(s)
  • GCT:垃圾回收消耗总时间(s)

堆内存统计

jstat -gccapacity 2294
  • NGCMN:新生代最小容量
  • NGCMX:新生代最大容量
  • NGC:当前新生代容量
  • S0C:第一个幸存区大小
  • S1C:第二个幸存区的大小
  • EC:伊甸园区的大小
  • OGCMN:老年代最小容量
  • OGCMX:老年代最大容量
  • OGC:当前老年代大小
  • OC:当前老年代大小
  • MCMN:最小元数据容量
  • MCMX:最大元数据容量
  • MC:当前元数据空间大小
  • CCSMN:最小压缩类空间大小
  • CCSMX:最大压缩类空间大小
  • CCSC:当前压缩类空间大小
  • YGC:年轻代gc次数
  • FGC:老年代GC次数

新生代垃圾回收统计

jstat -gcnew 2294
  • S0C:第一个幸存区大小
  • S1C:第二个幸存区的大小
  • S0U:第一个幸存区的使用大小
  • S1U:第二个幸存区的使用大小
  • TT:对象在新生代存活的次数
  • MTT:对象在新生代存活的最大次数
  • DSS:期望的幸存区大小
  • EC:伊甸园区的大小
  • EU:伊甸园区的使用大小
  • YGC:年轻代垃圾回收次数
  • YGCT:年轻代垃圾回收消耗时间

老年代垃圾回收统计

jstat -gcold 2294
  • MC:方法区大小
  • MU:方法区使用大小
  • CCSC:压缩类空间大小
  • CCSU:压缩类空间使用大小
  • OC:老年代大小
  • OU:老年代使用大小
  • YGC:年轻代垃圾回收次数
  • FGC:老年代垃圾回收次数
  • FGCT:老年代垃圾回收消耗时间
  • GCT:垃圾回收消耗总时间

总体的垃圾回收情况统计

jstat -gcutil 2294
  • S0:幸存1区当前使用比例
  • S1:幸存2区当前使用比例
  • E:伊甸园区使用比例
  • O:老年代使用比例
  • M:元数据区使用比例
  • CCS:压缩使用比例
  • YGC:年轻代垃圾回收次数
  • FGC:老年代垃圾回收次数
  • FGCT:老年代垃圾回收消耗时间(s)

以下命令每1000毫秒收集一次JVM内存和GC信息,共收集100次,每隔5行显示一次标题,且标题行带时间戳

jstat -gcutil -t -h5 2294 1000 100

类加载统计

jstat -class 2294
  • Loaded:加载class的数量
  • Bytes:所占用空间大小(字节)
  • Unloaded:未加载数量
  • Bytes:未加载占用空间
  • Time:时间(s)

查看JVM内存占用情况的各种命令总结

## 类加载情况情况
/java/bin/jstat -class pid

##查看总体的垃圾回收情况
/java/bin/jstat -gcutil pid
##查看年轻代垃圾回收情况
/java/bin/jstat -gcnew pid
##查看年轻代垃圾回收情况
/java/bin/jstat -gcold pid    
##查看年轻代内存统计
/java/bin/jstat -gnewcapacity pid
##查看老年代内存统计
/java/bin/jstat -gcoldcapacity pid

##每1000毫秒收集一次JVM内存和GC信息,共收集100次
##每隔5行显示一次标题,且标题行带时间戳
/java/bin/jstat -gcutil -t -h5 pid 1000 100


##查看指定进程堆内存使用概况
/java/bin/jmap -heap pid
##查看指定进程堆内存中的对象数量及大小
/java/bin/jmap -histo pid
##找到堆中占用内存空间最多的前30个类
/java/bin/jmap -histo pid | head -30

1.2.3 理解GC日志

以下贴一段Minor GC的日志信息

最前面的2020-08-21T10:18:16.335+0800: 750587.747:是固定的,2020-08-21T10:18:16.335+0800表示GC发生的日期时间,750587.747表示本次gc与JVM启动时的相对时间,单位为秒。

括号中的Allocation Failure表示gc的原因,新生代内存不足而导致新对象内存分配失败。再后面的[ParNew:表示本次GC使用的垃圾收集器为ParNew,我们知道ParNew是针对新生代的垃圾收集器,从这可以看出本次GC是Minor GC。

1760204K->34570K(1922432K)含义是“GC前该内存区域已使用容量->GC后该内存区域已使用容量(该内存区域总容量)”,2242167K->516569K(4019584K)含义是“GC前Java堆已使用容量->GC后Java堆已使用容量(Java堆总容量)”

本次GC后,堆内存大小从2242167K变成516569K,总体内存变小,释放了1685.15M(约1.6456G),年轻代大小从1760204K变成34570K,释放1685.19M,那么老年代内存增加了36K。

最后的[Times: user=0.11 sys=0.00, real=0.04 secs]表示GC事件在不同维度的耗时,单位为秒。这里面的user、sys和real与Linux的time命令所输出的时间含义一致,分别表示用户态消耗的CPU时间、内核态消耗的CPU时间和操作从开始到结束所经过的等待耗时,例如等待磁盘I/O、等待线程阻塞,而CPU时间不包括这些耗时,但当系统有多CPU或者多核的话,多线程操作会叠加这些CPU时间,所以有时候user或sys时间超过real时间也是完全正确的。

1.2.4 代码死循环排查

需要先定位到占用大量cpu时间片的java线程,然后排查对应线程的代码定位原因,具体步骤如下:
Step1.使用top命令找到CPU占用最高的线程(PID为进程ID),看一下是否为java进程

Step2. 查看CPU占比靠前的java线程,其中的PID为子进程ID,即java线程ID

top -p 3209 -H

命令解析:

  • -p:监视指定进程
  • -H:进入线程模式

Step3. 以上得到的3464是十进制的,我们需要转换为十六进制,然后通过jstack定位线程堆栈

printf "%x" 3464
d88

然后到java/bin/stack目录下运行以下命令

/java/bin/jstack 3209 | grep d88 -C 10

注意:jstack的对象是java进程的PID,而不是java线程的PID

Step4. 根据进程ID找到程序入口。pwdx命令根据指定的进程pid查找进程路径,从而定位位置

pwdx 3209
3209: /home/admin/xxxxx/target

到上面显示的路径中去找到jar包,解压jar包就可以找到程序入口类,把.class文件放到IDEA中反编译查看一下代码,找出代码问题。

1.2.5 关闭有问题的进程

如果你具有管理员或所有者的身份,则可将该进程由top中删除,这通常是因为该进程占用太多的系统资源。

  • 方式一:在top指令页输入k发送关闭信号删除进程
    执行top命令,然后在数据画面中按“k”键。画面中会出现“PID to kill:”信息,接着输入要删除的进程PID,输入PID后按键,会出现“Kill PID xxxxx with signal [15]:”提示信息(此处的xxxxx是指PID编号),此时需输入signal号码,如果直接按键,则以默认的15进行处理。如果无法顺利删除,则输入9来强制删除该进程。
  • 方式二:直接使用kill -9 pid关闭进程
    语法:kill -n,n表示信号编号
    不加参数默认使用15关闭进程(SIGTERM信号),大部分应用程序会先释放自己的资源后停止程序,但SIGTERM多半是会被阻塞忽略的。9发送的信号是SIGKILL,即exit。exit信号不会被系统阻塞,所以kill -9能顺利杀掉进程。使用的是7种进程间通信方式中的信号量。

2 系统负载(load)分析和异常排查

2.1 什么是系统负载

系统负载(Load)是指在一段时间内CPU正在处理以及等待CPU处理的进程数之和的统计信息,也就是CPU使用队列的长度的统计信息。当CPU完全空闲的时候,平均负荷为0;当CPU工作量饱和的时候,平均负荷为1。

如果CPU每分钟最多处理100个进程,那么系统负荷0.2,意味着CPU在这1分钟里只处理20个进程;系统负荷1.0,意味着CPU在这1分钟里正好处理100个进程;系统负荷1.7,意味着除了CPU正在处理的100个进程以外,还有70个进程正排队等着CPU处理

对于多核或单核处理器,2个CPU,意味着电脑的处理能力翻了一倍,能够同时处理的进程数量也翻了一倍。所以,2个CPU表明系统负荷可以达到2.0,此时每个CPU都达到100%的工作量。推广开来,n个CPU的电脑,可接受的系统负荷最大为n x 1.0。

把CPU想象成一座大桥,桥上只有一根车道(一个CPU),所有车辆都必须从这根车道上单向通行。系统负荷为0,意味着大桥上一辆车也没有。系统负荷为0.5,意味着大桥一半的路段有车。系统负荷为1.0,意味着大桥的所有路段都有车,也就是说大桥已经"满"了。但是必须注意的是,直到此时大桥还是能顺畅通行的。系统负荷为1.7,意味着车辆太多了,大桥已经被占满了(100%),后面等着上桥的车辆为桥面车辆的70%。

CPU的系统负荷,基本上等同于上面的类比。大桥的通行能力,就是CPU的最大工作量;桥梁上的车辆,就是一个个等待CPU处理的进程(process)。

2.2 CPU使用率与负载的区别

  • CPU利用率:显示的是程序在运行期间实时占用的CPU百分比
  • CPU负载:显示的是一段时间内正在使用和等待使用CPU的平均任务数

简单理解,一个是CPU的实时使用情况,一个是CPU的当前以及未来一段时间的使用情况。

2.3 查看系统负载

uptime命令

loadaverage的值分别表示1分钟、5分钟、15分钟内系统的平均负载。

2.4 机器正常负载范围(单核)

经验法则如下:
当系统负荷持续大于0.7,你必须开始调查了,问题出在哪里,防止情况恶化;
当系统负荷持续大于1.0,你必须动手寻找解决办法,把这个值降下来;
当系统负荷达到5.0,就表明你的系统有很严重的问题,长时间没有响应或者接近死机了。

2.5 CPU使用率低而负载高

主要原因是等待磁盘I/O完成的进程过多,导致进程队列长度过大,但是cpu运行的进程却很少,这样就导致负载过大,但CPU使用率低。常见导致这种情况的场景如下:

  • 磁盘读写请求过多导致大量IO等待
  • MySQL中存在没有用到的慢查询语句或死锁
  • 外接硬盘故障

CPU的工作效率要高于磁盘,而进程在CPU上面运行需要访问磁盘文件,这个时候CPU会向内核发起调用文件的请求,让内核去磁盘取文件,这个时候会切换到其他进程或者空闲,这个任务就会转换为不可中断睡眠状态。当这种读写请求过多就会导致不可中断睡眠状态的进程过多,从而导致负载高,CPU低的情况

MySQL的数据是存储在硬盘中,如果需进行sql查询,要先把数据从磁盘加载到内存中。当在数据特别大的时候,如果执行的sql语句没有索引,就会造成扫描表的行数过大导致I/O阻塞,或者是语句中存在死锁,也会造成I/O阻塞,从而导致不可中断睡眠进程过多,导致负载过大。

3 内存使用率异常排查

3.1 物理内存与虚拟内存

物理内存指通过物理内存条而获得的内存空间,即随机存取存储器。是与CPU直接交换数据的内部存储器,也叫主存(内存)。

虚拟内存是计算机系统内存管理的一种技术。它使得应用程序认为它拥有连续可用的内存(一个连续完整的地址空间),而实际上,它通常是被分隔成多个物理内存碎片,还有部分暂时存储在外部磁盘存储器上,在需要时进行数据交换也就是说,当物理内存不足时,可能会借用磁盘空间来充当内存使用)。与没有使用虚拟内存技术的系统相比,使用这种技术的系统使得大型程序的编写变得更容易,对真正的物理内存(例如RAM)的使用也更有效率。

3.2 swap分区

Swap分区(即交换区)在系统的物理内存不够用的时候(没有了buffers和cache时),可以临时存放使用率不高的内存分页,把这一部分物理内存释放出来,以供当前运行的程序使用。那些被释放的空间可能来自一些很长时间没有什么操作的程序,这些被释放的空间被临时保存到Swap分区中,等到那些程序要运行时,再从Swap分区中恢复保存的数据到内存中。

生产环境的应用服务器,一般都不设置swap分区,而是通过限定jvm内存小于物理内存的方式控制内存大小。动态的设置JVM堆内存的规则一般会在setenv.sh文件中。

3.3 查看内存使用情况

free命令,-h选项,这意味着适于人类可读,-h选项会在数字后面加上适于人类可读的单位。

Mem 是内存的使用情况;
Swap 是交换空间的使用情况;

buffers和cache的区别

A buffer is something that has yet to be “written” to disk.
A cache is something that has been “read“ from the disk and store for later use.

cache 是为了弥补高速设备和低速设备的鸿沟而引入的中间层,最终起到加快访问速度的作用;
buffer 的主要目的进行流量整理,把突发的大数量小规模的I/O」整理成平稳的「小数量较大规模的 I/O」,以减少响应次数。

free命令结果各列解释,free -b 命令运行结果将以byte为单位,free -k结果以KB为单位,不填写时,默认单位为KB

  • total,表示物理内存总大小;
  • used,表示总计分配给缓存(包含buffer与cache)使用的数量,其中可能部分缓存并未实际使用;
  • free,表示未被分配的内存;
  • shared,表示共享内存,一般系统不会用到;
  • buffers,系统分配但未被使用的buffers数量;
  • cached,系统分配但未被使用的cache数量;

3.4 内存占用飙高排查

3.4.1 常见原因

  • 内存溢出
  • 内存泄露
  • 堆外内存使用不当

3.4.2 内存溢出排查

内存溢出:指程序运行过程中无法申请到足够的内存而导致的一种错误。内存溢出通常发生于OLD段或Perm段垃圾回收后,仍然无内存空间容纳新的Java对象的情况。

堆内存溢出(outOfMemoryError:java heap space)

在jvm规范中,堆中的内存是用来生成对象实例和数组的。如果细分,堆内存还可以分为年轻代和年老代,年轻代包括一个eden区和两个survivor区。当生成新对象时,内存的申请过程如下:

  • jvm先尝试在Eden区分配新建对象所需的内存;
  • 如果内存大小足够,申请结束,否则下一步;
  • jvm启动youngGC,试图将Eden区中不活跃的对象释放掉,释放后若Eden空间仍然不足以放入新对象,则试图将部分Eden中活跃对象放入Survivor区;
  • Survivor区被用来作为Eden及old的中间交换区域,当OLD区空间足够时,Survivor区的对象会被移到Old区,否则会被保留在Survivor区;
  • 当OLD区空间不够时,JVM会在OLD区进行full GC;
  • Full GC后,若Survivor及OLD区仍然无法存放从Eden复制过来的部分对象,导致JVM无法在Eden区为新对象创建内存区域,则出现out of memory错误。

方法区内存溢出(outOfMemoryError:permgem space)

在jvm规范中,方法区主要存放的是类信息、常量、静态变量等。所以如果程序加载的类过多,或者使用反射、cglib等这种动态代理生成类的技术。就可能导致该区发生内存溢出

线程栈溢出(java.lang.StackOverflowError)

线程栈是线程独有的一块内存结构,所以线程栈发生问题必定是某个线程运行时产生的错误。一般线程栈溢出是由于递归太深或方法调用层级过多导致的

3.4.2 内存泄露排查

内存泄露是指程序中动态分配内存给一些临时对象,代码段运行结束后,这些对象已经没有被使用,但由于GC roots可达,没有被GC回收,始终占用内存。简单来说即被分配的对象无用但可达,这种问题一般是代码设计存在缺陷导致的。

Step1.使用top命令,查看内存占用较高的进程ID

发现PID为2294的进程占用内存45.2%,而且是一个Java进程,基本断定是程序问题。

Step2.使用jmap统计内存占用数据,并分析是否存在内存泄露

##查看java堆使用情况
/java/bin/jmap -heap 2294 

##查看堆内存(histogram)中的对象数量及大小
/java/bin/jmap -histo 2294 

##找到占用内存空间最多的前30个类
/java/bin/jmap -histo 2294 | head -30 

##JVM先触发gc,然后再统计信息
/java/bin/jmap -histo:live 2294 

##将内存使用的详细情况输出到文件
/java/bin/jmap -dump:format=b,file=heapDump 2294 

查看堆内存使用概况

查看占用内存空间最多的前20个类

理论上占用空间最多的类肯定是String、Object这些jdk类库中的类或某些框架源码类,如果出现了应用层编写的类,那肯定有问题。

jmap -histo pid 命令输出的class name含义解释如下。

如果输出中class name = [C的对象占用Heap最多,往往跟String有关,String内部是使用final char[]数组来保存数据的。

Step3.获取内存dump文件

jmap -dump:format=b,file=<filename.hprof> <pid>

此命令会将虚拟机heap镜像导成文件,format=b表示生成二进制文件,建议文件名中包含生成的日期和机器ip,方便问题追溯。dump在执行时,JVM是暂停服务的,所以对线上的运行会产生影响,导致应用实例暂时无法对外服务。使用以上命令得到堆dump文件后,可使用MAT工具进行对象分析。如果有大量对象在持续被引用,并没有被释放掉,那就产生了内存泄露。排查创建该对象的代码,进行修改,常见的内存泄露的原因有:

  • 长生命周期的对象持有短生命周期对象的引用;
  • 修改hashSet中对象的参数值,且参数是计算哈希值的字段;
  • 机器的连接数和关闭时间设置;

3.4.2 堆外内存使用不当排查

和堆内内存相对应,堆外内存就是把内存对象分配在Java虚拟机的堆以外的内存,这些内存直接受操作系统管理(而不是虚拟机),这样做的结果就是能够在一定程度上减少垃圾回收对应用程序造成的影响。堆外内存的优点:

  • 减少了垃圾回收 因为垃圾回收会暂停其他的工作;
  • 加快了复制的速度 堆内在flush到远程时,会先复制到直接内存,然后再发送,而堆外内存相当于省略掉了复制这个步骤;

堆外内存的缺点:内存难以控制,使用了堆外内存就间接失去了JVM管理内存的可行性,改由自己来管理,当发生内存溢出时排查起来非常困难。

堆外内存的使用场景:NIO引入了一种基于通道与缓冲区的IO方式,它可以使用Native函数库直接分配堆外内存,然后通过一个存储在java堆中的java.nio.DirectByteBuffer对角作为这块堆内存的引用进行操作。

4 网络异常分析及排查

4.1 查看网络指标

常用的查看网络流量的命令如下:

nload:监控入站流量和出站流量
nethogs: 按进程查看流量占用
iptraf: 按连接/端口查看流量
ifstat: 按设备查看流量
ethtool: 诊断工具
tcpdump: 抓包工具
ss: 连接查看工具
其他: dstat, slurm, nload, bmon

以上工具均需要安装。

4.2 查看TCP重传率

TCP重传率是对网络质量的一个体现,简单包装netstat -s的输出可以计算出TCP重传率。现成的脚本如下:

#!/bin/bash
export PATH='/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin'
SHELLDIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"

netstat -s -t > /tmp/netstat_s 2>/dev/null

s_r=`cat /tmp/netstat_s | grep 'segments send out' | awk '{print $1}'`
s_re=`cat /tmp/netstat_s  | grep 'segments retransmited' | awk '{print $1}'`

[ -e ${SHELLDIR}/s_r ] || touch ${SHELLDIR}/s_r
[ -e ${SHELLDIR}/s_re ] || touch ${SHELLDIR}/s_re

l_s_r=`cat ${SHELLDIR}/s_r`
l_s_re=`cat ${SHELLDIR}/s_re`

echo $s_r > ${SHELLDIR}/s_r
echo $s_re > ${SHELLDIR}/s_re

tcp_re_rate=`echo "$s_r $s_re $l_s_r $l_s_re" | awk '{printf("%.2f",($2-$4)/($1-$3)*100)}'`
echo $tcp_re_rate

4.2.1 为什么会产生TCP重传

  • TCP是一种可靠的协议,在网络交互的过程中,由于TCP报文是封装在IP协议中的,IP协议的无连接特性导致其可能在交互的过程中丢失,在这种情况下,TCP协议如何保障其传输的可靠性呢?
  • TCP通过在发送数据报文时设置一个超时定时器来解决这种问题,如果在定时器溢出时还没有收到来自对端对发送报文的确认,它就重传该数据报文

4.2.2 TCP重传率高的可能原因

发生重传说明网络传输有丢包,基本上从3个点去定位:客户端网络情况、服务端网络情况、中间链路网络情况。

  • 客户端机器网络异常;
  • 服务端网卡流量跑满,网卡有丢包现象,关注ifconfig的error输出;
  • 中间网络连路拥塞,比如交换机上联、核心交换机链路等,需要逐个排查链路流量情况;

数据报文传输中途丢失:发送端的数据报文在网络传输的过程中,被中间链路或中间设备丢弃;
接收端的ACK确认报文在传输中途丢失:发送端发送的数据报文到达了接受端,接受端也针对接收到的报文发送了相应的ACK确认报文,但是,这个ACK确认报文被中间链路或中间设备丢弃了;
接收端异常未响应ACK或被接收端丢弃:发送端发送的数据报文到达了接收端,但是,接收端由于种种原因,直接忽略该数据报文,或者接收到报文但并没有发送针对该报文的ACK确认报文。

4.3 查看TCP连接数

常用命令如下:

netstat -an									查看有哪些IP连接到本机
netstat -nat | grep -i "80" | wc -l			统计80端口连接数
netstat -na | grep ESTABLISHED | wc -l		统计已连接上的状态为established的连接数

查看各种状态的TCP连接数

netstat -n | awk '/^tcp/ {++S[$NF]} END {for(a in S) print a, S[a]}'

TCP连接状态详解
LISTEN: 侦听来自远方的TCP端口的连接请求
SYN-SENT: 再发送连接请求后等待匹配的连接请求
SYN-RECEIVED: 再收到和发送一个连接请求后等待对方对连接请求的确认
ESTABLISHED: 代表一个打开的连接
FIN-WAIT-1: 等待远程TCP连接中断请求,或先前的连接中断请求的确认
FIN-WAIT-2: 从远程TCP等待连接中断请求
CLOSE-WAIT: 等待从本地用户发来的连接中断请求
CLOSING: 等待远程TCP对连接中断的确认
LAST-ACK: 等待原来的发向远程TCP的连接中断请求的确认
TIME-WAIT: 等待足够的时间以确保远程TCP接收到连接中断请求的确认
CLOSED: 没有任何连接状态

另外,Tomcat的最大HTTP请求处理线程数默认为200,可修改xml进行配置。

4.4 无法创建HTTP连接

4.4.1 原因分析

常见原因:服务器上出现大量的close_wait和time_wait状态的TCP连接。

一个CLOSE_WAIT状态的TCP连接默认会在2个小时内被检测失活后回收。如果有流氓程序不停的反问请求,让服务器上产生了一堆的CLOSE_WAIT状态的TCP连接,消耗TCP资源,那么通常是等不到连接释放那一刻,系统就已经解决崩溃了。

4.4.2 解决方案

查看并修改linux内核配置文件

vim /etc/sysctl.conf

方法1 缩短TCP连接存活检测的时间间隔并回收TIME_WAIT状态的连接

## 发送keepalive探测消息的时间间隔,默认为7200秒
net.ipv4.tcp_keepalive_time=30
## 减少超时前的探测次数
net.ipv4.tcp_keepalive_probes=2
## 减少TIME_WAIT阶段过期时间,默认60
net.ipv4.tcp_tw_timeout=3
##开启TCP连接中TIME_WAIT sockets的快速回收。默认设置为0表示不开启
net.ipv4.tcp_tw_recycle = 1

方法2 复用TIME_WAIT状态的连接

## 表示开启重用TCP连接,允许将TIME_WAIT sockets重新用于新的连接,默认设置为0,表示不开启
net.ipv4.tcp_tw_reuse = 1

参考文档

https://my.oschina.net/laichendong/blog/283799
https://my.oschina.net/laichendong/blog/283790
https://blog.csdn.net/shimiso/article/details/21830871
https://www.cnblogs.com/virusolf/p/4335613.html
https://www.jianshu.com/p/b87c059d35f6
https://blog.csdn.net/lufeisan/article/details/53150971
https://blog.csdn.net/m0_37886429/article/details/78529681
https://www.cnblogs.com/hellojesson/p/6369506.html
http://www.hollischuang.com/archives/2642
https://zhuanlan.zhihu.com/p/36731397
https://www.jianshu.com/p/85e931636f27
https://www.cnblogs.com/virusolf/p/4335613.html

  • 2
    点赞
  • 35
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
### 回答1: autosar架构软件CPU load过高是常见的问题之一,它可能会导致设备性能受损,系统崩溃,甚至是安全性问题。快速排查原因可以通过以下步骤: 1. 确认CPU load过高的现象发生的时间和条件,包括何时,何地,何种环境。 2. 关注程序中的所有资源占用,包括主存,中间层,接口等,以及系统外部影响,如网络通信,时间表,CRC校验等等。 3. 检查CPU和核心电路等硬件是否存在故障或者无法正常工作的情况。 4. 采用基于时间的排查,通过记录事件的时间和相关的状态信息来追溯可能引起CPU load高的事件。 5. 使用调试软件进行排查,跟踪并分析对象和系统的运行,以定位可能的问题源并解决它们。同时,通过日志记录,分析产生CPU load高的原因和发生事件的位置。 总之,排查CPU load过高的问题需要有系统的思路和方法,通过分析硬件和软件的影响,以及使用高效的调试软件,来定位问题并解决它们,以确保设备的性能和安全性。 ### 回答2: 当autosar架构软件的CPU负载过高时,需要进行以下步骤来快速排查其原因。 首先,要使用性能分析工具来监控CPU使用率和系统负载。此类工具可突出显示CPU时间、热点和锁定问题,并提供CPU飙升或缺陷的警报。 其次,检查系统中的可用内存和使用的内存量。如有必要,可以通过增加内存或调整内存分配来减少CPU开销。 第三,检查系统中运行的进程和线程。通过检查这些进程和线程,可以确定是否存在紧急的CPU使用情况或死锁情况。 最后,如果以上方法都没有解决问题,可以使用追踪和调试工具进行进一步的调试。追踪工具可以捕捉CPU的使用情况,并记录系统中发生的事件和活动。调试工具可以确定哪些函数或线程在导致高CPU使用率。 总之,要快速排查autosar架构软件的CPU负载过高原因,需要使用性能分析、内存、进程/线程和调试工具来确定问题的根本原因。 ### 回答3: Autosar架构软件是一种高度复杂的软件,在使用中可能会出现CPU负载过高的问题。对于这种情况,我们可以从以下几个方面来进行快速排查。 1、通过软件调试工具查看代码是否存在死循环或者一些不必要的空循环等操作,这些都可能导致CPU过高。 2、可以通过系统监视器对CPU的利用率进行监控,这样可以了解CPU是否存在一个或多个线程的处理量过高导致的问题。 3、检查是否存在大量的IO操作,如读写文件或网络通信等,这些操作会占用CPU时间,导致CPU过高。 4、检查是否存在内存泄漏或者内存过大的情况,如果存在这样的情况,会导致CPU负载过高。 5、查看是否有高频中断的情况,这种情况一般是因为外设设备在短时间内向CPU发送了大量的中断请求,需要检查外设设备是否正常。 总之,对于Autosar架构软件的CPU负载过高问题,我们可以从多个角度去查找原因,只要找到了问题,就可以很快地进行解决。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值