【性能监控其他方法】

一、监控jvm的GC情况

1,监控jvm的GC情况
    jstat gcutil pid 1000 100

2,    jmap -heap pid:可以看到java进程的堆的配置信息,各区的空间大小和配置信息
    jmap -histo 5279 | head -20:查看jvm中各个类的实例数、占用内存数量以及类的全名
    jmap -dump:format=b,file=m.hdump 17777:对堆内存进行dump,以文件的形式进行保存下来,可以用jvisualvm等工具对文件进行分析

二、内存泄露有什么现象

1,tps出现大幅波动,并慢慢降低,甚至降为0,响应时间随之波动,慢慢升高
2,通过jstat命令看到,Jvm中Old区不断增加,FullGC非常频繁,对应的FullGC消耗的时间也不断增加
3,通过jconsole/jvisualvm可以看到,堆内存曲线不断上升,接近上限时,变成一条直线

内存泄露怎么定位
1,通过jmap命令:jmap -histo pid | head -20,查看当前堆内存中实例数和占用内存最多的前20个对象
2,通过jvisualvm,进行远程堆dump,然后把dump文件下载下来,用jvisualvm打开进行分析,可以看到更直观的jvm中对象的信息

在什么样的场景下监控内存泄露问题
1,在试压阶段,或任意场景都可以考虑通过jconsole和jstat监控jvm的情况
2,在稳定性场景中,一定要关注Jvm内存使用的情况,在长时间的压测下,最容易看出内存泄露的问题

三、内存泄漏的案例

内存泄漏的案例,先把tomcat的session持久化取消掉
修改:tomcat目录下temp/context.xml,将<Manager pathname=“”/>这行注释打开

JPROFILER工具下载地址:http://www.ej-technologies.com/download/jprofiler/files
linux下安装:rpm -ivh jprofiler_linux_9_1_1.rpm
需要在tomcat/bin/catalina.sh文件配置jvm参数的地方添加
-agentpath:/opt/jprofiler9/bin/linux-x86/libjprofilerti.so=port=8849,nowait

四、

potlight监控
需要新建一个用户useradd xxx,修改密码:passwd xxx
Linux下网卡的配置参数:ethtool eth0,Speed: 1000Mb/s,说明当前网卡的上限是1000/8=125MB

Linux监控命令:详细命令见word文档
cpu监控:top
内存监控:free -m
磁盘繁忙度监控:iostat -x -k 1
磁盘空间监控:df -h
网络监控:nmon
其他监控:vmstat
Linux磁盘速度测试:dd if=/dev/zero of=/export/ddtest bs=8k count=1000000 oflag=direct
=========================================================================================
1,nmon
命令:./nmon -fT -s 10 c 100,每10s采样一次,一共采样100次,并在当前目录下生成监控结果文件
重点关注四项
    cpu:cpu_all
    disk:diskbusy
    memory的使用百分比:(total-free-buffer-cache)/total
    netIO:eth0-total

2,spotlight监控
=========================================================================================    
线程的五种状态
 * 新建:new
 * 运行:runnable
 * 等待:waitting(无限期等待),timed waitting(限期等待)
 * 阻塞:blocked
 * 结束:terminated

线程的两种监控方式:
构造线程状态的Java脚本:java -jar thread-test.jar [1|2|3|4]
构造不同的状态的线程
 1:runnable
 2:waitting
 3:timedWaitting
 4:blocked


2,jvisualvm,图形界面的方式

    jvisualvm
    监控之前先对jvm加监控参数,在tomcat的bin目录下,catalina.sh文件中,搜索JAVA_OPTS=,在if里面,添加:
    -Dcom.sun.management.jmxremote.port=10086 -Dcom.sun.management.jmxremote.ssl=false -Dcom.sun.management.jmxremote.authenticate=false -Djava.rmi.server.hostname=192.168.210.45
    1-改port
    2-改hostname为本机ip
    
3,jstack pid:命令行方式
    "Mytesting..." prio=10 tid=0xb7545800 nid=0x15cf waiting for monitor entry [0xb4ba8000..0xb4ba9070]
   java.lang.Thread.State: BLOCKED (on object monitor)
    at ThreadStatusTest.blocked(ThreadStatusTest.java:53)
    - waiting to lock <0x8bd6a238> (a java.lang.Object)
    at BlockedStatus.run(ThreadStatusTest.java:73)
    at java.lang.Thread.run(Thread.java:619)
======================================================================================        
4,top、iostat、vmstat命令见文档    
[root@zhoucentos mysql]# free -m
             total       used       free     shared    buffers     cached
Mem:           498        491          7          0         14         32
-/+ buffers/cache:        443         55
Swap:         2015         97       1918

