linux下系统问题排查基本套路

这篇具有很好参考价值的文章主要介绍了linux下系统问题排查基本套路。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

总结常用命令

  1. top 查找cpu占用高的进程
  2. ps 找到对应进程的pid
  3. top -H -p pid 查找cpu利用率较高的线程
  4. printf ‘%x\n’ pid 将线程pid转换为16进制得到 nid
  5. jstack pid |grep ‘nid’ -C5 –color 在jstack中找到对应堆栈信息进行分析
  6. cat jstack.log | grep “java.lang.Thread.State” | sort -nr | uniq -c 对jstack有一个综合的把握,关注waiting、timed_waiting等线程状态
  7. jstat -gc pid 1000 观察 gc 分代变化,
  8. vmstat l 查看频繁上下文问题
  9. pidstat -w pid 监控特定 pid
  10. 磁盘
  11. df -hl 查看磁盘文件系统状态
  12. iostatiostat -d -k -x 分析磁盘读写速度,定位出问题的磁盘
  13. iotop 查看线程读写id,readlink -f /proc/*/task/tid/…/… 找到进程pid
  14. cat /proc/pid/io 查看进程具体读写情况
  15. lsof -p pid 确定具体的文件读写情况
  16. 内存
  17. free 检查内存情况
  18. jstack 、 jmap 检查没问题后
  19. jvm 设置 -Xss
  20. -Xms
  21. XX:MaxPermSize
  22. JMAPjmap -dump:format=b,file=filename pid 导出dump文件
  23. 在启动参数中指定-XX:+
    HeapDumpOnOutOfMemoryError 保存oom时的dump文件
  24. pstreee -p pid |wc -l 或者 ls -l /proc/pid/task | ws -l 查看总体线程数量
  25. pmap -x pid | sort -rn -k3 | head -30 查看对应进程倒数前30大的内存段
  26. strace -f -e “brk,mmap,munmap” -p pid 监控内存分配

原文

线上故障主要会包括cpu、磁盘、内存以及网络问题,而大多数故障可能会包含不止一个层面的问题,所以进行排查时候尽量四个方面依次排查一遍。

同时例如jstack、jmap等工具也是不囿于一个方面的问题的,基本上出问题就是df、free、top 三连,然后依次jstack、jmap伺候,具体问题具体分析即可。

一般来讲我们首先会排查cpu方面的问题。cpu异常往往还是比较好定位的。原因包括业务逻辑问题(死循环)、频繁gc以及上下文切换过多。而最常见的往往是业务逻辑(或者框架逻辑)导致的,可以使用jstack来分析对应的堆栈情况。

我们先用ps命令找到对应进程的pid(如果你有好几个目标进程,可以先用top看一下哪个占用比较高)。

接着用top -H -p pid来找到cpu使用率比较高的一些线程

linux下系统问题排查基本套路,生产业务线上问题,# JVM相关,linux,java,jvm

然后将占用最高的pid转换为16进制printf '%x\n' pid得到nid

linux下系统问题排查基本套路,生产业务线上问题,# JVM相关,linux,java,jvm

接着直接在jstack中找到相应的堆栈信息jstack pid |grep 'nid' -C5 –color

linux下系统问题排查基本套路,生产业务线上问题,# JVM相关,linux,java,jvm

可以看到我们已经找到了nid为0x42的堆栈信息,接着只要仔细分析一番即可。

当然更常见的是我们对整个jstack文件进行分析,通常我们会比较关注WAITING和TIMED_WAITING的部分,BLOCKED就不用说了。我们可以使用命令cat jstack.log | grep "java.lang.Thread.State" | sort -nr | uniq -c来对jstack的状态有一个整体的把握,如果WAITING之类的特别多,那么多半是有问题啦。

linux下系统问题排查基本套路,生产业务线上问题,# JVM相关,linux,java,jvm

当然我们还是会使用jstack来分析问题,但有时候我们可以先确定下gc是不是太频繁,使用jstat -gc pid 1000命令来对gc分代变化情况进行观察,1000表示采样间隔(ms),S0C/S1C、S0U/S1U、EC/EU、OC/OU、MC/MU分别代表两个Survivor区、Eden区、老年代、元数据区的容量和使用量。YGC/YGT、FGC/FGCT、GCT则代表YoungGc、FullGc的耗时和次数以及总耗时。如果看到gc比较频繁,再针对gc方面做进一步分析。

linux下系统问题排查基本套路,生产业务线上问题,# JVM相关,linux,java,jvm

针对频繁上下文问题,我们可以使用vmstat命令来进行查看

linux下系统问题排查基本套路,生产业务线上问题,# JVM相关,linux,java,jvm

cs(context switch)一列则代表了上下文切换的次数。

如果我们希望对特定的pid进行监控那么可以使用 pidstat -w pid命令,cswch和nvcswch表示自愿及非自愿切换。

linux下系统问题排查基本套路,生产业务线上问题,# JVM相关,linux,java,jvm

磁盘问题和cpu一样是属于比较基础的。首先是磁盘空间方面,我们直接使用df -hl来查看文件系统状态

linux下系统问题排查基本套路,生产业务线上问题,# JVM相关,linux,java,jvm

更多时候,磁盘问题还是性能上的问题。我们可以通过iostatiostat -d -k -x来进行分析

linux下系统问题排查基本套路,生产业务线上问题,# JVM相关,linux,java,jvm

最后一列%util可以看到每块磁盘写入的程度,而rrqpm/s以及wrqm/s分别表示读写速度,一般就能帮助定位到具体哪块磁盘出现问题了。

另外我们还需要知道是哪个进程在进行读写,一般来说开发自己心里有数,或者用iotop命令来进行定位文件读写的来源。

linux下系统问题排查基本套路,生产业务线上问题,# JVM相关,linux,java,jvm

不过这边拿到的是tid,我们要转换成pid,可以通过readlink来找到pidreadlink -f /proc/*/task/tid/../..。

