写点什么

线上问题排查学习总结

用户头像
原来不悔
关注
发布于: 2021 年 01 月 16 日

一.线上内存相关问题排查

关注点:内存溢出、内存分配不合理、对象不断创建导致

1.查看当前 java 应用的进程号

指令:ps -ef|grep java 或者 jps 命令

在jdk的bin路径下找到jps命令,如果输入jps提示bash: jps: command not found 就需要带上全路径:/usr/local/jdk1.8.0_92/bin/jps
复制代码

jps 实际执行效果:

2.使用 jmap 查看进程的内存情况(需要 root 权限执行)

指令:jmap -heap 8931

作用:可以查看新生代,老生代堆内存的分配大小以及使用情况

 指令:/usr/local/jdk1.8.0_92/bin/jmap -heap 8931
复制代码

实际执行效果如图:

上图中各个参数的解释如下:

using parallel threads in the new generation.  ##新生代采用的是并行线程处理方式using thread-local object allocation.   Concurrent Mark-Sweep GC   ##同步并行垃圾回收
Heap Configuration:  ##堆配置情况   MinHeapFreeRatio = 40 ##最小堆使用比例   MaxHeapFreeRatio = 70 ##最大堆可用比例   MaxHeapSize      = 2147483648 (2048.0MB) ##最大堆空间大小   NewSize          = 268435456 (256.0MB) ##新生代分配大小   MaxNewSize       = 268435456 (256.0MB) ##最大可新生代分配大小   OldSize          = 5439488 (5.1875MB) ##老生代大小   NewRatio         = 2  ##新生代比例   SurvivorRatio    = 8 ##新生代与suvivor的比例   PermSize         = 134217728 (128.0MB) ##perm区大小   MaxPermSize      = 134217728 (128.0MB) ##最大可分配perm区大小
Heap Usage: ##堆使用情况New Generation (Eden + 1 Survivor Space):  ##新生代(伊甸区 + survior空间)   capacity = 241631232 (230.4375MB)  ##伊甸区容量   used     = 77776272 (74.17323303222656MB) ##已经使用大小   free     = 163854960 (156.26426696777344MB) ##剩余容量   32.188004570534986% used ##使用比例Eden Space:  ##伊甸区   capacity = 214827008 (204.875MB) ##伊甸区容量   used     = 74442288 (70.99369812011719MB) ##伊甸区使用   free     = 140384720 (133.8813018798828MB) ##伊甸区当前剩余容量   34.65220164496263% used ##伊甸区使用情况From Space: ##survior1区   capacity = 26804224 (25.5625MB) ##survior1区容量   used     = 3333984 (3.179534912109375MB) ##surviror1区已使用情况   free     = 23470240 (22.382965087890625MB) ##surviror1区剩余容量   12.43827838477995% used ##survior1区使用比例To Space: ##survior2 区   capacity = 26804224 (25.5625MB) ##survior2区容量   used     = 0 (0.0MB) ##survior2区已使用情况   free     = 26804224 (25.5625MB) ##survior2区剩余容量   0.0% used ## survior2区使用比例concurrent mark-sweep generation: ##老生代使用情况   capacity = 1879048192 (1792.0MB) ##老生代容量   used     = 30847928 (29.41887664794922MB) ##老生代已使用容量   free     = 1848200264 (1762.5811233520508MB) ##老生代剩余容量   1.6416783843721663% used ##老生代使用比例Perm Generation: ##perm区使用情况   capacity = 134217728 (128.0MB) ##perm区容量   used     = 47303016 (45.111671447753906MB) ##perm区已使用容量   free     = 86914712 (82.8883285522461MB) ##perm区剩余容量   35.24349331855774% used ##perm区使用比例
复制代码

3.找到最耗内存的对象

指令:jmap -histo:live 8931|less

作用:可以很方便的看到实例数、占用内存大小、全类名

注意:线上执行该命令会强制执行一次 fgc

指令:/usr/local/jdk1.8.0_92/bin/jmap -histo:live 8931|less
顺带复习less指令: less 是一个Linux命令行实用程序,用于显示文件或命令输出的内容,它一次只显示一个页面。它类似于 more ,但具有更高级的功能,允许您在文件中向前和向后导航。该 less 命令主要用于打开大文件。less 不会读取整个文件,相比于 vim 或 nano 等文本编辑器,加载时间会更快。 -m 显示读取文件的百分比; -i 忽略搜索时的大小写 b:是上翻一页 空格:下翻一页 回车:是下一行 q:退出less /字符串:搜索"字符串"的功能举例: ps -ef | grep java | less(分页查看java进程) ps -ef | less(分页查看进程) less log2013.log(查看日志文件) less log2013.log log2014.log(查看多个文件)
复制代码

实际执行效果如下图所示:

4.还可以通过 dump 出堆内存信息进行分析

指令:jmap -dump:format=b,file=jmapdump_all 进程号

执行一下语句:/usr/local/jdk1.8.092/bin/jmap -dump:format=b,file=jmap_dump_all 8931执行完后会在当前目录出现一个二进制文件
复制代码

