java线上应用问题排查方法和工具

linux性能监测点 CPU, Memory, IO, Network

Linux性能监测工具-cpu

基本概念:

  • 上下文切换(Context Switches): 如果可运行的线程数大于CPU的数量,那么OS最终会强行换出正在执行的线程,从而使其他线程能够使用CPU,它会保存当前运行线程的执行上下文,并重建新调入线程的执行上下文。
  • 运行队列(Run Queue): 每个CPU都维护一个线程的运行队列。如果CPU子系统处于高负荷下,那就意味着内核调度将无法及时响应系统请求. 导致结果,可运行状态进程拥塞在运行队列里.当运行队列越来越巨大,进程线程将花费更多的时间获取被执行.
  • Load: 就是指在CPU 队列中有多少数目的线程,以及其中当前有多少进程线程数目被执行的组合. 安全的load一般是cpu的个数
  • CPU利用率(CPU Utilization): CPU 使用的百分比 User Time, System Time, Wait IO, Idle
  • 中断(Interrupts) – Devices tell the kernel that they are done processing。例子, 当一块网卡设备递送网络数据包或者一块硬件提供了一次IO请求.
  • Run Queues - 每个处理器应该运行队列丌超过1-3个线程. 例子, 一个双核处理器应该运行队列丌要超过6个线程。
  • CPU Utiliation - 如果一个CPU 被充分使用,利用率分类之间均衡的比例应该是: 65%-70% User Time, 30%-35% System Time, 0%-5% Idle Time

查看cpu信息
cat /proc/cpuinfo

获取cpu个数
grep ‘processor’ /proc/cpuinfo | wc –l

uptime
显示系统已经运行了多长时间,它依次显示下列信息:现在时间、系统已经运行了多长时间、目前有多少登陆用户、系统在过去的1分钟、5分钟和15分钟内的平 均负载。

相关命令
vmstat (virtual memory statistics) :实时的性能监测工具
1. 上下文切换数目高于中断数目,说明kernel中相当数量的时间都开销在上下文切换线程.
2. 大量的上下文切换将导致CPU 利用率分类不均衡.很明显实际上等待io请求的百分比(wa)非常高,以及user time百分比非常低(us).
3. 因为CPU 都阻塞在IO请求上,所以运行队列里也有相当数目的可运行状态线程在等待执行.

top: 常用参数:H Show all threads by process, 显示各个CPU的运行情况

mpstat (Multiprocessor Statistics) 不但能查看所有CPU的平均状况信息,而且能够查看特定CPU的信息

sar 能够查看历史数据,也可查看实时
sar –q 查看load状况 sar -q 1 3
sar –u 查看cpu使用率 sar -u 1 10
查看历史某一天的,这个很重要可以和以往进行对比sar -u -f /var/log/sa/sa01

对于Java进程的PID, 可以执行

top -Hp [PID]

Linux性能监测工具-内存

Virtual Memory: 虚拟内存就是采用硬盘对物理内存进行扩展
kswapd: kswapd进程负责确保内存空间总是在被释放中.
pdflush: 负责将内存中的内容和文件系统进行同步操作.即写操作返回的时候数据并没有真正写到磁盘上,而是先写到了系统cache里,随后由pdflush内核线程将系统中的脏页写到磁盘上
ps -ef | grep kswapd
ps -ef | grep pdflush

cat /proc/meminfo 查看内存信息
ps aux
RSS:物理内存
ps -p javaid -o rss
sar –r :内存和交换分区使用率
sar -r 1 10

  • 大量的disk pages(bi)被写入内存,很明显在进程地址空间里,数据缓存(cache)也在不断的增长.
  • 在这个时间点上,空闲内存(free) 始终保持在17MB,即使数据从硬盘读入而在消耗RAM.
  • 很明显可以看到buffer cache(buff) 在逐渐的减少中.
  • 同时kswapd 进程不断的写脏页到swap device(so)时,很明显虚拟内存的利用率是在逐渐的增加中(swpd)

Linux性能监测工具- Disk I/O

I/O子系统是Linux 系统中最慢的部分. 这个主要是归于CPU到物理操作磁盘之间距离(盘片旋转以及寻道). 如果拿读取磁盘和内存的时间作比较就是分钟级到秒级, 这就像7天和7分钟的区别. 因此本质上Linux 内核就是要最低程度的降低I/O数.