linux下系统问题排查基本套路,生产业务线上问题,# JVM相关,linux,java,jvm

找到pid之后就可以看这个进程具体的读写情况cat /proc/pid/io

linux下系统问题排查基本套路,生产业务线上问题,# JVM相关,linux,java,jvm

我们还可以通过lsof命令来确定具体的文件读写情况lsof -p pid

linux下系统问题排查基本套路,生产业务线上问题,# JVM相关,linux,java,jvm

内存问题排查起来相对比CPU麻烦一些,场景也比较多。主要包括OOM、GC问题和堆外内存。一般来讲,我们会先用free命令先来检查一发内存的各种情况。

linux下系统问题排查基本套路,生产业务线上问题,# JVM相关,linux,java,jvm

内存问题大多还都是堆内内存问题。表象上主要分为OOM和StackOverflow。

JMV中的内存不足,OOM大致可以分为以下几种:

Exception in thread "main" java.lang.OutOfMemoryError: unable to create new native thread

这个意思是没有足够的内存空间给线程分配java栈,基本上还是线程池代码写的有问题,比如说忘记shutdown,所以说应该首先从代码层面来寻找问题,使用jstack或者jmap。如果一切都正常,JVM方面可以通过指定Xss来减少单个thread stack的大小。

另外也可以在系统层面,可以通过修改

/etc/security/limits.confnofile和nproc来增大os对线程的限制

linux下系统问题排查基本套路,生产业务线上问题,# JVM相关,linux,java,jvm

Exception in thread "main" java.lang.OutOfMemoryError: Java heap space

这个意思是堆的内存占用已经达到-Xmx设置的最大值,应该是最常见的OOM错误了。解决思路仍然是先应该在代码中找,怀疑存在内存泄漏,通过jstack和jmap去定位问题。如果说一切都正常,才需要通过调整Xmx的值来扩大内存。

Caused by: java.lang.OutOfMemoryError: Meta space

这个意思是元数据区的内存占用已经达到XX:MaxMetaspaceSize设置的最大值,排查思路和上面的一致,参数方面可以通过XX:MaxPermSize来进行调整(这里就不说1.8以前的永久代了)。

栈内存溢出,这个大家见到也比较多。

Exception in thread "main" java.lang.StackOverflowError

表示线程栈需要的内存大于Xss值,同样也是先进行排查,参数方面通过Xss来调整,但调整的太大可能又会引起OOM。

上述关于OOM和StackOverflow的代码排查方面,我们一般使用JMAPjmap -dump:format=b,file=filename pid来导出dump文件

linux下系统问题排查基本套路,生产业务线上问题,# JVM相关,linux,java,jvm

通过mat(Eclipse Memory Analysis Tools)导入dump文件进行分析,内存泄漏问题一般我们直接选Leak Suspects即可,mat给出了内存泄漏的建议。另外也可以选择Top Consumers来查看最大对象报告。和线程相关的问题可以选择thread overview进行分析。除此之外就是选择Histogram类概览来自己慢慢分析,大家可以搜搜mat的相关教程。

linux下系统问题排查基本套路,生产业务线上问题,# JVM相关,linux,java,jvm

日常开发中,代码产生内存泄漏是比较常见的事,并且比较隐蔽,需要开发者更加关注细节。比如说每次请求都new对象,导致大量重复创建对象;进行文件流操作但未正确关闭;手动不当触发gc;ByteBuffer缓存分配不合理等都会造成代码OOM。

另一方面,我们可以在启动参数中指定-XX:+

HeapDumpOnOutOfMemoryError来保存OOM时的dump文件。

gc问题除了影响cpu也会影响内存,排查思路也是一致的。一般先使用jstat来查看分代变化情况,比如youngGC或者fullGC次数是不是太多呀;EU、OU等指标增长是不是异常呀等。

线程的话太多而且不被及时gc也会引发oom,大部分就是之前说的unable to create new native thread。除了jstack细细分析dump文件外,我们一般先会看下总体线程,通过pstreee -p pid |wc -l。

linux下系统问题排查基本套路,生产业务线上问题,# JVM相关,linux,java,jvm

或者直接通过查看/proc/pid/task的数量即为线程数量。

linux下系统问题排查基本套路,生产业务线上问题,# JVM相关,linux,java,jvm

如果碰到堆外内存溢出,那可真是太不幸了。首先堆外内存溢出表现就是物理常驻内存增长快,报错的话视使用方式都不确定,如果由于使用Netty导致的,那错误日志里可能会出现OutOfDirectMemoryError错误,如果直接是DirectByteBuffer,那会报OutOfMemoryError: Direct buffer memory。

