西西软件园多重安全检测下载网站、值得信赖的软件下载站!
软件
软件
文章
搜索

首页编程开发java → Spring 性能监控器排查出项目中性能瓶颈

Spring 性能监控器排查出项目中性能瓶颈

相关软件相关文章发表评论 来源:西西整理时间:2013/7/7 23:39:52字体大小:A-A+

作者:西西点击:144次评论:0次标签: Spring

手机QQ2017 for Androidv6.6.9 官方最新版
  • 类型:社交聊天大小:37.8M语言:中文 评分:8.0
  • 标签:
立即下载

spring,真是一个好东西;性能,真是个让人头疼又不得不面对的问题。如何排查出项目中性能瓶颈?如何迅速定位系统的慢查询?在这我就不说spring自带的性能监控器了,实在是有些简陋。下面就说说我自己写的这个性能监控器。先看看效果:

2013-07-07 19:19:50,440 WARN [main] [aop.PerformanceInterceptor]
|-144 ms; [HelloService.hellpAop]
|+---10 ms; [AnotherService.childMehhod]
|+---21 ms; [AnotherService.childMehhod3]
|+---+---8 ms; [HelloService.parentMehtod]
|+---12 ms; [AnotherService.childMehhod2] 

其实,利用spring AOP,任何人都可以写一个定制的监控,但大体思路是一样的,就是在被调用方法的开始之前,记录一下开始时间,在调用方法结束之后,记录结束时间,然后,在调用栈退出前,将日志打印出来。光说不练假把式,下面一步一步构建一个性能监控器。

step1.构造拦截器。

直接上代码,拦截器核心代码:

public Object invoke(MethodInvocation invocation) throws Throwable {
try {
String name = extractLogName(invocation);
//记录开始时间
start(name);
return invocation.proceed();
} finally {
//记录方法结束时间
stop();
}
}

因为最终要打印出来,因此,打印的名称必须在记录时间时把被调用方法的名称也记录下来。方法extractLogName就是干这个的。

step2.构造数据结构

首先,我们需要一个线程变量,存储AOP拦截的每个方法的开始时间及结束时间。就用threadLocal变量了,本人还没想到更好的方法。其次,调用过程其实是在一个方法栈(Stack)中旅行了一遍,被调用的方法总是后进先出。每进一个方法,都要记录一个开始时间,每当退出一个方法,都要记录这个方法运行的结束时间。最终,我们将得到一个类似树形的结构。我们需要定义这个结构,以便我们在退出方法栈时能够将每一个方法所耗费的时间都打印出来。

/**
* 保存监控信息变量
* @author donlianli@126.com
*/
private static class StackData {
/**
* 记录根根节点
*/
public StackEntry root;
/**
* 当前正在调用方法节点
*/
public StackEntry currentEntry;
/**
* 堆栈树高度
*/
public int level;
}
/**
* aop方法性能统计实体
* @author donlianli@126.com
*/
private static class StackEntry {
public String logName ;
public long beginTime;
public long endTime;
/**
* 节点所处高度
*/
public int level;
/**
* 调用的子方法
*/
public List<StackEntry> child;
/**
* 上级节点
*/
public StackEntry parent ;
public StackEntry(String logName, long currentTimeMillis) {
this.logName = logName;
this.beginTime = currentTimeMillis;
this.child = new ArrayList<StackEntry>(3);
}
}

好了,结构和拦截器都写好了。只需两步,大工基本就告成了,在拦截器中,在调用方法的前面及后面,记录一个StackEntry对象就可以了。start和stop的代码如下: StackData定义了根节点的结构,StackEntry存储每个方法的开始结束时间,另外在StackData和StackEntry加入level字段,方便后面打印日志。StackData和StackEntry都是作为一个内部类引入的,因为这两个类为了性能,都没有提供一些封装方法,不宜暴露出去(出去多丢人啊)。

public static void start(String logName) {
StackData data = dataHolder.get();
StackEntry currentEntry = new StackEntry(logName, System.currentTimeMillis());
if (data == null) {
data = new StackData();
data.root = currentEntry;
data.level = 1;
dataHolder.set(data);
} else {
StackEntry parent = data.currentEntry;
currentEntry.parent=parent;
parent.child.add(currentEntry);
}
data.currentEntry = currentEntry;
currentEntry.level=data.level;
data.level++;
}
public static void stop() {
StackData data = dataHolder.get();
StackEntry self = data.currentEntry;
self.endTime = System.currentTimeMillis();
data.currentEntry = self.parent;
data.level--;
printStack(data);
}
/**
* 此处还可以进行改进,可以将超时的数据放入一个有界队列
* 里,在另一个线程进行打印。
* @param data
*/
private static void printStack(StackData data) {
if(logger.isWarnEnabled()){
StringBuilder sb = new StringBuilder("\r\n");
StackEntry root = data.root;
appendNode(root,sb);
logger.warn(sb.toString());
}
}
private static void appendNode(StackEntry entry, StringBuilder sb) {
long totalTime = entry.endTime-entry.beginTime ;
if(entry.level ==1){
sb.append("|-");
}
sb.append(totalTime);
sb.append(" ms; [");
sb.append(entry.logName);
sb.append("]");
for(StackEntry cnode : entry.child){
sb.append("\r\n|");
for(int i=0,l=entry.level;i<l;i++){
sb.append("+---");
}
appendNode(cnode,sb);
}
}

