Springのいくつかのタスクのパフォーマンス統計を測定したいと思います。これらのパフォーマンス統計には、データベースクエリに必要な時間を含めるべきではありません。したがって私はDAOメソッドをSpring AOPの側面で傍受します。この方法では、タスクの測定を停止し、データベース呼び出しの測定を開始します。両方の測定が動作します問題は、CPU & ThreadMXBeanによって取得されたユーザー時間は、異なる測定セクションの1つの間に増加しないことがあります。これらのセクションでは、私はA)DBコール前のタスクの測定、B)DBコールの測定、およびC)DBコール後のタスクの測定を意味します。私は各セクションについて合理的な測定値を得ましたが、同時に3つすべてについては測定しませんでした。少なくとも1人(ランダムに見えるように)は、CPU時間の増加を示さないと思われる&ユーザ時間。私は一般的なセットアップがを作品言ったようにAOPを使ってSpringでThreadMXBeanと0のランダムに測定されたCPUとユーザーの時間差
@Api
@Path("task1")
@Consumes(MediaType.APPLICATION_JSON)
@Produces(MediaType.APPLICATION_JSON)
public class task1Resource {
@Autowired
private MeasurementService measurementService;
@POST
public Response startTask(...){
measurementService.start("task1", false);
//Transactional service methods with the business logic for task1
//are called
measurementService.end("task1");
return Response.ok(entity).build();
}
}
@Service
@Transactional
public class MeasurementService {
@Autowired
private MeasurementDAO measurementDao
public void start(String task, boolean interrupted){
MeasurementObject measurementObj = new MeasurementObject();
ThreadMXBean mxBean = ManagementFactory.getThreadMXBean();
if(interrupted){
//Get the previously persisted measurement object for the task
measurementObj = measurementDao.get(task);
//Calculate the differences with the values of the previous section
measurementObj.calcCpuTimeDifference(mxBean.getCurrentThreadCpuTime();
measurementObj.calcUserTimeDifference(mxBean.getCurrentThreadCpuTime();
}else{
//Initialize
measurementObj.setTask(task);
Set<DAOMeasurement> daoCalls = new HashSet<DAOMeasurement>();
measurementObj.setDaoCalls(daoCalls);
Thread currentThread = Thread.currentThread();
measurementObj.setThread(currentThread);
measurementObj.setCpuTime(mxBean.getCurrentThreadCpuTime);
measurementObj.setUserTime(mxBean.getCurrenThreadUserTime);
}
measurementDao.save(measurementObj);
}
public MeasurementObject end(String task){
//Get the measurement object for the task
MeasurementObject measurementObj = measurementDao.get(task);
ThreadMXBean mxBean = ManagementFactory.getThreadMXBean();
//Calculate the differences with the values from the start
//or the previously calculated differences
measurementObj.calcCpuTimeDifference(mxBean.getCurrentThreadCpuTime());
measurementObj.calcUserTimeDifference(mxBean.getCurrentThreadUserTime());
return measurementDao.save(measurementObj);
}
}
@Aspect
@Component
public class daoAspect {
@Autowired
private MeasurementService measurementService;
@Autowired
private DAOMeasurementService daoMeasurementService;
@Before("daoMethods() && !measurementMethods()")
private void start(Joinpoint jopo){
Thread currentThread = Thread.currentThread();
//Get the task measurement object that was started in the same thread
MeasurementObject measurementObj = measurementService.byThread(currentThread);
measurementObj = measurementService.end(measurementObj.getTask());
//Start the measurement for the DB call
DAOMeasurementObject daoMeasurementObj = daoMeasurementService.start(measurementObj);
}
@After("daoMethods() && !measurementMethods()")
private void end(Joinpoint jopo){
Thread currentThread = Thread.currentThread();
/*Please assume here that we only have one dao method
* (In my more complex case I query the database for
* the correct daoMeasurementObject by using additional parameters)
* So here we find the DB call measurement object that was started
* in this thread and end it. */
DAOMeasurementObject daoMeasurementObj = daoMeasurementService.byThread(currentThread);
daoMeasurementService.end(daoMeasurementObj);
//We get the task measurement object for this thread and start it again
MeasurementObject measurementObj = measurementService.byThread(currentThread);
measurementService.start(measurementObj.getTask(),true);
}
@Pointcut("execution(* com.foo.bar.dao.*(..))")
public void daoMethods(){}
@Pointcut("@annotation(Measurement)")
public void measurementMethods(){} //I annotated the measurement dao classes with this annotation
}
@Service
@Transactional
public class DAOMeasurementService {
/*This class is identical to the MeasurementService class with the
* difference that a DAOMeasurementObject gets a MeasurementObject
* reference. But the cpu-&user-times are calculated in the same manner */
}
:以下で
は私の問題のケースを視覚化するいくつかのサンプルコードです。タスク測定は、想定されるように開始および終了し、その間のDAOメソッドはアスペクトによって中断されます。また、私はときどき正しい値を得るので、測定は適切に機能しているようです。 唯一の問題は、しばしばCPU-&ユーザ倍私はさらに0
で算出された差分値をもたらすそれらの端に3つの測定値のセクションの一つまたは二つの先頭から変化しないということですこれらのメソッドのすべてが同じにThread.currentThread()とThreadMXBean.isCurrentThreadCpuTimeSupported()とThreadMXBean.isThreadCpuTimeEnabled()リターンすべての測定点で真を持っていることを確認しました。
私は本当にいくつかのヘルプやヒントをお待ちしています!さらにコードや情報が必要な場合は、お気軽にリクエストしてください。
更新:
私が代わりに@Before
と@After
側面の@Around
側面とし、複数回実行してシステムをテストしました。結果は変わりません。 ThreadMXBean.getCurrentThreadCpuTime
とThreadMXBean.getCurrentThreadUserTime
の値は、測定フェーズの1〜2の間に無作為に増加するのではなく、それらの間で増加します。例:フェーズA)、タスクの開始時の測定値は280801800のCPU時間と265201700のユーザー時間を示し、この測定値がDAOインターセプト中に停止されると、CPU時間280801800とユーザーDAOメソッドの測定の段階では、296401900のCPU時間と280801800のユーザー時間を示します。しかし、DAOメソッド測定の最後には、 296401900の同じCPU時間と280801800の同じユーザー時間。完全なフェーズC)の間、時間はB)と同じままです。
- > ThreadMXBeanは、メソッドが呼び出されたときではなく、ある間隔で統計情報のみを更新することができますか?現時点で測定しようとしているフェーズは比較的短く、LocalDateTimeを使用して1〜10ミリ秒の期間があります。