第一行代表是从系统的角度来统计的数据,其中的used包含了buffers和cached
第二行是代表从应用程序的角度来统计的数据,used是真正应用程序占用的内存
第一行的used = 第二行的used+buffers+cached

连接数的查看命令:netstat -an|grep 8080 |wc -l
redis:主要关注网络流量和连接数,通过netstat命令或者info命令可以查看连接数 

1,慢查询
    show variables like '%slow%'
    show global status like '%long_query%'
    具体配置见文档
    mysqldumpslow -s at 10 slow.log
    
2,连接数
    show variables like '%connections%'
    show status like '%thread%'
    其中:
    Threads_connected 当前打开的连接的数量
    Threads_cached   线程缓存内的线程的数量                        
    Threads_created  创建的线程数                       
    Threads_running  激活的(非睡眠状态)线程数         
    
    show status like '%connection%'
    Connections 试图连接MySQL服务器的次数
    max_connections:整个MySQL允许的最大连接数;
    
3,缓冲池
    show variables like '%buffer_pool_size%'
    show status like '%buffer%';
    其中:
    Innodb_buffer_pool_reads:缓冲池中没有读到数据,而从磁盘内读取的次数
    Innodb_buffer_pool_read_requests:来缓冲池中读数据的次数
    Innodb_buffer_pool_pages_total:缓冲池的总页数(内存是以页为单位)
    Innodb_buffer_pool_pages_free:缓冲池中处于空闲状态的页数
    
    命中率:innodb_buffer_read_hits=(1-Innodb_buffer_pool_reads/Innodb_buffer_pool_read_requests)*100%
    
    
以上要掌握
    
=================================================================
    show variables like '%query_cache%';
    show status like '%Qcache%'
    Query_cache_hits=(Qcache_hits/(Qcache_hits+Qcache_inserts))*100%

5,线程缓存(连接池)-- 了解
    show variables like '%thread%'
    show status like 'connections'
    show status like '%thread%'
    Threads_Cache_Hit=(Connections-Threads_created)/Connections*100%

6,表锁和行锁 
    show status like '%lock%';
    存储引擎:早期mysql用的,MyISAM,现在都用Innodb
    MyISAM:支持表锁
    Innodb:支持行锁
    

五、

Jvm常用参数
---------------------------------------
堆内存 = 年轻代+老年代+永久代
年轻代 = Eden+Survivor
Survivor = From Space+To Space
---------------------------------------
年轻代 = Eden+From Space+To Space
堆内存=Eden+From Space+To Space+老年代+永久代
====================================

