• 性能实战分析-问题分析(二)


    问题一:线程死锁

    刚进入到首页,或者刷新一下,就一直爱的魔力转圈圈。

    排查法:

    (一)、请求未发送到服务器

    1、负载机问题(cpu、磁盘、内存)

    2、网络问题

    (二)、请求发送到服务器,可能是服务器处理或者返回过程出现问题

    1、应用服务器cpu、磁盘、内存、网络

    2、数据库服务器cpu、磁盘、内存、网络

    3、数据库连接池排队

    4、应用程序代码问题

    5、sql语句执行慢,效率低

    6、JVM堆栈溢出,频繁gc

    7、中间件的线程池排队

     

    排查过程:

    (一)负载机问题最好排查,访问以下tomcat的初始页面就行,下图可以访问,从这张图片,可以侧面论证,我们的负载机是没有问题的,最起码可以访问服务器,网络、服务器的tcpip连接(服务器响应了)没有问题,同时也说明 web 容器的连接池并没有满,因为可以访问我们的 81 端口,那么尝试从其他方面去考虑,看看 jvm 和线程栈。

    单个排查,如何排查??

    1、负载机:随便访问一个页面,比如百度:请求可以访问,证明负载机发送请求是没有问题的。

    2、负载机ping服务器可以ping通,查看网络也是没有问题的。

    3、服务器的tcp,ip连接:netstat。

    4、web容器排队:监控tomcat的连接池是否有空闲线程。server status

    (二)请求发送到服务器,可能是服务器处理或者返回过程出现问题

    1、cpu:top,负载没有问题,cpu使用率没有问题。

    2、线程死锁:jstack  pid >1.log

    3、gc(oom):jstat -gcutil pid 1000

    4、代码

    5、查看文件句柄  lsof     uminit -n  最大文件句柄。

    5、数据库连接池:show processlist   和数据连接池的配置文件,查看是否到达最大连接。

    6、数据库死锁:

    7、慢查询(开启慢查询,查看慢查询日志)

    这里是线程死锁问题:    jstack 8071 > 1.log

    打开1.log日志,我们可以发现,在 http-nio-8082-exec-XXX 这种的线程中状态几乎都为 blocked,说明所有的 nio 的线程锁住了,没有可供使用的线程都被死锁了,代表请求发送到服务器,没有线程可供处理。

    我们看到这里,大概可以判断到应该是线程栈死锁导致的,而且可以看到在锁住的线程调用的方法的路径以及方法名是:org.tarena.common 路径下的 DbUtil类 路径下的 getConnection 方法的 43 行(DbUtil.java:43)

    我们切换到该路径下:这里不可以直接 vi ,将文件 down 到本地利用 jd-gui 反编译 .class文件成为一个 .java 文件。

    # pwd
    /opt/tomcat7/webapps/dangdang/WEB-INF/classes/org/tarena/common
    # ll
    total 36
    -rw-r--r-- 1 root root  737 Jun 24  2016 BooToStrUtil.class
    -rw-r--r-- 1 root root  338 Jun 24  2016 Constant.class
    -rw-r--r-- 1 root root 2697 Jun 24  2016 CookieUtil.class
    -rw-r--r-- 1 root root  371 Jun 24  2016 DangException.class
    -rw-r--r-- 1 root root 2954 Jun 24  2016 DbUtil.class
    -rw-r--r-- 1 root root 1397 Jun 24  2016 DegistUtil.class
    -rw-r--r-- 1 root root  440 Jun 24  2016 EmailUtil.class
    -rw-r--r-- 1 root root 2998 Jun 24  2016 ImageUtil.class
    -rw-r--r-- 1 root root 2237 Jun 24  2016 VerifyUtil.clas
    

      打开反编译文件,显示如下代码:

    //
    // Source code recreated from a .class file by IntelliJ IDEA
    // (powered by Fernflower decompiler)
    //
    
    package org.tarena.common;
    
    import java.sql.Connection;
    import java.sql.DriverManager;
    import java.sql.SQLException;
    import java.util.Properties;
    
    public class DbUtil {
        private static Object ds = new Object();
        private static Object connLocal = new Object();
        private static String driver;
        private static String url;
        private static String dbUser;
        private static String dbPwd;
        public static int maxConnection;
        public static int countConnection;
    
        static {
            Properties pro = new Properties();
    
            try {
                pro.load(DbUtil.class.getClassLoader().getResourceAsStream("dbcp.properties"));
                url = pro.getProperty("url");
                driver = pro.getProperty("driverClassName");
                dbUser = pro.getProperty("username");
                dbPwd = pro.getProperty("password");
                maxConnection = Integer.parseInt(pro.getProperty("maxActive"));
                Class.forName(driver);
            } catch (Exception var2) {
                var2.printStackTrace();
            }
    
        }
    
        public DbUtil() {
        }
    
        public static Connection getConnection() throws SQLException {
            synchronized(ds) {
                Connection connection = null;
    
                try {
                    synchronized(connLocal) {
                        connection = DriverManager.getConnection(url, dbUser, dbPwd);
                        System.out.println(countConnection + ":" + maxConnection + ":" + (countConnection > maxConnection));
                        if (countConnection > maxConnection) {
                            throw new RuntimeException();
                        }
    
                        ++countConnection;
                        System.out.println(countConnection);
                    }
                } catch (SQLException var4) {
                    var4.printStackTrace();
                }
    
                return connection;
            }
        }
    
        public static void closeConnection(Connection conn) throws SQLException {
            synchronized(connLocal) {
                if (conn != null) {
                    synchronized(ds) {
                        System.out.println("->cloase");
                    }
                }
    
            }
        }
    }

    这里是因为加了一个同步锁:synchronized(ds) ,要解决把这里删掉就成了。

     线程同步锁导致的线程死锁,这里把同步锁去掉,替换新的class文件就好了。

    路径:WEB-INF/classes/org/tarena/common

    问题二:堆溢出


    1、压测这个接口: http://192.168.0.38:8080/dangdang/user/image.action  也就是首页获取验证码图片的接口。

    2、压测过程中,top观察现象——cpu高看线程

    # top
    top - 17:14:41 up 8 days,  5:15,  7 users,  load average: 0.22, 0.05, 0.02
    Tasks: 113 total,   2 running, 111 sleeping,   0 stopped,   0 zombie
    Cpu(s): 99.3%us,  0.4%sy,  0.0%ni,  0.0%id,  0.0%wa,  0.0%hi,  0.4%si,  0.0%st
    Mem:   2054084k total,  1978048k used,    76036k free,   135632k buffers
    Swap:        0k total,        0k used,        0k free,   724640k cached
    
      PID USER      PR  NI  VIRT  RES  SHR S %CPU %MEM    TIME+  COMMAND                                                                                                                          
     8591 root      20   0 2551m 640m  14m S 99.0 31.9   3:50.78 java      

    cpu和负载较高

    查看cpu较高的进程下的线程,看这个线程在执行干啥

    把线程id转化为16进制,然后使用jstack pid | grep 【16进制的】

    查看到内存溢出这块来。

    3、访问8080端口,看是否能访问,这里根本访问不了,cpu和负载有问题,这里也能看出是OOM问题。

     或者查看一下gc情况:full gc 次数夸张

    # jstat -gcutil 4232 1000
      S0     S1     E      O      M     CCS    YGC     YGCT    FGC    FGCT     GCT   
    100.00   0.00 100.00 100.00  96.53  91.74     71    0.944  2485  269.686  270.630
    100.00   0.00 100.00 100.00  96.53  91.74     71    0.944  2495  271.024  271.967
    100.00   0.00 100.00 100.00  96.53  91.74     71    0.944  2503  272.043  272.986
    100.00   0.00 100.00 100.00  96.53  91.74     71    0.944  2513  273.024  273.967
    100.00   0.00 100.00 100.00  96.53  91.74     71    0.944  2523  274.110  275.053
    100.00   0.00 100.00 100.00  96.53  91.74     71    0.944  2533  275.096  276.040
    100.00   0.00 100.00 100.00  96.53  91.74     71    0.944  2541  276.077  277.020

    那么,我们有两种方式去分析堆内存溢出

               (4)jmap -histo:live pid

               (5)jmap -dump:live,format=b,file=heap.bin pid

     4、[root@wuzm ~]# jmap -histo:live 4232 > error.log

    这里发现前20没有认识的类和方法,所以这里定位不到类,所以要dump下来文件。

     

     5、[root@wuzm ~]# jmap -dump:live,format=b,file=heap.bin 4232,然后用mat分析,可以看到如下这个类方法里出了问题。

     

    问题三:栈溢出


    点击我的当当,查看页面显示:这里为栈溢出,同时显示了类的路径以及名字

     

  • 相关阅读:
    基于Centos7.2搭建Cobbler自动化批量部署操作系统服务
    Centos 7 Linux系统修改网卡名称为ethx
    解决端口被占用而导致软件运行失败,程序无法启动,无法安装开发工具等问题
    applicationContext.xml文件放置位置不同而导致的jUnit测试的时候路径的不同
    myeclipse中的web项目导入到eclipse中注意事项,项目部署到tomcat后无法访问jsp文件
    SSH项目整合教学Eclipse搭建SSH(Struts2+Spring3+Hibernate3)
    ApplicationContext.xml文件详解
    SSH项目练习的时候报错:[applicationContext.xml]: Invocation of init method failed;
    [转载]快速搭建Spring MVC 4开发环境
    struts配置测试中遇到报错信息,记录下
  • 原文地址:https://www.cnblogs.com/wuzm/p/11403806.html
Copyright © 2020-2023  润新知