堆外内存溢出往往是和NIO的使用相关,一般我们先通过pmap来查看下进程占用的内存情况pmap -x pid | sort -rn -k3 | head -30,这段意思是查看对应pid倒序前30大的内存段。这边可以再一段时间后再跑一次命令看看内存增长情况,或者和正常机器比较可疑的内存段在哪里。

linux下系统问题排查基本套路,生产业务线上问题,# JVM相关,linux,java,jvm

我们如果确定有可疑的内存端,需要通过gdb来分析gdb --batch --pid {pid} -ex "dump memory filename.dump {内存起始地址} {内存起始地址+内存块大小}"

linux下系统问题排查基本套路,生产业务线上问题,# JVM相关,linux,java,jvm

获取dump文件后可用heaxdump进行查看hexdump -C filename | less,不过大多数看到的都是二进制乱码。

NMT是Java7U40引入的HotSpot新特性,配合jcmd命令我们就可以看到具体内存组成了。需要在启动参数中加入 -XX:NativeMemoryTracking=summary 或者 -XX:NativeMemoryTracking=detail,会有略微性能损耗。

一般对于堆外内存缓慢增长直到爆炸的情况来说,可以先设一个基线jcmd pid VM.native_memory baseline。

linux下系统问题排查基本套路,生产业务线上问题,# JVM相关,linux,java,jvm

然后等放一段时间后再去看看内存增长的情况,通过jcmd pid VM.native_memory detail.diff(summary.diff)做一下summary或者detail级别的diff。

linux下系统问题排查基本套路,生产业务线上问题,# JVM相关,linux,java,jvm
linux下系统问题排查基本套路,生产业务线上问题,# JVM相关,linux,java,jvm

可以看到jcmd分析出来的内存十分详细,包括堆内、线程以及gc(所以上述其他内存异常其实都可以用nmt来分析),这边堆外内存我们重点关注Internal的内存增长,如果增长十分明显的话那就是有问题了。

detail级别的话还会有具体内存段的增长情况,如下图。

linux下系统问题排查基本套路,生产业务线上问题,# JVM相关,linux,java,jvm

此外在系统层面,我们还可以使用strace命令来监控内存分配 strace -f -e "brk,mmap,munmap" -p pid

这边内存分配信息主要包括了pid和内存地址。

linux下系统问题排查基本套路,生产业务线上问题,# JVM相关,linux,java,jvm

不过其实上面那些操作也很难定位到具体的问题点,关键还是要看错误日志栈,找到可疑的对象,搞清楚它的回收机制,然后去分析对应的对象。比如DirectByteBuffer分配内存的话,是需要full GC或者手动system.gc来进行回收的(所以最好不要使用-XX:+DisableExplicitGC)。

那么其实我们可以跟踪一下DirectByteBuffer对象的内存情况,通过jmap -histo:live pid手动触发fullGC来看看堆外内存有没有被回收。如果被回收了,那么大概率是堆外内存本身分配的太小了,通过-XX:MaxDirectMemorySize进行调整。如果没有什么变化,那就要使用jmap去分析那些不能被gc的对象,以及和DirectByteBuffer之间的引用关系了。文章来源地址https://www.toymoban.com/news/detail-668056.html

GC相关

堆内内存泄漏总是和GC异常相伴。不过GC问题不只是和内存问题相关,还有可能引起CPU负载、网络问题等系列并发症,只是相对来说和内存联系紧密些,所以我们在此单独总结一下GC相关问题。

我们在cpu章介绍了使用jstat来获取当前GC分代变化信息。而更多时候,我们是通过GC日志来排查问题的,在启动参数中加上-verbose:gc -XX:+PrintGCDetails -XX:+PrintGCDateStamps -XX:+PrintGCTimeStamps来开启GC日志。

常见的Young GC、Full GC日志含义在此就不做赘述了。

针对gc日志,我们就能大致推断出youngGC与fullGC是否过于频繁或者耗时过长,从而对症下药。我们下面将对G1垃圾收集器来做分析,这边也建议大家使用G1-XX:+UseG1GC。

youngGC频繁一般是短周期小对象较多,先考虑是不是Eden区/新生代设置的太小了,看能否通过调整-Xmn、-XX:SurvivorRatio等参数设置来解决问题。如果参数正常,但是young gc频率还是太高,就需要使用Jmap和MAT对dump文件进行进一步排查了。

耗时过长问题就要看GC日志里耗时耗在哪一块了。以G1日志为例,可以关注Root Scanning、Object Copy、Ref Proc等阶段。Ref Proc耗时长,就要注意引用相关的对象。

Root Scanning耗时长,就要注意线程数、跨代引用。Object Copy则需要关注对象生存周期。而且耗时分析它需要横向比较,就是和其他项目或者正常时间段的耗时比较。比如说图中的Root Scanning和正常时间段比增长较多,那就是起的线程太多了。

linux下系统问题排查基本套路,生产业务线上问题,# JVM相关,linux,java,jvm

G1中更多的还是mixedGC,但mixedGC可以和youngGC思路一样去排查。触发fullGC了一般都会有问题,G1会退化使用Serial收集器来完成垃圾的清理工作,暂停时长达到秒级别,可以说是半跪了。

