java问题定位思路总结
很久没写文章了,java相关问题定位方法很久之前就在酝酿,一直没时间下笔,有时候需要按项目的方式逼着自己做些事情。前段时间看到一些相关文章,自己也尝试做下相关总结,如有错误还望大家多多指正。
快速准确的定位出在线问题,需要不断地学习总结,抽丝剥茧,剖析出问题本质。定位一个问题的过程,就像是医生诊治的过程一样,需要通过望闻问切、听诊、医疗器械等方式探查病情,并根据人的生理机制,分析问题原因,对症下药。定位进程问题与之有异曲同工之处,只不过诊治过程是与人沟通,定位进程问题是与机器、进程、代码逻辑沟通。
与人交谈,需要大家都理解的语言,同理,与机器、进程交谈(即定位问题)也需要大家都能理解的语言,即命令和工具。机器不会主动说话但会被动回答,定位问题的过程,需要我们主动问机器,机器会根据我们的提问,返回他当前的感受。因此,我们需要熟知一些基本的工具及返回结果的含义。
工欲善其事必先利其器,首先我们需要了解相关基础原理及工具使用,原理包括机器层面、linux相关原理、jvm相关原理、服务相关原理等,工具包括linux各种命令、jvm jdk相关命令、各个服务metric指标和操作工具等。下面将由下到上(机器->操作系统->jvm->服务)从4个方面介绍,但是实际定位问题时的路径是由上到下(服务->jvm->操作系统->机器)。
机器架构
现今大部分计算机都基本遵循冯·诺伊曼结构
,基本包括cpu、内存、磁盘、网卡(此文对显卡/交换机/路由器等其他设备不做讨论)。
- cpu:负责运行机器指令,是机器的核心,cpu相关的问题也是生产中经常遇到的问题,按指令集分为CISC和RISC,按多核组织方式分为SMP/MPP/NUMA,当前大多数服务器使用NUMA架构。
- 内存:包含L1/L2/L3 cache、主存、虚拟内存等,缓存主要解决cpu速度和内存读写速度差距较大问题,由于缓存是顺序预读机制,在编写程序时注意顺序处理数据,可提高缓存命中率,程序性能得到很大提升。
- 磁盘:按磁盘类型分为HDD/SSD/HHD/M.2等,按接口协议分为sata、sas、scsi、nvme等。不同接口和不同磁盘类型影响磁盘的整体性能。传统hdd硬盘,涉及到扇区、磁道寻址等,顺序读写和随机读写性能差距很大,可能达到几百倍,一般情况下,单裸盘,顺序读写可以达到200MB/s左右,随机读写可以达到60MB/s左右。ssd从存储机制层面解决了hdd的问题,顺序和随机读写性能差距不大,不同的接口和ssd类型读写性能差距较大,如nvme比sata性能高至少2倍以上。
- 网卡:按速度分为1000Mbps千兆、10Gbps万兆、40Gbps、100Gbps。机器可以选择双网卡做bond以达到负载均衡及容灾效果。
linux相关
从硬件层面了解了相关组件,下面最重要的就是要了解操作系统的原理,应用程序与硬件直接是通过操作系统进行关联、交互的。现在大部分服务器都是基于linux的,因此,熟悉linux的基本原理和基本命令使用,是定位问题的关键所在。linux内核是个非常复杂的系统,对大多数人,只需要掌握基本概念以及相关工具的使用即可。
cpu相关
分析cpu常用的工具有top、ps、sar、mpstat、dstat、pidstat、perf、strace、proc等,简单介绍两个常用的。
top
top命令是查看cpu的基本命令,可以得到的信息有:
- 系统启动时长:
up xxx
,查看系统启动时间还可用who -b/last reboot
等命令 - 最近1/5/15分钟平均负载:
load average xxx
,表示正在运行和等待运行的进程数,注意cpu利用率高和磁盘利用率高都可能导致负载上升,需注意这两种情况。通过3个值也可以看出当前机器是逐渐变空闲还是变繁忙 - 进程数:
Tasks: xxx
,总数、running数、sleeping数、stopped数、zombie数 - cpu利用率:
%Cpu(s) xxxx
-
us/sys/ni
表示用户空间、内核空间、用户空间内改变优先级占用cpu百分比 -
id
:空闲态cpu占比,此值较高表示cpu较空闲 -
wa
:等待输入输出cpu占比,此值过高一般表示磁盘压力过大 -
hi/si/st
:硬中断、软中断、偷走时间(如虚拟机等)
-
- 内存情况、swap情况
- 进程详细情况:虚拟内存使用、实际内存使用、共享内存使用等
top可以定位到某个进程是否有问题,top -Hp $pid
可查看指定进程的所有线程情况,基本定位到是某个线程的问题,然后根据线程ID,使用jstack命令查看java进程相关线程的情况即可(注意jstack的输出为16进制线程号,需做转换)。
ps
可查看进程的状态
-
ps axu | grep xxx
:可查看进程的pid、启动用户、内存占用情况、进程状态、启动命令等信息- 进程状态有:
D/R/S/T/W/X/Z/</N/L/s/l/+
,如果出现大量的D、Z状态进程则需额外注意,进程一般情况下处于S/R/l状态
- 进程状态有:
-
ps -ef | grep xxx
:可查看进程的pid和父进程id -
ps -eLf | grep xxx
:可查看所有轻量级进程(LWP)情况
proc文件系统
proc文件系统中,存放内核中运行状态的各种信息,了解这个文件内含义,非常重要,如机器cpuinfo、meminfo、vmstat、diskstats、net、进程的env/stat/fd等各种详细信息,基本上大部分工具的结果都是从proc中获取相关信息进行汇总后的展示。
关于cpu,生产中也踩过不少坑,如机器温度高被降频、cpu performance模式未开启、cpu中断affinity设置等问题。
内存相关
内存分析,常用的工具有free、top、vmstat、pmap、ps、slabtop、cachestat、/proc/meminfo、/proc/vmstat等
- free:查看当前内存、swap、buff/cache等使用情况
- vmstat:
-a/-s
显示更加详细信息,如active/inactive mem
、swap等信息,其中inactive涉及到LRU页面回收算法,当inactive过多,说明页面较慢,可能磁盘有问题(详情可了解INACTIVE_ANON与INACTIVE_FILE
) - top:可按进程的mem进行排序,找到占用内存较高的进程,进行分析处理,这里需注意
VIRT/RES/SHR
三者区别 - cachestat:可查看pagecache使用及命中率情况
磁盘相关
通常情况下,磁盘是最慢的物理设备,因此针对磁盘问题的定位和调优,是需要着重考虑的。关于磁盘的常用命令有:iostat、iotop、df、du、fdisk、blktrace、cachestat等。
磁盘的常用调度策略有:noop/deadline/cfq
,可在/sys/block/xxx/queue/scheduler
中动态调整,新内核默认开启scsi_mod.use_blk_mq
,新的磁盘调度策略为bfq/kyber/mq-deadline/none
。
磁盘的文件系统有xfs、ext4等,还可做阵列,以提高可用性、性能等,如raid0、raid1、raid5、raid10等。
- iostat:
-dx sdx 1
,查看磁盘性能指标,包括读写merge情况、读写次数、读写速率、读写队列、读写wait、磁盘服务时间svctm、磁盘使用率util - iotop:可以查看磁盘总读写速率、每个进程/线程的读写情况,按左右键可指定排序列,找到对应的进程或线程,分析相关问题
- df:查看磁盘使用情况,
-T
查看磁盘类型,-i
查看inode使用 - blktrace:当遇到磁盘问题时,用blktrace分析io过程中那个过程最耗费资源,如请求排队、排序、写盘等过程
- fdisk:列出磁盘信息,分区操作等
网络相关命令
网络问题的分析是最难的,涉及的面非常广,如cpu调度、affinity设置、内存配置、队列配置、网卡配置、交换机配置、tcp协议配置等等。
网络常用的命令有:ifconfig、ethtool、netstat、ss、tcpdump、iftop、ping、traceroute、dig、wget、scp、ssh等。网卡有接收队列和发送队列,涉及到ringbuffer。tcp有半连接队列和全连接队列,涉及到server端握手过程。如果遇到drop、overflow、ofoprune等情况,则需要考虑ringbuffer、tcp_max_syn_backlog/somaxconn、rmem_max等值是否合理,另外需要查看对应内存的使用情况。
- ifconfig:查看网卡基本信息,如ip地址、mac地址、接收/发送包情况(error、drop、overrun等)
- ethtool:查看网卡基本信息,如网卡速度,
-g/-G
可查看/调整ring buffer大小 - netstat:
-s
可以看各网络协议包发送情况,tcp/udp等。当连接数很多时,查看每个连接的信息会非常慢,需使用ss - ss:
-anp
,查看每个连接的状态、接收/发送队列、ip端口等信息,还可查看全连接队列的大小(默认50) - iftop:查看网络使用排行榜和总体网络使用速率,
-P
可显示本机和对端端口, - tcpdump:抓包工具
其他常用命令
grep、tail、xargs、awk、cat、find、less、sort、uniq、tr、comm、for、while等常用命令的灵活使用,可帮助分析和处理日志文件,如切分、统计个数、排序、交集等,帮助发现各种隐藏问题。
jvm相关原理
定位jvm相关问题,需要深入学习java内存模型、垃圾回收、相关工具使用。
java内存模型
学习堆、栈、堆外、元空间、happens-before原则、java异常体系等概念。
- 堆:java对象分配空间,垃圾回收重点区域,此空间可能会抛出OutOfMemoryError。分为Eden/Survivor/Old三个区
- 栈:本地方法栈/虚拟机栈、局部变量表、引用、方法返回地址等,此空间可能会抛出StackOverflowError/OutOfMemoryError
- 堆外
- 元空间:每个加载器分配专门的空间
- java异常体系(基类Throwable)
- Error:非检查异常,程序无法处理,如OutOfMemoryError、StackOverflowError、NoClassDefFoundError、NoSuchMethodException等
- Exception:程序可处理
- RuntimeException(非检查异常):NullPointerException、NumberFormatException、ArrayIndexOutOfBoundsException、ArithmeticException、ClassCastException等
- 非运行时异常(检查异常)
垃圾回收
学习young/old区、STW、SafePoint、SafeRegion、串行/并行/并发、复制、标记清除、标记整理、8种垃圾回收器等概念。
- young区:2个eden+1个survivor,使用复制算法,所有young的gc都是stw的
- old区:使用标记清除或标记整理算法
- STW:stop-the-world,严重影响程序性能,尽量减少发生频次
- SafePoint/SafeRegion:所有线程进入安全检查点,才能进行gc
- 串行/并行/并发:垃圾回收器有串行、并行和并发,串行和并行会产生STW,并发不会
- 8种垃圾回收器
- young区:Serial、ParNew、ParallelScavenge
- old区:CMS、Serial-Old、Parallel-Old
- both:G1、ZGC
- 当前主流的还是cms、g1,ZGC是方向
相关工具
熟悉常用工具:jstack、jmap、jstat、jinfo、mat、arthas、nmt、perf、strace、gdb等
jstack:打印线程栈
jmap:dum内存、
-histo:live
会触发fgcjstat:动态打印内存各个区域使用情况
jinfo:查看jvm相关参数,可动态设置一些jvm参数
mat:分析jmap dump下的内存
arthas:阿里开源的强大分析工具
nmt:定位jvm直接内存使用情况(通过本地方法使用的内存无法追踪)
strace:跟踪系统调用情况
gdb:dump内存
gdb --batch --pid 11 -ex "dump memory a.dump 0x7fd488000000 0x7fd488000000+56124000"
,然后使用strings a.dump | less
或者hexdump -C a.dump | less
或者view a.dump
查看。用于分析堆外内存perf:perf record、perf report
基本问题定位
-
cpu问题(cpu使用率过高、死锁、卡住等情况)
- top找到对应的进程,top -Hp找到对应的线程,jstack找到对应的线程栈(注意16进制转换)
- arthas、strace、perf进行性能分析
堆内内存问题:jstat查看内存使用情况及gc情况,jmap -histo:live/jmap dump结合mat分析内存使用情况
堆外内存问题:nmt跟进,gdb dump
服务原理
掌握上述基本原理及工具,还需要掌握服务的原理,构建完善的监控指标,才能有的放矢,知道问题出错的地方并做相关验证工作。
hive
整体过程为:sql -> ast -> 逻辑执行计划 -> 物理执行计划 -> 执行 -> 返回。
- sql -> ast:使用antlr编译,需满足语法规范
- ast -> 逻辑执行计划:解析table/join/gby/union/udf等,并做优化,如条件下推、分区剪枝、列剪枝、distinct转换、mapjoin、join顺序调整等
- 逻辑执行计划 -> 物理执行计划:按ReduceSinkOp切分为多个MapRedTask、MoveTask等,并做优化,如小文件合并、task合并等
- 执行:按task的dag图执行mr,需注意map/reduce/am相关问题(预聚合、数据倾斜问题)
spark(on yarn)
主要有3个组件服务:driver、am、executor。
- driver:负责资源管控、dag切分、stage依赖调度、task分发、executor管理,是高频出现问题的组件
- am:spark支持client/cluster模式,am负责与yarn交互,主要负责资源的申请和释放
- executor:负责task执行、数据读写与存储(broadcast/persist/cache)、注册并读写shuffle数据,需注意gc问题、task分发问题
- job/stage/task分析,需注意数据倾斜问题、task分发均衡问题等
yarn
主要有三个组件:RM(主从)、NM、ZK。
- RM:负责总体资源的管控和协调,如nm的注册及心跳信息处理、队列资源的管理和分配、application的管理,重要指标有rpc处理时间、各个队列调度指标、container分配时间、gc情况等
- NM:负责管理当前机器资源、拉起释放和监控container、日志聚合等
- ZK:记录app状态信息,保证宕机恢复;用于选主
hdfs
主要有五个组件:zkfc、nn、jn、dn、zk。
- zkfc:自动选主
- nn:主节点,分为active/standby,管理所有存储资源、目录树、文件信息、block信息、权限信息等;接收并处理元信息请求,如mkdir、rm等;lease管理等。重要指标有rpc处理时间、排队时间、元信息情况、gc情况等
- jn:journal node,负责edit log读写,保证active/standby节点数据保证一致,保证高可用
- dn:负责管理当前节点的存储资源、block信息、数据存储与转发等。重要指标有rpc处理时间、读写数据情况、磁盘io情况、读写block情况、block report情况、gc情况等
- zk:选主
kafka
主要有三个组件:controller、broker、zk。
- controller:负责元信息管理,topic的创建、删除、扩partition、reassgin等
- broker:管理当前节点资源,partition数据读写、主从同步、leader和follower管理、consumerGroupCoordinator、offset管理
- zk:存放topic、partition、权限等元数据,controller选主等
主要指标有ur个数、partition主从个数、isr情况、network/request idle指标、request/response queue size、active controller个数、producer/consumer读写情况、lag情况、cache情况、jvm情况等