1、我们只想找出慢查询,而不想把所有的方法的运行时间都打印出来等等,还有需求?

2、希望有一个开关,平常不需要监控,在出现问题的时候,才把这个监控打开。

好吧,程序员都是被这些需求给搞死的。

在拦截器中增加一个开关switchOn和一个阈值threshold,当switchOn==true的时候,才进行监控,否则不监控。在监控时,如果整个方法的运行时间小于threshold,不打印日志,因为打印日志会IO,会给方法增加额外的开销。改进后代码如下:

  /** 
 * 性能监控开关 
 * 可以在运行时动态设置开关 
 */ 
private volatile boolean switchOn = true;  
/** 
 * 方法执行阈值 
 */ 
private volatile int threshold = 100;  
public Object invoke(MethodInvocation invocation) throws Throwable {  
    if(switchOn){  
        String name = extractLogName(invocation);  
        try {    
                start(name);    
            return invocation.proceed();    
        } finally {    
                stop(threshold);    
        }    
    }  
    else {  
         return invocation.proceed();    
    }  
}  

? 打印日志阈值:

/**
* @param threshold 打印日志的阈值
*/
public static void stop(int threshold) {
StackData data = dataHolder.get();
StackEntry self = data.currentEntry;
self.endTime = System.currentTimeMillis();
data.currentEntry = self.parent;
data.level--;
if(data.root == self && (self.endTime -self.beginTime) > threshold){
printStack(data);
}
}

但这个监控器是运行在spring AOP上面的,并且,监控的方法必须都是通过interface调用的。所以,如果你要使用这个方法,还要确保你是使用的面向接口的编程。不过,如果你的项目没有使用面向接口,可以利用eclipse自带的工具,将公用方法Extract成interface。到此,这个性能监控器几乎算完美了。

spring怎么配置?拦截器怎么配置?你不会连这个都不会吧,那你搜索一下吧。

    寂寞交友
    (73)寂寞交友
    寂寞交友由西西为大家整理一系列火热的社交应用,因为寂寞而交友,随着时代的发展,人们越来越无法满足现有的交际圈子,对于择偶标准的提高,催生出一系列单身男女的情感问题,压抑的情绪需要得到一定的释放,如果你想找寻属于自己的缘分,就赶快下载吧。交友软件排行微信企鹅之子的基数之巨大,寂寞的时候摇一摇,丝男也会有春天不过企鹅之子也有个弊病,依托于的用户资源,环肥燕瘦难以保证。来往来往是拼爹的,背靠大树好乘凉。...更多>>
    生活分享
    (13)生活分享
    生活分享系列是由西西为大家整理,当前的各类软件都是服务于我们的生活,只是着重点不同,有聊天有美食有娱乐有旅行,西西特地为大家准备了一些日常生活中常用的小工具,相信能在平时的日常生活中用到,让我们能更好的品味生活。生活小妙招巧用牙膏若有小面积皮肤损伤或烧伤烫伤,抹上少许牙膏,可立即止血止痛,也可防止感染,疗效颇佳。巧除纱窗油腻可将洗衣粉吸烟剩下的烟头一起放在水里,待溶解后,拿来擦玻璃窗纱窗,效果均不...更多>>
    2015最受欢迎APP
    (27)2015最受欢迎APP
    中国最受欢迎榜单发布,西西第一时间为用户推出最受欢迎排行榜专区下载,在这里你可以下载到中国最受欢迎的,在整个市场,实际上仍旧是占领主导地位。中国最受欢迎榜单前分别是微信手机淘宝搜狗输入法浏览器支付宝钱包浏览器爱奇艺今日头条百度地图酷狗音乐大众点评滴滴出行等等。整个市场可以分成三大类第一类是移动社交移动出行手机地图移动购物等领域已经是大局已定。微信移动社交,以及快的滴滴手机地图手机淘宝移动商城等领域...更多>>
    00后最常用的app
    (29)00后最常用的app
    西西软件园为用户带来后手机必备软件大全,最常用的手机下载,一次性搞定这些热门的社交软件和游戏,让你的生活更加精彩,下面看下部分软件介绍社交软件手机,手机移动版提供多媒体沟通服务,方便用户在移动设备上通过语音图片视频等方式轻松交流。致力于更完美的移动社交娱乐与生活体验乐在沟通年,聊天欢乐亿人微信,微信,数亿人使用,能通过手机网络给好友发送语音文字消息表情图片和视频,还可分享照片到朋友圈。通过摇一摇查...更多>>
    qq2016
    (11)qq2016
    每年年初腾讯都会发布当年最新版的,正是腾讯官方发布的正式版。虽然从版开始就不再以年号明明而是以版本,不过用户还是习惯的年号版本。最新版的因为刚刚发布肯定是有一些细节上的问题的,不过大家可以体验到新版的功能特性也是很不错的,如果你喜欢折腾可以来西西下载版,这里西西给大家提供了最新的电脑版下载及手机版下载。...更多>>

    相关评论

    阅读本文后您有什么感想? 已有人给出评价!

    • 8 喜欢喜欢
    • 3 顶
    • 1 难过难过
    • 5 囧
    • 3 围观围观
    • 2 无聊无聊

    热门评论

    最新评论

    发表评论 查看所有评论(0)

    昵称:
    表情: 高兴 可 汗 我不要 害羞 好 下下下 送花 屎 亲亲
    字数: 0/500 (您的评论需要经过审核才能显示)