fullGC的原因可能包括以下这些,以及参数调整方面的一些思路:

并发阶段失败:在并发标记阶段,MixGC之前老年代就被填满了,那么这时候G1就会放弃标记周期。这种情况,可能就需要增加堆大小,或者调整并发标记线程数-XX:ConcGCThreads。

晋升失败:在GC的时候没有足够的内存供存活/晋升对象使用,所以触发了Full GC。这时候可以通过-XX:G1ReservePercent来增加预留内存百分比,减少-XX:InitiatingHeapOccupancyPercent来提前启动标记,-XX:ConcGCThreads来增加标记线程数也是可以的。

大对象分配失败:大对象找不到合适的region空间进行分配,就会进行fullGC,这种情况下可以增大内存或者增大-XX:G1HeapRegionSize。

程序主动执行System.gc():不要随便写就对了。

另外,我们可以在启动参数中配置-XX:HeapDumpPath=/xxx/dump.hprof来dump fullGC相关的文件,并通过jinfo来进行gc前后的dump


 
 
  1. jinfo -flag +HeapDumpBeforeFullGC pid
  2. jinfo -flag +HeapDumpAfterFullGC pid

这样得到2份dump文件,对比后主要关注被gc掉的问题对象来定位问题。

网络

涉及到网络层面的问题一般都比较复杂,场景多,定位难,成为了大多数开发的噩梦,应该是最复杂的了。这里会举一些例子,并从tcp层、应用层以及工具的使用等方面进行阐述。

超时错误大部分处在应用层面,所以这块着重理解概念。超时大体可以分为连接超时和读写超时,某些使用连接池的客户端框架还会存在获取连接超时和空闲连接清理超时。

  • 读写超时

readTimeout/writeTimeout,有些框架叫做so_timeout或者socketTimeout,均指的是数据读写超时。注意这边的超时大部分是指逻辑上的超时。soa的超时指的也是读超时。读写超时一般都只针对客户端设置。

  • 连接超时

connectionTimeout,客户端通常指与服务端建立连接的最大时间。服务端这边connectionTimeout就有些五花八门了,jetty中表示空闲连接清理时间,tomcat则表示连接维持的最大时间。

  • 其他

包括连接获取超时connectionAcquireTimeout和空闲连接清理超时idleConnectionTimeout。多用于使用连接池或队列的客户端或服务端框架。

我们在设置各种超时时间中,需要确认的是尽量保持客户端的超时小于服务端的超时,以保证连接正常结束。

在实际开发中,我们关心最多的应该是接口的读写超时了。

如何设置合理的接口超时是一个问题。如果接口超时设置的过长,那么有可能会过多地占用服务端的tcp连接。而如果接口设置的过短,那么接口超时就会非常频繁。

服务端接口明明rt降低,但客户端仍然一直超时又是另一个问题。这个问题其实很简单,客户端到服务端的链路包括网络传输、排队以及服务处理等,每一个环节都可能是耗时的原因。

tcp队列溢出是个相对底层的错误,它可能会造成超时、rst等更表层的错误。因此错误也更隐蔽,所以我们单独说一说。

linux下系统问题排查基本套路,生产业务线上问题,# JVM相关,linux,java,jvm

如上图所示,这里有两个队列:syns queue(半连接队列)、accept queue(全连接队列)。三次握手,在server收到client的syn后,把消息放到syns queue,回复syn+ack给client,server收到client的ack,如果这时accept queue没满,那就从syns queue拿出暂存的信息放入accept queue中,否则按tcp_abort_on_overflow指示的执行。

tcp_abort_on_overflow 0表示如果三次握手第三步的时候accept queue满了那么server扔掉client发过来的ack。tcp_abort_on_overflow 1则表示第三步的时候如果全连接队列满了,server发送一个rst包给client,表示废掉这个握手过程和这个连接,意味着日志里可能会有很多connection reset / connection reset by peer。

那么在实际开发中,我们怎么能快速定位到tcp队列溢出呢?

netstat命令,执行netstat -s | egrep "listen|LISTEN"

linux下系统问题排查基本套路,生产业务线上问题,# JVM相关,linux,java,jvm

如上图所示,overflowed表示全连接队列溢出的次数,sockets dropped表示半连接队列溢出的次数。

linux下系统问题排查基本套路,生产业务线上问题,# JVM相关,linux,java,jvm

上面看到Send-Q 表示第三列的listen端口上的全连接队列最大为5,第一列Recv-Q为全连接队列当前使用了多少。

接着我们看看怎么设置全连接、半连接队列大小吧:

全连接队列的大小取决于min(backlog, somaxconn)。backlog是在socket创建的时候传入的,somaxconn是一个os级别的系统参数。而半连接队列的大小取决于max(64,

/proc/sys/net/ipv4/tcp_max_syn_backlog)。

在日常开发中,我们往往使用servlet容器作为服务端,所以我们有时候也需要关注容器的连接队列大小。在tomcat中backlog叫做acceptCount,在jetty里面则是acceptQueueSize。

RST包表示连接重置,用于关闭一些无用的连接,通常表示异常关闭,区别于四次挥手。

