Microservice architecture is gaining momentum; many want to replicate the Netflix experience and create a reliable and perfectly scalable application.
The main requirements to microservice architecture can be reduced to two – speed and reliability. Therefore, the main task that Micronaut’s creators tried to solve was to make it lighter in weight than Spring Boot, and thus faster.
Let’s find out more about what this framework is, what its advantages are, and how to create microservices on it.
To effectively create microservices, the framework already includes an HTTP server and a dependency container that is created at compile time.
In the early days of microservices there were no off-the-shelf solutions and frameworks, but as cloud technology improved, so did the requirements for not only the architecture, but for the services themselves, working in the cloud. The development community tried to create solutions that could save what cloud providers charge for – CPU time and memory.
A major tool of business frameworks, reflexion, which is used to inject dependencies and generate various proxy classes on the fly, was questioned. Such techniques require a lot of resources from the Java virtual machine, so they entail performance issues – too much activity during startup and memory usage in runtime greatly affect startup.
Micronaut framework creators decided to go a different way: incorporating best practices from existing solutions, they added a new DI/AOP container that enforces dependencies at compile time, not runtime. Thus, the lion’s share of dependencies is resolved before the application even starts. That is, even before the application starts, the Micronaut framework will scan all the code for annotations, try to generate additional classes needed for proper code execution, and fill its context with them.
Since in Micronaut all this will happen before the application starts, startup time and memory consumption are not directly related to the amount of code, unlike the Spring Boot framework, which uses reflection everywhere.
Reflexion-based IoC platforms load and cache data for every single field, method, and constructor in your code. Thus, as your code grows in size, so do your memory requirements.
The developers themselves consider the following framework design principles to be fundamental:
- use reflection only in the most “hopeless” cases;
- to avoid proxies;
- optimize startup time as much as possible;
- reduce memory usage as much as possible.
Since Micronaut was originally designed as a framework for cloud applications, it comes with a “gentlemen’s” set of native cloud solutions to create a complete infrastructure: support for Service discovery and Circuit Breaker patterns, request tracing, distributed logging, load balancing, asynchronous queues – Kafka and RabitMQ, reactive HTTP and standards JWT and OAuth2.
HTTP server
Micronaut includes a fast, flexible and high-performance Netty HTTP server. Just a couple of lines are enough to start the application and start processing requests.
Service Discovery
The framework already supports the popular Eureka and Consul solutions.
To add your service to Eureka, you don’t even need to add annotations to the previous example, just connect the runtime dependency:
"io.micronaut:micronaut-discovery-client"
Load balancing
When multiple instances of the same service are registered, Micronaut provides a form of “cyclic” load balancing, requesting available instances in turn to ensure that no instance is overloaded or underutilized. This is a form of client-side load balancing where each instance either accepts the request or passes it on to the next service instance, automatically distributing the load among available instances. This distribution occurs in general with no additional resource overhead.
Micronaut also provides native support for Netflix Ribbon. To run the balancer on the application side, you need to do a couple of simple steps.
Add a compile dependency:
"io.micronaut.configuration:micronaut-netflix-ribbon"
And specify the configuration for Ribbon:
"ribbon: VipAddress: test ServerListRefreshInterval: 2000"
Activity Monitoring
When launching an application based on a microservice architecture, it is important to know the status of all microservices. For this purpose, Micronaut already implements out-of-the-box endpoints, which can be used to get information about the service:
URI | Description |
/beans | Returns information about the loaded bins. |
/health | Returns information about the overall current state of the service. |
/loggers | Returns information about available loggers and allows you to change the configured logging level. |
Conclusion
Thus, Micronaut already out of the box supports a lot of tools that greatly simplify the life of the creator of any microservice, and its partly innovative approach to creating a container of bins and resolving dependencies at compile time gives it an undeniable advantage over its main competitor – Spring Boot.