Backend for Frontend pattern - Exams of ASP.NET - Revisiting the CQRS pattern - What is a Modular Monolith?

Example – Introduction to Microservices Architecture-2

The following diagram demonstrates this:

 Figure 19.12: The DeviceLocation microservice replaying the DeviceTwinCreated event to create its materialized view of the device twinFigure 19.12: The DeviceLocation microservice replaying the DeviceTwinCreated event to create its materialized view of the device twin 

  1. The DeviceLocation microservice receives the NetworkingInfoUpdated event, which updates the networking type to MQTT, leading to the following:

{
    “device”: {
        “id”: “some id”,
        “name”: “Device 1”
    },
    “networking”: {
        “type”: “MQTT”
    },
    “location”: {…}
}

The following diagram demonstrates this:

 Figure 19.13: The DeviceLocation microservice replaying the NetworkingInfoUpdated event to update its materialized view of the device twinFigure 19.13: The DeviceLocation microservice replaying the NetworkingInfoUpdated event to update its materialized view of the device twin 

  1. The DeviceLocation microservice receives the DeviceTwinUpdated event, updating the device’s name. The final model looks like this:

{
    “device”: {
        “id”: “some id”,
        “name”: “Kitchen Thermostat”
    },
    “networking”: {
        “type”: “MQTT”
    },
    “location”: {…}
}

The following diagram demonstrates this:

 Figure 19.14: The DeviceLocation microservice replaying the DeviceTwinUpdated event to update its materialized view of the device twinFigure 19.14: The DeviceLocation microservice replaying the DeviceTwinUpdated event to update its materialized view of the device twin 

From there, the DeviceLocation microservice is initialized and ready. Users could set the kitchen thermostat’s location on the map or continue using the other microservices. When a user queries the DeviceLocation microservice for information about Kitchen Thermostat, it displays the materialized view, which contains all the required information without sending external requests.With that in mind, we could spawn new instances of the DeviceLocation microservice or other microservices, and they could generate their materialized views from past events—all of that with very limited to no knowledge of other microservices. In this type of architecture, a microservice can only know about events, not the other microservices. How a microservice handles events should be relevant only to that microservice, never to the others. The same applies to both publishers and subscribers.This example illustrates the event sourcing pattern, integration events, the materialized view, the use of a message broker, and the Publish-Subscribe pattern.In contrast, using direct communication (HTTP, gRPC, and so on) would look like this:

 Figure 19.15: Three microservices communicating directly with one anotherFigure 19.15: Three microservices communicating directly with one another 

If we compare both approaches by looking at the first diagram (Figure 16.7), we can see that the message broker plays the role of a mediator and breaks the direct coupling between the microservices. By looking at the preceding diagram (Figure 16.14), we can see the tight coupling between the microservices, where the DeviceLocation microservice would need to interact with the DeviceTwin and Networking microservices directly to build the equivalent of its materialized view. Furthermore, the DeviceLocation microservice translates one interaction into three since the Networking microservice also talks to the DeviceTwin microservice, leading to indirect tight coupling between microservices, which can negatively impact performance.Suppose eventual consistency is not an option, or the Publish-Subscribe pattern cannot be applied or could be too hard to apply to your scenario. In this case, microservices can directly call each other. They can achieve this using HTTP, gRPC, or any other means that best suits that particular system’s needs.I won’t be covering this topic in this book, but one thing to be careful of when calling microservices directly is the indirect call chain that could bubble up fast. You don’t want your microservices to create a super deep call chain, or your system will likely become very slow. Here is an abstract example of what could happen to illustrate what I mean:

 Figure 19.16: A user calling microservice A, which then triggers a chain reaction of subsequent calls, leading to disastrous performanceFigure 19.16: A user calling microservice A, which then triggers a chain reaction of subsequent calls, leading to disastrous performance 

In terms of the preceding diagram, let’s think about failures (for one). If microservice C goes offline, the whole request ends with an error. No matter the measures we put in place to mitigate the risks, if microservice C cannot recover, the system will remain down; goodbye to microservices’ promise of independence. Another issue is latency: ten calls are made for a single operation; that takes time.Such chatty systems have most likely emerged from an incorrect domain modeling phase, leading to multiple microservices working together to handle trivial tasks. Now think of Figure 16.15 but with 500 microservices instead of 6. That could be catastrophic!This type of interdependent microservices system is known as the Death Star anti-pattern. We can see the Death Star anti-pattern as a distributed big ball of mud. One way to avoid such pitfalls is to ensure that the bounded contexts are well segregated and that responsibilities are well distributed. A good domain model should allow you to avoid building a Death Star and create the “most correct” system possible instead. No matter the type of architecture you choose, if you are not building the right thing, you may end up with a big ball of mud or a Death Star. Of course, the Pub-Sub pattern and EDA can help us break the tight coupling between microservices to avoid such issues.

Leave a Reply

Your email address will not be published. Required fields are marked *