Much has been written about microservices vs. monolithic applications, and the advantages of microservices, such as scaling, ease, and speed of deployment, fault tolerance, etc. Breaking a large software project into smaller, independent, and loosely coupled modules not only has an impact on deployment, but it also has an effect on operational aspects such as monitoring. In this blog post, we look at the differences between monolithic and microservices applications from the perspective of monitoring.
Differences in Application Stack
A monolithic software application is typically developed in a single software language. In a microservices application, different teams working on different application components have more freedom in choosing the best-suited development framework. This also means that in a microservices application it is easier to swap out things, while in a monolithic application a more long-term commitment to the architecture and programming language is required.
From a monitoring perspective, a monolithic application typically uses a combination of infrastructure performance monitoring (IPM) and application performance monitoring (APM). APM tools allow deep-dive troubleshooting of code-related problems and should provide good support for the selected programming language of the monolithic application (e.g. Java, .NET, Ruby). In a microservices application, a monitoring tool typically needs to support a much broader technology stack, as different programming languages and application frameworks are used, but without necessarily requiring code instrumentation as argued in the next section.
Interactions Between Application Components
In a monolith, the different application components written in the same programming language simply interact via internal procedures or method calls. In a microservices application, remote procedure calls or REST APIs are used for the different components to communicate with each other.
This means that for a monolith, in order to understand how the different application components interact at runtime, some form of code-level instrumentation is required. For a microservices application, looking inside the application code is less of a necessity, since the amount of code executed in each microservice is typically much more limited and isolated. In this case, monitoring the interactions between application components can already give you a very good idea on performance bottlenecks, without requiring code-level visibility.
Infrastructure Model: Application Servers vs. Containers
A monolithic application is typically deployed on an application server, such as a Java-based application deployed on a Tomcat application server. Microservices, on the other hand, composed of different technologies, each run on their own specialized instances, typically using an underlying container technology such as Docker.
Again, this has its impact on monitoring. In a monolithic application, you typically need to monitor a more limited number of servers or VMs. In a microservices application, the number of containers is an order of magnitude larger, and containers are added and removed in a much more dynamic way, using orchestration platforms such as Kubernetes, Docker Swarm, or Mesos. Hence monitoring tools should be adapted for such large and dynamic environments and integrated with these orchestration tools.
Containers are very lightweight constructs, designed to run a single process per container. Whereas in a monolithic application, you would typically run a monitoring agent per server or VM, it is not advisable to use such an approach at the container level, since you would pollute your container and the service it runs with the monitoring agent.
To gather more detailed metrics from the application components running inside the container, you need to use a different approach. One alternative is to leverage application log files, that can be accessed from outside the container. This is a useful approach for application components that have default logging capabilities. Another approach could be to instrument the application from within using techniques like StatsD. This is a useful approach for extracting custom metrics from your application. Finally, some application components also expose API's from which relevant metrics can be obtained.
Breaking down your monolithic application into microservices also means breaking down your monitoring approach. For monolithic applications, traditional APM tools that provide code-level visibility are useful to understand performance bottlenecks inside the application. For microservices applications, focus on understanding the performance of the individual microservices and the interactions between them, and use low-overhead instrumentation techniques to gather application-specific metrics.