检查文件系统的磁盘空间占用情况
df -ha

以指定的目彔下的子目彔为单位,显示每个目彔内所有档案所占用的磁盘空间大小
du –ah -d1

iostat
iostat -d -k 2  
-d 表示,显示设备(磁盘)使用状态
-k 某些使用block为单位的列强制使用Kilobytes为单位
2表示,数据显示每隔2秒刷新一次
-x 选项用于显示和io相关的扩展数据

  • tps:该设备每秒的传输次数(Indicate the number of transfers per second that were issued to the device.)。"一次传输"意思是"一次I/O请求"。多个逻辑请求可能会被合并为"一次I/O请求"。"一次传输"请求的大小是未知的。
  • kB_read/s:每秒从设备(drive expressed)读取的数据量;
  • kB_wrtn/s:每秒向设备(drive expressed)写入的数据量;
  • kB_read:读取的总数据量;
  • kB_wrtn:写入的总数量数据量;这些单位都为Kilobytes。
  • rrqm/s:每秒这个设备相关的读取请求有多少被Merge了(当系统调用需要读取数据的时候,VFS将请求发到各个FS,如果FS发现不同的读取请求读取的是相同Block的数据,FS会将这个请求合并Merge);wrqm/s:每秒这个设备相关的写入请求有多少被Merge了。
  • rsec/s:每秒读取的扇区数;
  • wsec/:每秒写入的扇区数。
  • rKB/s:The number of read requests that were issued to the device per second;
  • wKB/s:The number of write requests that were issued to the device per second;
  • avgrq-sz 平均请求扇区的大小
  • avgqu-sz 是平均请求队列的长度。毫无疑问,队列长度越短越好。
  • await: 每一个IO请求的处理的平均时间(单位是微秒毫秒)。这里可以理解为IO的响应时间,一般地系统IO响应时间应该低于5ms,如果大于10ms就比较大了. 这个时间包括了队列时间和服务时间,也就是说,一般情况下,await大于svctm,它们的差值越小,则说明队列时间越短,反之差值越大,队列时间越长,说明系统出了问题。
  • svctm 表示平均每次设备I/O操作的服务时间(以毫秒为单位)。如果svctm的值与await很接近,表示几乎没有I/O等待,磁盘性能很好,如果await的值远高于svctm的值,则表示I/O队列等待太长,系统上运行的应用程序将变慢
  • %util: 在统计时间内所有处理IO时间,除以总共统计时间。例如,如果统计间隔1秒,该设备有0.8秒在处理IO,而0.2秒闲置,那么该设备的%util = 0.8/1 = 80%,所以该参数暗示了设备的繁忙程度, 一般如果该参数是100%表示设备已经接近满负荷运行了(如果是磁盘阵列, 即使%util是100%也未必就到了瓶颈)

sar -b

Linux性能监测工具-network

ifconfig 网络配置信息 
ping用于查看网络上的主机是否在工作TTL是由发送主机设置的, 以防止数据包不断在IP互联网络上永不终止地循环. 转发IP数据包时, 要求路由器至少将TTL减小1.

netstat 用于显示不IP、TCP、UDP和ICMP协议相关的统计数据, 一般用于检验本机各端口的网络连接情况.
常用参数:
-a或–all显示所有连线中的Socket.
-n或–numeric 直接使用IP地址, 而不通过域名服务器
-p或–programs 显示正在使用Socket的程序识别码和程序名称
-t或–tcp 显示TCP传输协议的连线状况
netstat –anpt

sar -n SOCK查看网络连接资源
totsck Total number of used sockets
tcpsck Number of TCP sockets currently in use.

sar -n DEV 查看网络流量

Linux性能监测工具-其他

lsof: 可以列出被进程所打开的文件的信息.
COMMAND: 进程的名称
PID: 进程标识符
USER: 进程所有者
FD: 文件描述符,应用程序通过文件描述符识别该文件。如cwd、txt等
TYPE: 文件类型,如DIR、REG等
DEVICE: 指定磁盘的名称
SIZE: 文件的大小
NODE: 索引节点(文件在磁盘上的标识)
NAME: 打开文件的确切名称

