zoukankan      html  css  js  c++  java
  • JAVA优化篇 如何从茫茫日志中找到运行缓慢的线程

    引入

      JAVA提供了一些分析DUMP的工具,比如jmap,visualvm 等

      JAVA还有寻找线程状态的工具,jstack等

      数据库也有检查连接数,连接状态的命令,status,processlist等

      代码中也可以添加一些时间的信息,对比信息发现可优化的地方

      但这些都不是今天要记录的内容,今天要做的是使用一个比较暴力的方式查找出高并发模式下运行缓慢的线程

    正文

      写高并发的时候经常会遇到的问题:

        单独观察每个分支线程或者主线程时,都执行地非常快,但是总体上运行的TPS却并不高,没有达到期望的值

        更换环境,或者调大运行内存和CPU后,情况仍然不见好转

      这时候有个办法是,找出每个线程的运行过程,寻找出耗时较大的代码段,再对代码进行分析

      脚本我已经写好了:

    #!/bin/bash
     parseLog(){
        ##初始值
        upLine="blank"
        last_time_pre="blank"
        last_time_post="blank"
        cat "$1" | while read line
            do
              time_pre=`echo "$line" | awk '{print$1}'`
              time_post=`echo "$line" | awk '{print$2}'`
              if [[ `echo "$time_post" | grep ":"` != "" ]]
                then
                if [[ "$upLine" == "blank" ]]
                then
                  upLine=${line}
                  last_time_pre=`echo "$line" | awk '{print$1}'`
                  last_time_post=`echo "$line" | awk '{print$2}'`
                  total2="$last_time_pre"" $last_time_post"
                  last_time_pre=`date +%s -d "$total2"` 
                  last_time_pre=`expr "$last_time_pre" * 1000`
                  last_time_post=`echo ${last_time_post:9:3}`
                else
                  total="$time_pre"" $time_post"
                  time_pre=`date +%s -d "$total"`
                  time_pre=`expr "$time_pre" * 1000`
                  time_post=`echo ${time_post:9:3}`
                  time_end=`expr "$time_pre" + "$time_post"`
                  time_begin=`expr "$last_time_pre" + "$last_time_post" + "$2"`
                  last_time_pre=${time_pre}
                  last_time_post=${time_post}
                  if [[ "$time_end" -gt "$time_begin" ]]
                    then
                        echo ${upLine} >> result.log
                        echo ${line} >> result.log
                  fi
                  upLine=${line}
                fi
              fi
            done
    }
    
    
    if [[ ! -n "$1" ]] || [[ ! -n "$2" ]] || [[ ! -n "$3" ]]
      then
        echo [log file] [interval millis] [key words]
        exit
    fi
    
    
    awk '{num[$4]++} 
          END{for(k in num)print k,"----",num[k]|"sort -k 3  -rn"}' "$1" |
          head -n 15 | awk '{str[$1]++} END{for (s in str)print s}'| grep "$3" > thread.log
    
    
    ##对上述输出的每一个线程做分析处理,调用parseLog
    cat thread.log | while read line
        do
          grep """${line}"""  "$1" > temp.log
          parseLog temp.log $2
        done
    exit
    View Code

      这个脚本有个基础条件是,分析的日志必须得是按照一定规范输出的日志,输出字段中带有时间和线程名

      脚本传参:

      获得可以分析的所有线程,按照数量排序,并只获得前15个

      接下来对每一个过滤出来的线程做分析处理

      最后就是分析日志的方法了

      主要思路是,用下一行的时间减去上一行的时间,如果超过给定的值,就将两行都输出到指定文件。

      执行效果:

    [utap@host145 logs]$ sh pick_thread.sh bb.log 1 timer
    timerQ_3-service-#146]
    [utap@host145 logs]$ cat result.log 
    2019-11-05 00:02:00.371 [DEBUG] [TaskRule:405][printExpr] [timerQ_3-service-#146] [100000000004] - TaskRule printExpr i-j=2-0, expr[i].elementAt(j).m_min=0, m_max=9999
    2019-11-05 00:02:00.373 [DEBUG] [TaskRule:405][printExpr] [timerQ_3-service-#146] [100000000004] - TaskRule printExpr i-j=3-0, expr[i].elementAt(j).m_min=0, m_max=9999^C

      方便再次使用到吧,地址在 https://github.com/garfieldcgf/notes/tree/master/operations/bin

  • 相关阅读:
    Python基础知识二
    Django1-10-5管理界面中文设置
    人之初
    一句话解释wifi、蓝牙、4g的意思
    如何完美备份旧手机到新手机
    问题解决 --- surface go sd卡槽不识别问题
    反调试技术
    wireshark学习心得
    Socket编程,网络编程
    asm 知识总结
  • 原文地址:https://www.cnblogs.com/garfieldcgf/p/12144690.html
Copyright © 2011-2022 走看看