- Java EE 8 High Performance
- Romain Manni Bucau
- 471字
- 2021-06-30 19:14:34
CDI instrumentation
If we focus back on the Metrics library, we will find several CDI integrations. The global idea is to decorate the code with some annotation and automatically get the metrics associated with the executed code. Clearly, it will impact your code this way (using https://github.com/astefanutti/metrics-cdi for instance):
@Transactional
@ApplicationScoped
public class QuoteService {
@PersistenceContext
private EntityManager entityManager;
@Timed(name = "create")
public Quote create(final Quote newQuote) {
entityManager.persist(newQuote);
entityManager.flush();
return newQuote;
}
}
The @Timed annotation will automatically wrap the method execution in a Metrics timer and will therefore provide the statistics about the execution time of the method. The relevant code of the interceptor associated with the @Timed annotation is very close to this logic:
private Object onInvocation(InvocationContext context) throws Exception { Timer.Context time = findTimer(context).time(); try { return context.proceed(); } finally { time.stop(); } }
This is exactly what we want to achieve but it has one trap we didn't think about yet: the exception handling. To understand this point, we can compare the code used in the retired project (called Apache Sirona), which had the following differently implemented feature:
protected Object doInvoke(final InvocationContext context) throws Throwable {
final Context ctx = before(context);
Throwable error = null;
try {
return proceed(context);
} catch (final Throwable t) {
error = t;
throw t;
} finally {
if (error == null) {
ctx.stop();
} else {
ctx.stopWithException(error);
}
}
}
What is important to see here is that the code path changes in the case of an exception. In terms of statistics, this implies that failures will have a different marker from successful calls in the metrics report. This is important to notice because the execution time of a failure is rarely comparable to a success, even for simple methods. Let's take a simple finder example from our quote manager application and observe this. Here is the line we will investigate:
entityManager.find(Quote.class, id)
A normal call with a valid ID will be around 6 to 7 ms (on my reference machine, with my personal configuration). The EntityManager#find method can take any type for the identifier, so if we pass a wrong type (such as String instead of long ) then the call should compile and execute. Eclipselink will complain with an exception but the performance impact is something interesting: 0 ms! Indeed, this example is very extreme and is a bug, but if you have some rate limiting on an endpoint or some sanity checks at the beginning of the methods, the same impact can be observed.
This means that if the framework you are using is putting all the invocations (with errors or not) in the same bucket, you can have a very good performance but a very slow application, since the average of the success/failure makes the figures look good.
- pcDuino開發實戰
- 30天自制操作系統
- Mastering vRealize Operations Manager(Second Edition)
- Linux Mint Essentials
- Learn Helm
- Linux Shell編程從入門到精通(第2版)
- 嵌入式操作系統(Linux篇)(微課版)
- 混沌工程實戰:手把手教你實現系統穩定性
- 新手學電腦從入門到精通(Windows 10+Office 2016版)
- Learning Bootstrap
- 網絡操作系統教程:Windows Server 2016管理與配置
- jQuery UI Cookbook
- Windows Server 2012網絡操作系統項目教程(第4版)
- INSTANT Galleria Howto
- Cassandra 3.x High Availability(Second Edition)