Since I have heard the word “microservices” for the first time, I tried to learn how to build something that could really be called a “microservice”, or at least a microservice-based application. Finally, after lots of tutorials, readings, books and so on, I found out the way Spring framework allows everybody to build a microservice application. This serie of articles is intended to give out a set of tutorials on how to use the framework and it is based on my personal experience.
First of all, let’s see what microservices are. This first post will cover some of the base concepts of this new architecture and introduce all the upcoming articles. Let’s suppose we have an application that permits to our users to place some reservations. The application has two basic functionalities: the users management and the reservations management. The whole thing is built in a monolithic way, so we just have a big database with a whole application built on top of it. A generic client, that could be a web application, or a mobile device, directly communicates with the monolithic application, as shown in figure.
This monolithic application has some pros and some contros. It is true that we only need an application server to have it running, but what happens if we need a replica of only a part of it, let’s say, the reservation management sub-system? We have to run a replica of the whole thing. Not only: developers would tend to write the application in a high coupled way, and the complexity of the code would increase very easily. Microservices could help us. In particular, let’s give a look at the basic patterns of the microservices way, as detailed in in the Patterns page at microservices.io. The firsts pattern we will adopt are API Gateway and Database per service. As the names suggest, starting from our monolithic application, we split it into two basic services, a Users service and a Reservations service. Both services will have their local database, built in order to store just the data needed by each service and anything else. Users’ informations will be stored in the Users service database, and when the Reservation service will need any information on a user, the service itself will ask the User service for it. In order to allow client to communicate with these services, we will set a gateway to which a client will have to connect. The gateway will know both Users and Reservations service, and will handle the requests and responses between services and clients.
We are now in the situation where we could easily deploy a new instance of our Reservation service, using either Multiple services per host pattern or Single service per host pattern. In both cases, we could have a replica of the service and it could be useful, for example, for a geographic distributed load balancer. This solution would give us a new problem: how would the API Gateway know that we have two running instances of the Reservation service? We could build a custom gateway and hard code this information in it, or we could use a ways better solution, called Discovery. Every single instance of our services would connect to a Discovery server, and whoever would need to know the endpoint to contact in order to consume a certain service, it could do contact the Discovery server and ask for a running endpoint. See both Server-side discovery pattern and Client-side discovery pattern for these concepts. The landscape for our application would then be as shown in the following figure.
As we can see in the figure, we now have two database instances in the Reservation service endpoints. I just represented them in a separate way, but we could easily consider it a unique database. For example, we could imagine it like a sharded MongoDB cluster.
Until now, I have represented the communication between the User service and the Reservation service as a remote procedure invocation, but it could also be done with a message bus, and the whole picture would then become like this.
We have covered all the basic patterns that a microservices architecture would bring. I will add an other component to this architecture: a config service. Let’s imagine we have just deployed our both Reservation service instances, and we need to change a configuration after a week. We will need to deploy again the instances, and it would require a short time of unreachability. It would be definitely better if both the instances would fetch the config files from a service designed for that mere purpose. In this condition, we could update the config file wherever the Config service would be able to read it from, and our Reservation service instance would be notified of the change so they can update the configurations.
In the next article we will start exactly from this last component: the Config service.