管道
下面这个命令用来统计与1234 端口相连的机器数
netstat -antp | grep 1234 | wc –l
查看java线程
ps -eLf | grep java | wc -l
find
find work/ -name
grep
ps -eLf | grep java | wc -l
awk
对收藏夹apache日志 进行页面排序和统计
awk -F" {print $2} 2011-11-02-taobao-access_log |awk {print $2} |awk -F? {print $1} | awk -F- {print $1} | sort | uniq -c | sort -n +0 -1-r > 11.txt

JVM基础及性能监测工具

JVM体系结构

JVM 堆结构

  • Young Generation :Eden - where new objects get Instantiated, 2 Survivor Spaces to hold live objects during minor GC
  • Old Generation: Objects that are longer-lived are eventually promoted or tenured, to the old generation
  • Permanent Generation: VM and Java class metadata as well as interned Strings and class static variables
  • One survivor space is always empty, serves as destination for minor collections。
  • At the end of the minor garbage collection: the two survivor spaces swap roles; the eden is entirely empty; only one survivor space is in use; and the occupancy of the old generation has grown slightly.
  • Major collections occur when the tenured space fills up, major collections free up eden and both survivor spaces.

JVM 堆大小设置

-XX:NewSize
-XX:PermSize
-XX:MaxNewSize
-XX:MaxPermSize
-Xmn(NewSize= MaxNewSize)
-Xms
-Xmx
-XX:NewRatio=n-
-XX:SurvivorRatio=n

If the application has a small data set (up to approximately 100MB), then select the serial collector with -XX:+UseSerialGC

If the application will be run on a single processor and thereare no pause time requirements, thenlet the VM select the collector, orselect the serial collector with -XX:+UseSerialGC

If (a) peak application performance is the first priority and (b) there are no pause time requirements or pauses of onesecond or longer are acceptable, then let the VM select the collector, or select the parallel collector with -XX:+UseParallelGC and (optionally) enable parallel compaction with -XX:+UseParallelOldGC.

If response time is more important than overall throughput and garbage collection pauses must be kept shorter than approximately one second, then select the concurrent collector with -verbose:gc -Xloggc:/home/admin/logs/gc.log -XX:+PrintGCDetails -XX:+PrintGCDateStamps

JVM主要参数
Behavioral options change the basic behavior of the VM.
Performance tuning options are knobs which can be used to tune VMperformance.
Debugging options generally enable tracing, printing, or output of VMinformation.

OutOfMemoryError
内存问题的两个主要发生区段:
Java内存--包括heap堆内存和permanent区
本地内存--包括JVM进程内存和java使用的第三方本地代码

Java内存不足
Java堆内存heap不足,无法再分配新对象或内存块
permanent区内存不足,无法再加载类到内存中

本地内存不足
物理内存不够,无法再得到内存

第三方本地代码有内存泄漏的Bug,例如oracle oci driver本地代码
JVM的JIT或者JVM本身的Bug

Heap Size Starting Point
From the GC log you will get
Approximation of the Live Data Size (LDS) It is the heap occupancy after each full GC
Approximation of max perm gen size It is the perm gen occupancy after each full GC

Initial Heap Configuration
You can now make an informed decision on choosing areasonable heap size
Rule of thumb
Set -Xms and -Xmx to 3x to 4x LDS
Set both -XX:PermSize and -XX:MaxPermSize to around 1.2x to 1.5x the max perm gen size
Set the generation sizes accordingly

Rule of thumb
Young gen should be around 1x to 1.5x LDS
Old gen should be around 2x to 3x LDS
e.g., young gen should be around 1/3-1/4 of the heap

JVM调优建议
You should try to maximize the number of objects reclaimed in the young generation. This is probably the most important piece of advice when sizing a heap and/or tuning the young generation
Your applications memory footprint should not exceed the available physical memory. This is probably the second most important pieceof advice when sizing a heap
Applications with emphasis on performance tendto set -Xms and -Xmx to the same value, when -Xms != -Xmx, heap growth or shrinkingrequires a Full GC
Applications with emphasis on performance almost always set -XX:PermSize and -XX:MaxPermSize to the same value. Growing or shrinking the permanent generation requires a Full GC too
Try to retain as many objects as possible in the survivor spaces so that they can be reclaimed inthe young generation. Less promotion into the old generation, Less frequent old GCs
But also, try not to unnecessarily copy very long lived objects between the survivors, Unnecessary overhead on minor GCs
Not always easy to find the perfect balance

1. Higher tenuring threshold → promotes fewerobjects

  • Possibly (but not necessarily) longer young GC times
  • Increases the number of objects reclaimed in the young genBetter overall efficiency

2. Lower tenuring threshold → promotes more objects

  • Possibly (but not necessarily) shorter young GC times
  • More load / pressure on the old gen
  • More frequent old GCsCould make fragmentation more severe

Java crash
• A crash, or fatal error, causes a process to terminateabnormally。
• Crash后会产生 hs_err_pid开头的文件,(有时候可能来不及)
• 可能的原因:
– Java虚拟机自身的Bug
– 系统的库文件、API或第三方的库文件造成
– 系统资源的短缺

Crash 文件由以下几部分组成:
• A header that provides a brief description of the crash.
• A section with thread information.
– Thread Information
– Signal Information
– Register Context
– Machine Instructions
– Thread Stack
– Further Details
• A section with process information.
– Thread List
– VMState
– Mutexes and Monitors
– Heap Summary
– MemoryMap

几个crash例子
Crash in Native Code
*

Java性能监测工具

jinfo

prints Java configuration information for a given Javaprocess or core file or a remote debug server.
打印某个参数 -flag

jps

lists the instrumented HotSpot Java Virtual Machines (JVMs)on the target system, 显示java进程及其PID

jmap

内存查看工具
常用参数: -heap -histo –permstat -dump:format=b,file=HeapDump.hprof

jstat

可以查看gc情况
常用参数:gcutil,gcnew,gcold,
jstat -gcutil 929 1000

jstack

线程查看工具. 在得到java进程PID后, 可以通过

jstack -l [PID]

查看java进程的堆栈信息, 参数 -l 表示长列表, 打印关于锁的附加信息,例如属于java.util.concurrent 的 ownable synchronizers列表
如果当前用户不是进程所属用户, 例如启动进程的用户是tomcat, 当前是root, 要使用 sudo -u tomcat jstack -l 77340 这样的方式才能连接, 否则会出现如下错误

jstack Unable to open socket file: target process not responding or HotSpot VM not loaded

参数-m: 打印java和native c/c++ 框架的所有栈信息.可以打印JVM的堆栈,显示上Native的栈帧,一般应用排查不需要使用


jstack java进程id
同killall -3 java

top -H –p javaid
转换 printf 0x%xn 30490

MAT

Eclipse Memory Analyzer: a fast and feature-rich heap analyzerthat helps you find memory leaks and high memory consumption issues

Java VisualVM: a tool that provides a visual interface for viewing detailedinformation about Java technology-based applications (Java applications)while they are running on a Java Virtual Machine (JVM)

JConsole

日志分析, Filter日志, 应用错误日志, Apache日志

web应用服务器诊断问题常用流程

Web应用服务器,主要是load变高。Load高主要是资源不够导致,比如数据库连接池不够。
1 可以通过 top 和 vmstat 查看load状况
2 通过ps -eLf | grep java | wc –l 统计java线程 通过ps -eLf | grep httpd | wc –l 统计 apache线程 这样可以判断是否是机器在超负荷运转. 也可通过日志大小判断.
3 通过filter日志判断系统慢在什么地方.
4 通过debug日志判断cache, 数据库或者依赖的其他系统是否正常.
5 通过dump 线程查看线程都在干什么.
6 通过jstat 查看java gc状况.
7 通过 dump内存 查看java 内存是否存在泄漏.
8 通过sar看看机器历史记录有助问题排查.
9 经验!!

参考

http://java.sun.com/docs/hotspot/index.html
http://java.sun.com/performance/reference/whitepapers/tuning.html
http://java.sun.com/performance/reference/whitepapers/6_performance.html
《深入理解jvm高级特性与最佳实践》
《Java_Performance》
《Linux_Performance_Monitoring 》
《Performance.Tuning.for.Linux.Servers 》
《Troubleshooting Guide for Java SE6 with HotSpot VM 》
《sed and awk, 2nd Edition》