如下图所示二进制文件无法直接打开,需要通过工具进行分析,如果文件比较小,推荐使用 jdk 自带的 jvisiualvm 工具进行打开分析,如果文件较大推荐用 eclipse 的内存分析工具 MAT。

Eclipse Memory Analyzer(MAT)支持两种安装方式,一是 Eclipse 插件的方式,另外一个就是独立运行的方式,建议使用独立运行的方式。下载地址: http://www.eclipse.org/mat/downloads.php


jvisiualvm的使用方法暂时可参考:http://www.xwood.net/_site_domain_/_root/5870/5874/t_c279949.htmlMAT的使用方法:(推荐)https://blog.csdn.net/itomge/article/details/48719527、https://www.jianshu.com/p/2cf7169ba1c4?utm_campaign=maleskine&utm_content=note&utm_medium=seo_notes&utm_source=recommendation、https://www.cnblogs.com/hanlinhu/p/10174185.html
复制代码

5.查看句柄和线程使用情况

查看句柄详情:ll /proc/9339/fd查看线程详情:ll /proc/9339/task当前使用的句柄数量: ll /proc/${PID}/fd | wc -l 当前使用的线程数量:ll /proc/${PID}/task | wc -l 
顺便复习wc的用法: wc -c filename:显示一个文件的字节数 wc -m filename:显示一个文件的字符数 wc -l filename:显示一个文件的行数 wc -L filename:显示一个文件中的最长行的长度 wc -w filename:显示一个文件的字数
复制代码

查看当前进程使用句柄数量

查看当前进程使用线程数量

6.linux 系统句柄数查看和配置

1.查看句柄数量

指令:ulimit -n

默认值:1024

2.查看当前各个进程句柄使用情况

指令:lsof -n|awk '{print $2}'|sort|uniq -c|sort -nr|more
复制代码

实际执行效果

3.修改句柄大小

修改文件:/etc/security/limits.conf,在文件中添加	soft nofile 32768 #限制单个进程最大文件句柄数(到达此限制时 系统报警)	hard nofile 65536 #限制单个进程最大文件句柄数(到达此限制时系统报错)修改文件:/etc/sysctl.conf。在文件中添加:	fs.file-max=655350 #限制整个系统最大文件句柄数
复制代码

6.总结

1.jps 查看进程号

2.jmap -heap 进程号 查看 java 进程堆内存分配情况

3.jmap -histo:live 进程号 | less 查看当前存活的最耗内存的对象

4.也可以通过 jmap -dump:format=b,file=jmapdump_all 进程号 dump 出内存镜像,通过 MAT 分析

5.查看当前进程使用的句柄数:ll /proc/进程号/fd | wc -l

查看当前进程使用的线程数量:ll /proc/进程号/task | wc -l

6.查看 linux 系统句柄数: ulimit -n


二.线上服务器 cpu 负载高

1.通过 top 命令可以查看当前 cpu,内存使用情况

第一列为当前进程的进程 id,通过 top 很容易找到 cpu 使用较高的进程。如果确定是 java 应用导致的 cpu 高,也可以通过 jdk 自带的 jps 命令查看 java 进程的进程号。

2.找到进程下耗资源的线程信息

指令:top -p 8931 -H

第一列为进程下的线程的 pid,可以看到线程 id 为 9996

3.导出进程的栈信息

指令:jstack 8931 >> stack.log

 指令:/usr/local/jdk1.8.0_92/bin/jstack 8931>>stack.log
复制代码

接下来在当前目录会出现一个 stack.log 文件

4.将 cpu 消耗高的线程的 pid 换算为 16 进制

指令:printf 0x%x 9996

得到 16 进制值为:0x270c

5.从刚才的栈日志中查找该线程正在运行的方法

指令:grep 0x270c stack.log -a 10

如果不想dump出stack.log文件,那么也可以直接在服务器查看:jstack 17850|grep 0x270c -a 10另外也可以查找正在运行的线程,及线程处于运行状态的位置,从这些线程中来查找资源消耗过高的代码。指令:grep RUNNABLE stack.log  -a1
复制代码

6.总结

1.通过 top 命令找到占用 cpu 高的进程

2.通过 top -p 进程号 -H 找到进程下的线程使用情况

3.导出堆栈信息 jstack 进程号 >> stack.log

4.将最耗 cpu 的线程 id 转成 16 进制,printf 0x%x 9996

5.在 stack.log 中查看该线程是哪里在使用,分析定位原因


三.其他有用的排查问题指令

1.ps -efL, 显示所有活跃线程 ID 和对应时间

pid 为进程 id

ppid 为线程 id

往后翻可以看到 java 各个线程的存活情况

2.查看某一个端口的使用方式:

lsof -i :8080
复制代码


3.

du -sch * 
复制代码


发布于: 2021 年 01 月 16 日阅读数: 72
用户头像

原来不悔

关注

还未添加个人签名 2021.01.11 加入

还未添加个人简介

评论

发布
暂无评论
线上问题排查学习总结