在实际开发中,我们往往会看到connection reset / connection reset by peer错误,这种情况就是RST包导致的。

如果像不存在的端口发出建立连接SYN请求,那么服务端发现自己并没有这个端口则会直接返回一个RST报文,用于中断连接。

一般来说,正常的连接关闭都是需要通过FIN报文实现,然而我们也可以用RST报文来代替FIN,表示直接终止连接。实际开发中,可设置SO_LINGER数值来控制,这种往往是故意的,来跳过TIMED_WAIT,提供交互效率,不闲就慎用。

客户端或服务端有一边发生了异常,该方向对端发送RST以告知关闭连接

我们上面讲的tcp队列溢出发送RST包其实也是属于这一种。这种往往是由于某些原因,一方无法再能正常处理请求连接了(比如程序崩了,队列满了),从而告知另一方关闭连接。

接收到的TCP报文不在已知的TCP连接内

比如,一方机器由于网络实在太差TCP报文失踪了,另一方关闭了该连接,然后过了许久收到了之前失踪的TCP报文,但由于对应的TCP连接已不存在,那么会直接发一个RST包以便开启新的连接。

一方长期未收到另一方的确认报文,在一定时间或重传次数后发出RST报文

这种大多也和网络环境相关了,网络环境差可能会导致更多的RST报文。

之前说过RST报文多会导致程序报错,在一个已关闭的连接上读操作会报connection reset,而在一个已关闭的连接上写操作则会报connection reset by peer。通常我们可能还会看到broken pipe错误,这是管道层面的错误,表示对已关闭的管道进行读写,往往是在收到RST,报出connection reset错后继续读写数据报的错,这个在glibc源码注释中也有介绍。

我们在排查故障时候怎么确定有RST包的存在呢?当然是使用tcpdump命令进行抓包,并使用wireshark进行简单分析了。tcpdump -i en0 tcp -w xxx.cap,en0表示监听的网卡。

linux下系统问题排查基本套路,生产业务线上问题,# JVM相关,linux,java,jvm

接下来我们通过wireshark打开抓到的包,可能就能看到如下图所示,红色的就表示RST包了。

linux下系统问题排查基本套路,生产业务线上问题,# JVM相关,linux,java,jvm

TIME_WAIT和CLOSE_WAIT是啥意思相信大家都知道。

在线上时,我们可以直接用命令netstat -n | awk '/^tcp/ {++S[$NF]} END {for(a in S) print a, S[a]}'来查看time-wait和close_wait的数量

用ss命令会更快ss -ant | awk '{++S[$1]} END {for(a in S) print a, S[a]}'

TIME_WAIT

time_wait的存在一是为了丢失的数据包被后面连接复用,二是为了在2MSL的时间范围内正常关闭连接。它的存在其实会大大减少RST包的出现。

过多的time_wait在短连接频繁的场景比较容易出现。这种情况可以在服务端做一些内核参数调优:

#表示开启重用。允许将TIME-WAIT sockets重新用于新的TCP连接,默认为0,表示关闭net.ipv4.tcp_tw_reuse = 1#表示开启TCP连接中TIME-WAIT sockets的快速回收,默认为0,表示关闭net.ipv4.tcp_tw_recycle = 1
 
 

当然我们不要忘记在NAT环境下因为时间戳错乱导致数据包被拒绝的坑了,另外的办法就是改小tcp_max_tw_buckets,超过这个数的time_wait都会被干掉,不过这也会导致报time wait bucket table overflow的错。

CLOSE_WAIT

close_wait往往都是因为应用程序写的有问题,没有在ACK后再次发起FIN报文。close_wait出现的概率甚至比time_wait要更高,后果也更严重。往往是由于某个地方阻塞住了,没有正常关闭连接,从而渐渐地消耗完所有的线程。

想要定位这类问题,最好是通过jstack来分析线程堆栈来排查问题,具体可参考上述章节。这里仅举一个例子。

开发同学说应用上线后CLOSE_WAIT就一直增多,直到挂掉为止,jstack后找到比较可疑的堆栈是大部分线程都卡在了countdownlatch.await方法,找开发同学了解后得知使用了多线程但是确没有catch异常,修改后发现异常仅仅是最简单的升级sdk后常出现的class not found。

原文链接:

https://www.toutiao.com/article/6868136002486010371/?channel=&source=search_tab

线上故障主要会包括cpu、磁盘、内存以及网络问题,而大多数故障可能会包含不止一个层面的问题,所以进行排查时候尽量四个方面依次排查一遍。

同时例如jstack、jmap等工具也是不囿于一个方面的问题的,基本上出问题就是df、free、top 三连,然后依次jstack、jmap伺候,具体问题具体分析即可。

一般来讲我们首先会排查cpu方面的问题。cpu异常往往还是比较好定位的。原因包括业务逻辑问题(死循环)、频繁gc以及上下文切换过多。而最常见的往往是业务逻辑(或者框架逻辑)导致的,可以使用jstack来分析对应的堆栈情况。

我们先用ps命令找到对应进程的pid(如果你有好几个目标进程,可以先用top看一下哪个占用比较高)。

接着用top -H -p pid来找到cpu使用率比较高的一些线程

linux下系统问题排查基本套路,生产业务线上问题,# JVM相关,linux,java,jvm

