Introduction to Java async instrumentation

New Relic for Java includes a set of API methods for custom instrumentation of asynchronous activity. This is most useful to instrument asynchronous activity in unsupported frameworks, but you can also use the API to add additional instrumentation to supported frameworks. This document explains how asynchronous activity occurs, and how New Relic monitors async work.

Asynchronous operations

With a synchronous programming model, programming tasks are usually executed in a specific order. One task must complete before the next task begins, and each task blocks the next task from completing.

Asynchronous programming uses a non-blocking model, so that tasks can be run in parallel. Tasks executed asynchronously are completely independent of each other in their execution and initialization. Because asynchronous code doesn't execute in a specific order, the server's full processing power can be used more efficiently, and the app's throughput increases.

Async and thread-switching

For applications that use asynchronous processing, thread-switching is when a program or task switches from one thread to another. Understanding these asynchronous interleavings can help you decide which methods should be instrumented.

Here is an example method with a controller that makes external requests in parallel. These requests execute asynchronously, so each request executes independently of each other and getScoreAsync() returns immediately after being called. This allows the requesting thread to continue making requests while getScoreAsync() makes an external call and sends a reply.

@ResponseBody
@RequestMapping("getScores", method = RequestMethod.Get
   produces = “text/plain”)
public String getCreditScores(@RequestParam(name = "uids") uids) {
     return Arrays.stream(uids.split(","))
                .parallel()
                .map(Integer::valueOf)
                .map(uid -> getScoreAsync(uid))
                .collect(Collectors.toList());}

Some of these requests will finish before others. Some might even finish after the requesting thread has moved on to other tasks:

async diagram.png

With New Relic's asynchronous instrumentation, the New Relic APM UI flags the work as Async. For example, if the above method were instrumented by New Relic (either automatically or via custom instrumentation), this is what the New Relic APM UI would show on the Trace details page:

narrow-trace.png
rpm.newrelic.com/apm > (select an app) > Transactions > Transaction trace > Trace details: When asynchronous activity in a Java application is detected by New Relic APM, it is indicated with the Async flag in the Drilldown column.

Async and response time

Response time is defined as the duration of a transaction from the perspective of the requester. For asynchronous applications, the response time is often less than the total transaction time. This is because the methods don't have to wait for all preceding methods to complete before returning. Because tasks can be deferred, the application can take advantage of its limited resources and process things more quickly.

The chart's response time line gives you more insight into the perceived behavior and speed of your application than does the total web transaction time:

Async Response Time.png
rpm.newrelic.com/apm > (select an app) > Overview: On the New Relic APM Overview page, asynchronous activity in a Java app can result in the response time (the blue line) being less than the total transaction time. This is because the methods don't have to wait for all preceding methods to complete before returning.

Custom instrumentation with the async API

To implement custom instrumentation of async work, see the Java agent async API guide. For general information on how to use the Java agent API, see Java agent API guide.

For more help

Recommendations for learning more: