Microservices architecture describes a set of techniques for building a back-end server applications as a set of smaller services. Each microservice has its own bounded context, database, and domain model. Also, each service is developed and deployed independently and runs in its own separate process. Microservice architecture is the opposite of monolithic application design where it is used a single database and any part of the application can invoke another one just by a simple function call. One advantage of microservice architecture is the possibility of granular scaling out services depending on their processing requirements. Suppose that there is a web application used by graphic designers, the application allows them to upload images one by one and apply some beautiful artistic effects. Users have to create a free account to be able to access their basic free functionality, also the site provides a subscription model and users can pay on a monthly or annual basis to unlock some features like bulk image upload, access to dozens of advanced image effects, etc. Bellow is the comparison of two scaling models.
monolithic application
microservices architecture
Scaling monolithic application vs. scaling microservices
Scaling out a monolithic application means cloning it entirely, in this case, there will be some application parts that are excessively copied across virtual machines and pointlessly use memory. Contrarily, in a microservices architecture, only the services that require more processing power are scaled.
In microservice architecture, it is not possible to access all domain models and data in one place because data is distributed across various services and database servers. There is no possibility to change data in one single database transaction, instead, microservices have to communicate with each other using inter-process protocols like AMQP or HTTP/HTTPS in order to achieve data consistency.
Inter-service communication
Microservices have to communicate with each other for data exchange and for propagating changes, the main two types of inter-service communication based on their protocol mechanism are:
  • synchronous, based on synchronous protocols like HTTP or gRPC. One service is making a request to another service and is waiting for a response. This approach increases the coupling between services, microservices must be isolated as much as possible and one service must not directly depend on the other. Also if a request to a service, in turn, generates one more request to another service, the original request will create a chain of requests, as a result, this will increase the inter-service dependencies and will add undesirable latency. In this case, if the request is made for demanding some data(for example some business entity properties): it is worth considering to replicate that data(using integration events) into the database of dependent service to avoid a requirement for one extra request.
  • asynchronous communication type, it can be provided using a message broker that supports AMQP protocol or an event bus. In this case, the service originating the request publishes a message to a queue, and another service is subscribing in order to receive the message. The message broker will place the message in a corresponding queue and will deliver it to the subscriber. If the service originating the message(publisher) needs a response from the destination service: the receiver(subscriber) also has to publish a response message to a separate queue, hence the originator service will subscribe to that separate queue to wait for responses. The figure below depicts how it works:
    event bus
    Message brokers can reliably deliver messages and guaranty that no messages will be lost in case of restart or if the destination service is not available at some moment.

Event-driven communication
Event-driven communication is used when one service needs to be up to date with changes that have occurred in another service(like business entity changes). The service that initiated the domain changes asynchronously publishes an integration event in order to notify other interested services, those interested services have to be subscribed to message queue in order to receive event notifications. Publisher does not require to be aware of the subscribers, both parts are decoupled and there is no explicit dependency between them. When the subscriber receives a new event message, it can update its domain model, which in turn can result in creating more integration events. Publishing and subscription functionality are accomplished by using an event bus that exposes an API for publish/subscribe and unsubscribe functionality. The event bus can be implemented for example by RabbitMQ message broker.
Integration events are POCO classes that just hold some data that is useful for subscribed services, an example of an integration event can be a class containing three properties: new user id, user name and user profile photo URL, such an event can be triggered at every new user registration and it will be asynchronously propagated to all involved parts..