在软件开发中,性能监控是一个重要的环节,它可以帮助了解应用程序在不同时间段的表现,从而进行相应的优化。本文将介绍一种使用Unity拦截器机制实现方法性能监控的方法,包括设计模式的应用、日志记录的实现以及如何通过日志分析性能问题。
性能监控通常需要记录方法调用的次数、最大时间和最小时间等信息。这些信息可以按分钟或小时的间隔进行记录,也可以自定义间隔。每个间隔定义为一个时间周期,例如从01:00:00到01:00:59.59。这样,就可以按天/周等时间段绘制日志图表,并与一天中的时间精确对应,而不是从程序启动时的分钟数。
拦截器是一种设计模式,通常称为装饰器模式,它能够改变被拦截(或装饰)对象的功能。Unity和其他容器有特定的机制,可以在不编写特定装饰器类的情况下,动态地装饰任何对象,这种机制称为拦截。
使用拦截器的原因是为了设计横切关注点,这是面向方面编程的一部分。一个常用的示例是日志记录。例如,如果想记录任何方法的性能,如果不使用任何设计模式,将不得不在每个想要测量性能的方法中编写一些日志记录代码。这将导致大量重复的代码,并会稀释方法的核心业务代码,这将使其难以阅读和维护。
本文实现的日志横切关注点使用了Unity及其拦截器机制。可以选择PostSharp或其他特定的AOP框架,或者选择具有拦截器机制的不同DI容器来实现这一点。
在设计时,使用了SOLID原则,特别是开放/封闭原则,使其对扩展开放(例如,一个新的时间间隔类),但对修改封闭。
当调用配置了使用仪器拦截器的方法时,Unity会拦截调用并测量调用所花费的时间。拦截器将这些信息放入队列中,以免过多干扰方法调用的主线程。一个单独的线程用于从队列中提取时间,并将其与在同一配置周期内发生的调用进行平均,同时记录最大和最小调用时间。当拦截器识别出它处于一个“新”周期时,它将记录结果(上一周期的结果)。
要使用拦截器,需要使用XML配置或代码配置配置Unity。关键部分是注册想要仪器化的类型,并定义一个策略。这里,说的是要仪器化IOrderService类型,并在IOrderService类型上进行类型匹配,并且只在Authorize方法上进行匹配。使用了基于策略的拦截来针对特定方法,但也可以使用接口拦截,那样的话,将需要有一个不同的类来实现正确的接口拦截接口,类似于InstrumentationCallHandler,并以不同的方式配置它。
日志文件将如下所示:
2013-03-20 20:41:47,066 [11] DEBUG Purchase [(null)] - 20 calls in previous minute.
Slowest: 29627.1982ms, Fastest: 1000.1604ms, Average: 2433.719805ms
2013-03-20 20:42:15,229 [11] DEBUG Purchase [(null)] - 0 calls in previous minute.
Slowest: 0ms, Fastest: 0ms, Average: 0ms
2013-03-20 20:43:13,201 [11] DEBUG Purchase [(null)] - 6 calls in previous minute.
Slowest: 1000.3109ms, Fastest: 1000.1399ms, Average: 1001.54535ms
2013-03-20 20:44:13,258 [11] DEBUG Purchase [(null)] - 60 calls in previous minute.
Slowest: 1000.2761ms, Fastest: 1000.12ms, Average: 1000.68573333333ms
2013-03-20 20:45:13,259 [11] DEBUG Purchase [(null)] - 60 calls in previous minute.
Slowest: 1000.4533ms, Fastest: 1000.1001ms, Average: 1000.595075ms
2013-03-20 20:46:13,262 [11] DEBUG Purchase [(null)] - 24 calls in previous minute.
Slowest: 1000.704ms, Fastest: 1000.0908ms, Average: 1000.52014583333ms
2013-03-20 20:47:13,276 [11] DEBUG Purchase [(null)] - 0 calls in previous minute.
Slowest: 0ms, Fastest: 0ms, Average: 0ms
通过这些结果,可以创建一个图表来帮助分析随时间变化的性能(在这个例子中是24小时)。更好的做法是配置log4net将其写入数据库,这样前端程序/网页就可以读取结果并实时生成图表。
解决方案由以下项目组成:
它是使用Visual Studio 2012编写的。
解决方案通过NuGet添加了以下引用:
如果下载的是非EXE版本,可能需要自己获取这些引用。
在考虑从一个周期到另一个周期的时间时,确保记录上一周期发生的事情,同时允许它在同一个周期内处理队列中的时间,这是一个相当棘手的问题。
计划添加不同类型的日志记录:
可以通过重新配置log4net将其记录到数据库中。