然后将占用最高的pid转换为16进制printf '%x\n' pid得到nid

linux下系统问题排查基本套路,生产业务线上问题,# JVM相关,linux,java,jvm

接着直接在jstack中找到相应的堆栈信息jstack pid |grep 'nid' -C5 –color

linux下系统问题排查基本套路,生产业务线上问题,# JVM相关,linux,java,jvm

可以看到我们已经找到了nid为0x42的堆栈信息,接着只要仔细分析一番即可。

当然更常见的是我们对整个jstack文件进行分析,通常我们会比较关注WAITING和TIMED_WAITING的部分,BLOCKED就不用说了。我们可以使用命令cat jstack.log | grep "java.lang.Thread.State" | sort -nr | uniq -c来对jstack的状态有一个整体的把握,如果WAITING之类的特别多,那么多半是有问题啦。

linux下系统问题排查基本套路,生产业务线上问题,# JVM相关,linux,java,jvm

当然我们还是会使用jstack来分析问题,但有时候我们可以先确定下gc是不是太频繁,使用jstat -gc pid 1000命令来对gc分代变化情况进行观察,1000表示采样间隔(ms),S0C/S1C、S0U/S1U、EC/EU、OC/OU、MC/MU分别代表两个Survivor区、Eden区、老年代、元数据区的容量和使用量。YGC/YGT、FGC/FGCT、GCT则代表YoungGc、FullGc的耗时和次数以及总耗时。如果看到gc比较频繁,再针对gc方面做进一步分析。

linux下系统问题排查基本套路,生产业务线上问题,# JVM相关,linux,java,jvm

针对频繁上下文问题,我们可以使用vmstat命令来进行查看

linux下系统问题排查基本套路,生产业务线上问题,# JVM相关,linux,java,jvm

cs(context switch)一列则代表了上下文切换的次数。

如果我们希望对特定的pid进行监控那么可以使用 pidstat -w pid命令,cswch和nvcswch表示自愿及非自愿切换。

linux下系统问题排查基本套路,生产业务线上问题,# JVM相关,linux,java,jvm

磁盘问题和cpu一样是属于比较基础的。首先是磁盘空间方面,我们直接使用df -hl来查看文件系统状态

linux下系统问题排查基本套路,生产业务线上问题,# JVM相关,linux,java,jvm

更多时候,磁盘问题还是性能上的问题。我们可以通过iostatiostat -d -k -x来进行分析

linux下系统问题排查基本套路,生产业务线上问题,# JVM相关,linux,java,jvm

最后一列%util可以看到每块磁盘写入的程度,而rrqpm/s以及wrqm/s分别表示读写速度,一般就能帮助定位到具体哪块磁盘出现问题了。

另外我们还需要知道是哪个进程在进行读写,一般来说开发自己心里有数,或者用iotop命令来进行定位文件读写的来源。

linux下系统问题排查基本套路,生产业务线上问题,# JVM相关,linux,java,jvm

