Mastering Spring Cloud
上QQ阅读APP看书,第一时间看更新

Metrics

As we usually say, there is no such thing as a free lunch. Development is fast and easy, but after including some additional libraries in the project, the fat JAR file now has about 30 MB. Using one of the auto-configured actuator endpoints, /metrics, we can easily check out our microservice heap and non-heap memory usage. After sending some test requests, heap usage was about 140 MB and non-heap was 65 MB. Total memory usage for the application was about 320 MB. Of course, these values can be reduced a little even just by using the -Xmx parameter during startup with the java -jar command. However, we should not reduce this limit too much if we care about reliable working in production mode. Apart from memory usage, the /metrics endpoint displays information about the number of loaded classes, the number of active threads, the average duration of each API method, and a lot more. Here's a fragment of the endpoint response for our sample microservice:

{
"mem":325484,
"mem.free":121745,
"processors":4,
"instance.uptime":765785,
"uptime":775049,
"heap.committed":260608,
"heap.init":131072,
"heap.used":138862,
"heap":1846272,
"nonheap.committed":75264,
"nonheap.init":2496,
"nonheap.used":64876,
"threads.peak":28,
"threads.totalStarted":33,
"threads":28,
"classes":9535,
"classes.loaded":9535,
"gauge.response.person":7.0,
"counter.status.200.person":4,
// ...
}

There is the possibility to create our own custom metrics. Spring Boot Actuator provides two classes in case we would like to do that—CounterService and GaugeService. CounterService, as its name indicates, exposes methods for value incrementation, decrementation, and reset. By contrast, GaugeService is intended to just submit the current value. Default metrics for the API method calling statistics are a little imperfect because they are based only on the invoking path. There is no distinguishing between method types if they are available  on the same path. In our sample endpoint, this applies to GET /person, POST /person, and PUT /person. Anyway, I created the PersonCounterService bean, which counts the number of add and delete method calls:

@Service
public class PersonCounterService {
private final CounterService counterService;

@Autowired
public PersonCounterService(CounterService counterService) {
this.counterService = counterService;
}

public void countNewPersons() {
this.counterService.increment("services.person.add");
}

public void countDeletedPersons() {
this.counterService.increment("services.person.deleted");
}
}

This bean needs to be injected into our REST controller bean, and the methods incrementing the counter value can be invoked when a person is added or removed:

public class PersonController {

@Autowired
PersonCounterService counterService;

// ...

@PostMapping
public Person add(@RequestBody Person p) {
p.setId((long) (persons.size()+1));
persons.add(p);
counterService.countNewPersons();
return p;
}

@DeleteMapping("/{id}")
public void delete(@RequestParam("id") Long id) {
List<Person> p = persons.stream().filter(it -> it.getId().equals(id)).collect(Collectors.toList());
persons.removeAll(p);
counterService.countDeletedPersons();
}
}

Now, if you display application metrics again, you will see the following two new fields in the JSON response:

{
// ...
"counter.services.person.add":4,
"counter.services.person.deleted":3
}

All metrics generated by the Spring Boot application may be exported from the in-memory buffers to a place where they can be analyzed and displayed. We can store them, for example, in Redis, Open TSDB, Statsd, or even InfluxDB.

I think that's about all the details about built-in monitor endpoints I wanted to give you. I had designated a relatively large amount of space to such topics as documentation, metrics, and health checks, but in my opinion, these are the important aspects of microservice development and maintenance. Developers often do not care if these mechanisms are well implemented, but others often see our application just through the prism of those metrics, health checks and application's logs quality. Spring Boot provides such an implementation out of the box, and therefore developers do not have to spend much time enabling them.