-Xms2048m,初始堆大小,建议<物理内存的1/4,默认值为物理内存的1/64
-Xmx2048m,最大堆大小,建议与-Xms保持一致,默认值为物理内存的1/4
-Xmn512m,新生代大小,建议不超过堆内存的1/2
-Xss256k,线程堆栈大小,建议256k
-XX:PermSize=256m,永久代初始值,默认值为物理内存的1/64
-XX:MaxPermSize=256m,永久代最大值,默认值为物理内存的1/4
-XX:SurvivorRatio=8:年轻带中Eden区和Survivor区的比例,默认为8:1,即Eden(8),From Space(1),ToSpace(1-XX:MaxTenuringThreshold=15:晋升到老年代的对象年龄,每个对象坚持过一次MinorGC后对象年龄+1,默认值是15,年龄超过15进入到老年代,该参数在串行GC时有效
-XX:PretenureSizeThreshold=3145728:单位字节,只对Serial和ParNew两款收集器有效,新生代采用Parallel Scavenge GC时无效,大于这个值的对象直接在老年代进行分配

非稳定参数,使用方式主要有以下三种:
1,-XX +<option>:开启option参数
2,-XX -<option>:关闭option参数
3,-XX <option>=<value>:将option参数的值设置为value

client模式,Jvm默认垃圾收集器
UseSerialGC:新生代采用Serial收集器,老年代采用Serial Old收集器

server模式,Jvm默认垃圾回收期
UseParallelGc:新生代采用Parallel Scavenge收集器,吞吐量优先的收集器,老年代采用Serial Old收集器

-XX:+UseConcMarkSweepGC:默认关闭,ParNew+CMS+Serial Old,当CMS收集器出现ConcurrentModeFailure错误(Jvm预留空间不足以容纳程序使用),采用后备收集器Serial Old
CMS相关参数
-XX:CMSInitiatingOccupancyFraction=80:CMS收集器在老年代空间被使用多少时触发FullGC,默认为92
-XX:+UseCMSCompactAtFullCollection:CMS收集器在FullGC时开启内存碎片的压缩,默认开启
-XX:CMSFullGCsBeforeCompaction=8:执行多少次不压缩FullGC后,进行一次压缩,默认是0(代表每次FullGC都进行压缩)
-XX:+UseCMSInitiatingOccupancyOnly:使用手动定义初始化定义开始,禁止hostspot自行触发CMS GC
-XX:ParallelGCThreads=8:并行收集器的线程数,此值最好配置与处理器数目相等 同样适用于CMS

日志参数:
-XX:+HeapDumpOnOutOfMemoryError:当发生内存溢出时,进行堆内存dump
-XX:+PrintGCDetails:打印GC的详细信息
======================================================================

企业实际配置
-server -Xms1028m -Xmx1028m -XX:PermSize=256m -XX:MaxPermSize=256m -Xmn512m -XX:MaxDirectMemorySize=1g -XX:SurvivorRatio=10 
-XX:+UseConcMarkSweepGC 
-XX:+UseCMSCompactAtFullCollection 
-XX:CMSMaxAbortablePrecleanTime=5000 
-XX:+CMSClassUnloadingEnabled 
-XX:CMSInitiatingOccupancyFraction=80 
-XX:+UseCMSInitiatingOccupancyOnly 
-XX:ParallelGCThreads=8 
-Xloggc:/home/admin/logs/gc.log 
-XX:+PrintGCDetails 
-XX:+PrintGCDateStamps 
-XX:+HeapDumpOnOutOfMemoryError
-XX:HeapDumpPath=/home/admin/logs/java.hprof

六、

案例:慢sql和执行计划
http://192.168.0.110:8080/PerfTeach/SlowQuery?cardNO=1000009
http://192.168.0.110:8080/PerfTeach/SlowQuery?cardNO=1000009&course=Math 

现象:tps很低,响应时间很长,数据库服务器cpu很高(接近100%),应用服务器负载比较低

慢查询的配置和抓取:略

执行计划
在sql语句前加上explain,可以分析这条sql语句的执行情况
explain select * from teacher where 

Type列可能的值:
Const:表中只有一个匹配行,用到primary key或unique key
Eq_ref:唯一性索引扫描,key的所有部分被连接联接查询使用,且key是unique或primary key
ref:非唯一性索引扫描,或只使用了联合索引的最左前缀
Range:索引范围扫描,在索引列上进行给定范围内的检索,如between,in(1,100)
Index:遍历索引...
All:全表扫描

Prossible key:使用哪个索引能找到行
Keys:sql语句使用的索引
rows:mysql 根据索引选择情况,估算查找数据所需读取的行数

---------------------------------------------------
案例:线程死锁
http://192.168.1.110:8080/PerfTeach/DeadServlet
线程死锁就是有两个线程,一个线程锁住了资源A,又想去锁定资源B,另外一个线程锁定了资源B,又想去锁定资源A,两个线程都想去得到对方的资源,而又不愿释放自己的资源
从而造成一种互相等待,无法执行的情况

现象:出现死锁后,tps降为0,压力测试工具无法得到服务器的响应,服务器硬件资源空闲,通过jvisualvm去查看线程情况,至少两个线程一直处于红色的阻塞状态
死锁经常表现为程序的停顿,或者不再响应用户的请求。从操作系统上观察,对应进程的CPU占用率为零

定位方法:通过jvisualvm或者jstack,进行线程dump,对现在状态进行分析,获取到哪行代码导致的死锁,如:

Found one Java-level deadlock:
http-bio-8080"-exec-162":
  waiting to lock monitor 0x0818abac (object 0x84b40ad0, a com.lee.domain.Order),
  which is held by ""http-bio-8080"-exec-158"
""http-bio-8080"-exec-158":
  waiting to lock monitor 0x08188cd0 (object 0x84b3bc48, a com.lee.domain.Order),
  which is held by ""http-bio-8080"-exec-162"

Java stack information for the threads listed above:
死锁一般解决思路:
减少嵌套加锁
减小锁粒度

---------------------------------------------------
线程info信息块:
1. "Timer-0" daemon prio=10tid=0xac190c00 nid=0xaef in Object.wait() [0xae77d000]
2.  java.lang.Thread.State: TIMED_WAITING (on object monitor)
3.  atjava.lang.Object.wait(Native Method)
4.  -waiting on <0xb3885f60> (a java.util.TaskQueue)     ###继续wait 
5.  atjava.util.TimerThread.mainLoop(Timer.java:509)
6.  -locked <0xb3885f60> (a java.util.TaskQueue)         ###已经locked
7.  atjava.util.TimerThread.run(Timer.java:462)
* 线程名称:Timer-0
* 线程类型:daemon
* 优先级: 10,默认是5
* jvm线程id:tid=0xac190c00,jvm内部线程的唯一标识(通过java.lang.Thread.getId()获取,通常用自增方式实现。)
* 对应系统线程id(NativeThread ID):nid=0xaef,和top命令查看的线程pid对应,不过一个是10进制,一个是16进制。(通过命令:top -H -p pid,可以查看该进程的所有线程信息)
* 线程状态:in Object.wait().
* 起始栈地址:[0xae77d000]
* Java thread statck trace:是上面2-7行的信息。到目前为止这是最重要的数据,Java stack trace提供了大部分信息来精确定位问题根源。

---------------------------------------------------
性能瓶颈定位整体思路,从前到后,从表象到内部
1,首先排除压力机的性能情况,包括cpu、内存
2,应用服务器的硬件指标,cpu,内存,网络IO(ethtool eth0),磁盘IO
3,其他服务器,比如数据库服务器,依赖的其他应用服务器
4,看应用服务器的日志,tomcat下看的是catalina.out,用tail -200 catalina.out ,看cause by:xxx TimeOut
5,tps比较低,应用服务器cpu比较高,jvisualvm看下java进程,消耗cpu的方法
6,tps比较低,应用服务器cpu也比较低,可能是java程序的线程阻塞或死锁,也用jvisualvm看,如果红色的线程比较多,就是阻塞的原因,jstack pid
7,tps比较低,响应时间比较长,首先要先弄清楚请求的流向,比如:LR-->nginx-->tomcat-->java-->数据库-->缓存-->外部依赖--返回,如果排除到其他的问题
    可以在java代码加时间戳的方法来定位响应时间比较长的问题
8,tps缓慢降低,或大幅降低,tps大幅波动,用jmap或者jvisualvm进行堆内存dump,用jstat -gcutil,看看是否有内存泄露趋势,Jvm的FullGC是否频繁
9,排查连接数相关的内容,包含tomcat的连接数、mysql的连接数,某端口的连接数:netstat -an|grep 8080 | wc -l
    关于连接数,要看2方面,首先是中间件最大配置的连接数,然后就是当前连接数
    tomcat的当前连接数用netstat可以看,略。最大连接数在
    一般tomcat需要设置的参数,第一个就是连接数在conf/server.xml里配置
    <Connector port="8080" protocol="HTTP/1.1"
               connectionTimeout="20000"
               redirectPort="8443" />
    maxThreads="200" 表示最多同时处理200个连接,默认值是200
    acceptCount="100" 当同时连接的人数达到maxThreads时,还可以接收排队的连接,超过这个连接的则直接返回拒绝连接。默认值为100    
    第二个jvm的参数,在bin目录下的catalina.sh
    if [ -z "$LOGGING_MANAGER" ]; then
    JAVA_OPTS="$JAVA_OPTS -Dcom.sun.management.jmxremote.port=10086 -Dcom.sun.management.jmxremote.ssl=false -Dcom.sun.management.jmxremote.authenticate=false -Djava.rmi.server.hostname=192.168.1.117 -Djava.util.logging.manager=org.apache.juli.ClassLoaderLogManager -Xms512m -Xmx512m -Xmn128m -XX:MaxPermSize=64m"
    else
    JAVA_OPTS="$JAVA_OPTS $LOGGING_MANAGER"
    
---------------------------------------------------
线程阻塞问题-log4j日志级别问题
http://192.168.1.110:8080/PerfTeach/Block?userId=1
log4j.xml中设置的日志级别,程序会打印在此级别之上日志
Error
Warn
Info
debug
级别越低,日志越多
-------------------------------------------------
tomcat连接数设置
netstat -an|grep 8080 |wc -l :查看8080当前端口建立的连接数

maxThreads="200" 表示最多同时处理200个连接,默认值是200
minSpareThreads="10" 表示即使没有人使用也开这么多空线程等待,默认是10
(tomcat7可能不支持)maxSpareThreads="75" 表示如果最多可以空75个线程,例如某时刻有80人访问,之后没有人访问了,则tomcat不会保留80个空线程,而是关闭5个空的。
acceptCount="100" 当同时连接的人数达到maxThreads时,还可以接收排队的连接,超过这个连接的则直接返回拒绝连接。默认值为100
----------------------------------------------
响应时间长
http://192.168.1.110:8080/PerfTeach/TimeMonitor?id=1

-------------------------------------------------
数据库架构的调优
    --读写分离:主从配置
    --分库分表:根据一个id来路由库名和表名,id%10
        user_1
        user_2
        user_3
        ...
        user_10
        
    --硬件调优
        普通磁盘
        SSD
        fusionIO卡
    
6,应用程序架构调优
    --同步-异步
    --加缓存
    --循环调用和批量调用
        接口1,单条数据查询
            for (){
                调用接口1
            }
        接口2
            调用接口2        
            
    --分布式集群部署,加实例,加机器

猜你喜欢

转载自www.cnblogs.com/frankruby/p/10696292.html