不过这边拿到的是tid,我们要转换成pid,可以通过readlink来找到pidreadlink -f /proc/*/task/tid/../..。

linux下系统问题排查基本套路,生产业务线上问题,# JVM相关,linux,java,jvm

找到pid之后就可以看这个进程具体的读写情况cat /proc/pid/io

linux下系统问题排查基本套路,生产业务线上问题,# JVM相关,linux,java,jvm

我们还可以通过lsof命令来确定具体的文件读写情况lsof -p pid

linux下系统问题排查基本套路,生产业务线上问题,# JVM相关,linux,java,jvm

内存问题排查起来相对比CPU麻烦一些,场景也比较多。主要包括OOM、GC问题和堆外内存。一般来讲,我们会先用free命令先来检查一发内存的各种情况。

linux下系统问题排查基本套路,生产业务线上问题,# JVM相关,linux,java,jvm

内存问题大多还都是堆内内存问题。表象上主要分为OOM和StackOverflow。

JMV中的内存不足,OOM大致可以分为以下几种:

Exception in thread "main" java.lang.OutOfMemoryError: unable to create new native thread

这个意思是没有足够的内存空间给线程分配java栈,基本上还是线程池代码写的有问题,比如说忘记shutdown,所以说应该首先从代码层面来寻找问题,使用jstack或者jmap。如果一切都正常,JVM方面可以通过指定Xss来减少单个thread stack的大小。

另外也可以在系统层面,可以通过修改

/etc/security/limits.confnofile和nproc来增大os对线程的限制

linux下系统问题排查基本套路,生产业务线上问题,# JVM相关,linux,java,jvm

Exception in thread "main" java.lang.OutOfMemoryError: Java heap space

这个意思是堆的内存占用已经达到-Xmx设置的最大值,应该是最常见的OOM错误了。解决思路仍然是先应该在代码中找,怀疑存在内存泄漏,通过jstack和jmap去定位问题。如果说一切都正常,才需要通过调整Xmx的值来扩大内存。

Caused by: java.lang.OutOfMemoryError: Meta space

这个意思是元数据区的内存占用已经达到XX:MaxMetaspaceSize设置的最大值,排查思路和上面的一致,参数方面可以通过XX:MaxPermSize来进行调整(这里就不说1.8以前的永久代了)。

栈内存溢出,这个大家见到也比较多。

Exception in thread "main" java.lang.StackOverflowError

表示线程栈需要的内存大于Xss值,同样也是先进行排查,参数方面通过Xss来调整,但调整的太大可能又会引起OOM。

上述关于OOM和StackOverflow的代码排查方面,我们一般使用JMAPjmap -dump:format=b,file=filename pid来导出dump文件

linux下系统问题排查基本套路,生产业务线上问题,# JVM相关,linux,java,jvm

通过mat(Eclipse Memory Analysis Tools)导入dump文件进行分析,内存泄漏问题一般我们直接选Leak Suspects即可,mat给出了内存泄漏的建议。另外也可以选择Top Consumers来查看最大对象报告。和线程相关的问题可以选择thread overview进行分析。除此之外就是选择Histogram类概览来自己慢慢分析,大家可以搜搜mat的相关教程。

linux下系统问题排查基本套路,生产业务线上问题,# JVM相关,linux,java,jvm

日常开发中,代码产生内存泄漏是比较常见的事,并且比较隐蔽,需要开发者更加关注细节。比如说每次请求都new对象,导致大量重复创建对象;进行文件流操作但未正确关闭;手动不当触发gc;ByteBuffer缓存分配不合理等都会造成代码OOM。

另一方面,我们可以在启动参数中指定-XX:+

HeapDumpOnOutOfMemoryError来保存OOM时的dump文件。

gc问题除了影响cpu也会影响内存,排查思路也是一致的。一般先使用jstat来查看分代变化情况,比如youngGC或者fullGC次数是不是太多呀;EU、OU等指标增长是不是异常呀等。

线程的话太多而且不被及时gc也会引发oom,大部分就是之前说的unable to create new native thread。除了jstack细细分析dump文件外,我们一般先会看下总体线程,通过pstreee -p pid |wc -l。

linux下系统问题排查基本套路,生产业务线上问题,# JVM相关,linux,java,jvm

或者直接通过查看/proc/pid/task的数量即为线程数量。

linux下系统问题排查基本套路,生产业务线上问题,# JVM相关,linux,java,jvm

如果碰到堆外内存溢出,那可真是太不幸了。首先堆外内存溢出表现就是物理常驻内存增长快,报错的话视使用方式都不确定,如果由于使用Netty导致的,那错误日志里可能会出现OutOfDirectMemoryError错误,如果直接是DirectByteBuffer,那会报OutOfMemoryError: Direct buffer memory。

堆外内存溢出往往是和NIO的使用相关,一般我们先通过pmap来查看下进程占用的内存情况pmap -x pid | sort -rn -k3 | head -30,这段意思是查看对应pid倒序前30大的内存段。这边可以再一段时间后再跑一次命令看看内存增长情况,或者和正常机器比较可疑的内存段在哪里。

linux下系统问题排查基本套路,生产业务线上问题,# JVM相关,linux,java,jvm

我们如果确定有可疑的内存端,需要通过gdb来分析gdb --batch --pid {pid} -ex "dump memory filename.dump {内存起始地址} {内存起始地址+内存块大小}"

linux下系统问题排查基本套路,生产业务线上问题,# JVM相关,linux,java,jvm

获取dump文件后可用heaxdump进行查看hexdump -C filename | less,不过大多数看到的都是二进制乱码。

NMT是Java7U40引入的HotSpot新特性,配合jcmd命令我们就可以看到具体内存组成了。需要在启动参数中加入 -XX:NativeMemoryTracking=summary 或者 -XX:NativeMemoryTracking=detail,会有略微性能损耗。

一般对于堆外内存缓慢增长直到爆炸的情况来说,可以先设一个基线jcmd pid VM.native_memory baseline。

linux下系统问题排查基本套路,生产业务线上问题,# JVM相关,linux,java,jvm

然后等放一段时间后再去看看内存增长的情况,通过jcmd pid VM.native_memory detail.diff(summary.diff)做一下summary或者detail级别的diff。

linux下系统问题排查基本套路,生产业务线上问题,# JVM相关,linux,java,jvm
linux下系统问题排查基本套路,生产业务线上问题,# JVM相关,linux,java,jvm

可以看到jcmd分析出来的内存十分详细,包括堆内、线程以及gc(所以上述其他内存异常其实都可以用nmt来分析),这边堆外内存我们重点关注Internal的内存增长,如果增长十分明显的话那就是有问题了。

detail级别的话还会有具体内存段的增长情况,如下图。

linux下系统问题排查基本套路,生产业务线上问题,# JVM相关,linux,java,jvm

此外在系统层面,我们还可以使用strace命令来监控内存分配 strace -f -e "brk,mmap,munmap" -p pid

这边内存分配信息主要包括了pid和内存地址。

linux下系统问题排查基本套路,生产业务线上问题,# JVM相关,linux,java,jvm

不过其实上面那些操作也很难定位到具体的问题点,关键还是要看错误日志栈,找到可疑的对象,搞清楚它的回收机制,然后去分析对应的对象。比如DirectByteBuffer分配内存的话,是需要full GC或者手动system.gc来进行回收的(所以最好不要使用-XX:+DisableExplicitGC)。

那么其实我们可以跟踪一下DirectByteBuffer对象的内存情况,通过jmap -histo:live pid手动触发fullGC来看看堆外内存有没有被回收。如果被回收了,那么大概率是堆外内存本身分配的太小了,通过-XX:MaxDirectMemorySize进行调整。如果没有什么变化,那就要使用jmap去分析那些不能被gc的对象,以及和DirectByteBuffer之间的引用关系了。

到了这里,关于linux下系统问题排查基本套路的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • ELK常用语法和线上问题排查

    1.全文搜索 在搜索栏输入目标值,查询所有字段中包含该值的文档 案例:用户反馈了一串id或者其他同事给了一个jobid,还没有头绪怎么查的时候,直接全局搜索 jobid 2.字段 限定字段全文搜索: field:value 通配符限定: ?:匹配单个字符 :匹配多个字符 案例:查询uid是 XXX 的

    2024年02月13日
    浏览(74)
  • Java线上服务CPU、内存飙升问题排查步骤!

    作为一名从事Java开发快一年的程序员,在线上经常碰到 某个模块的Pod发出CPU与内存告警的问题 ,而这些问题会导致系统响应缓慢甚至是服务不可用。一般情况下可以通过 重启 或者 调高Pod的资源量或者增加Pod数量 暂时解决问题,但这是治标不治本的,只有找到问题发生的原

    2024年02月16日
    浏览(46)
  • Java线上CPU内存冲高问题排查步骤

    作为一名从事Java开发快一年的程序员,在线上经常碰到 某个模块的Pod发出CPU与内存告警的问题 ,而这些问题会导致系统响应缓慢甚至是服务不可用。一般情况下可以通过 重启 或者 调高Pod的资源量或者增加Pod数量 暂时解决问题,但这是治标不治本的,只有找到问题发生的原

    2024年02月07日
    浏览(44)
  • 【Jvm】性能调优(下)线上问题排查思路汇总

    【Jvm】性能调优(上)线上问题排查工具汇总 【Jvm】性能调优(中)Java中不得不了解的OOM Error 标准参数(-) :所有的JVM实现都必须实现该功能且向后兼容 非标准参数(-X) : 默认Jvm实现该功能 ,但是不保证所有jvm实现都满足,且 不保证向后兼容 非稳定参数(-XX) : 各

    2024年02月21日
    浏览(45)
  • 【Jvm】性能调优(上)线上问题排查工具汇总

    产品闭环 产品闭环是能够让 用户主动迭代促进产品发展的方式 。例如一些内容产品,比如 糗事百科 ,种子用户 产出高质量内容 ,举报与赞起到 筛选内容 ,提高内容质量的作用, 内容质量的提升有助于吸引更多用户 。 这就是产品闭环, 产品给予用户需求解决方法,用户

    2024年02月20日
    浏览(46)
  • JVM:性能监控工具分析和线上问题排查实践

    在日常开发过程中,多少都会碰到一些jvm相关的问题,比如: 内存溢出、内存泄漏、cpu利用率飙升到100%、线程死锁、应用异常宕机 等。 在这个日益内卷的环境,如何运用好工具分析jvm问题,成为每个java攻城狮必备的技能。所以白梦特意整理了 jdk自带分析工具的使用 ,以及

    2024年01月19日
    浏览(44)
  • 记一次 Redisson 线上问题 → ERR unknown command 'WAIT' 的排查与分析

    昨晚和一个朋友聊天 我:处对象吗,咱俩试试? 朋友:我有对象 我:我不信,有对象不公开? 朋友:不好公开,我当的小三 程序在生产环境稳定的跑着 直到有一天,公司执行组件漏洞扫描,有漏洞的  jar  要进行升级修复 然后我就按着扫描报告将有漏洞的  jar  修复到指

    2024年02月09日
    浏览(54)
  • 阿里云新用户滑块验证不过,阿里云滑动验证流程及线上问题排查

    滑动验证是阿里巴巴集团提供的一种验证码解决方案,采用风险分析引擎,有效区分来自人类与机器人的访问行为并拦截机器风险,为您提供安全可靠的业务环境。 下图是滑动验证在用户客户端的展示效果。 产品介绍:阿里云验证码(Alibaba Captcha) 滑动验证流程 滑动验证服

    2024年01月17日
    浏览(41)
  • 辽宁线上3D三维虚拟工厂生产仿真系统应用场景及优势

    工厂虚拟仿真是一种基于计算机技术和虚拟现实技术的数字化解决方案,它可以通过模拟工厂中的设备、流程和操作,来为工程师和操作人员提供了一个沉浸式的虚拟环境,帮助他们更好地了解和优化工厂生产过程。 工厂VR三维可视化技术为工业生产提供了更高效、更精确的

    2024年02月13日
    浏览(39)
  • 我是如何用 redis 分布式锁来解决线上历史业务问题的

    近期发现,开发功能的时候发现了一个 mq 消费顺序错乱(历史遗留问题),导致业务异常的问题,看看我是如何解决的 首先,简单介绍一下情况: 线上 k8s 有多个 pod 会去消费 mq 中的消息,可是生产者发送的消息是期望一定要有序去消费,此时要表达的是,例如 生产者如果

    2024年02月09日
    浏览(32)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包