Skip to main content

Designing Microservices





Introduction

It is architectural style of building applications that are resilient, highly scalable and individually deployable small units that can be maintained by small heterogeneous teams. Each service will have separate codebase where it can be handled by individual development team. The internal implementation of one service will not know to other services. Microservices will have its own data store and it will act like a distributed database.

Overview of Microservices


Client applications will interact only with API Gateway and thus it routes the call to appropriate microservices behind the scenes.
Some of the advantage of API Gateway are as follows
1.       Decouple the client from microservices. In other words, client don’t have any awareness of microservices
2.       Facade for entire microservices.
3.       It can cover other operations like Authentication, Authorization, Logging etc.,

Domain Driven Design (DDD)

It is an important aspect in design microservices. In order to design loosely coupled and cohesive microservices Domain plays a vital role. We should consider designing the bounded context for an microservices and it should interact with another bounded context.

Pic. Simple Catalogue Domain Design

Analyzing Domain

We should consider designing the domain and it should meet our business functional requirements. The above picture represents the sample Catalogue domain design of entire system. It is necessary to take cohesiveness of microservices and it should be loosely coupled.

Bounded Context

When we think about the microservices, we should have boundaries between microservices, and it should be loosely coupled. Each boundary in a domain should represent the same thing and it should not overlap the representation of other thing. In other words, it must be single unit,


In above picture, the thin line represents the boundaries between the primary entity/domain, and it should represent the single thing. The thin lines represent the communication between bounded context in order to achieve the business logic.
When we think about the communication between the boundaries directly, the system will become tightly coupled and becomes more complex.
So, we should think about in writing fine-grained well-designed API’s in order to achieve loosely coupled highly maintainable systems. In order to do that we must implementing some design patterns mentioned by Eric Evans.

 Glimpse of Tactical DDD

In real, a single business transaction may span into multiple data stores of microservices. Handling such scenario must be tactical in designing the microservices.

Entities

It is an object that represent Unique Identifier of a system that can be persisted over time.

Value Object

It is an Object that does not have Unique Identifier which is simply values.

Aggregates

It is boundary around one or more entities. The Root entity must have reference to the child entity within it.

Domain and Application Services

Domain services usually means encapsulated within business or domain logic. Application services usually don’t have domain logic and it won’t affect any state of domain or business. Example, sending any kind of notification.

Domain Events

It is used to notify that something happened within domain. As we know microservices are distributed across the systems and don’t share the databases with each other. These events are came to rescue in maintain the data integrity of microservice distributed system.

Scenario: Order Status

In our catalog system, we may have the status of Order and it might be distributed across the entities.
We may have domain events like,
·         Order entity may sends Order Placed, Cancel Order, In-Progress, Order Completed
·         Printer entity may send Print Label, Cancel Print, Print Completed
·         Employee entity may send Order Review, Approve, Cancel Order, Test and Invoice
Look at this UML Diagram, which represents the order aggregate entity,


In above aggregation, lot of microservices involved like Order, Customer, Payment, Printer, Employee and we think about direct communication between microservices. Then our system will look like Chatty I/O and we tend to build complex system. In this case, we need to have reverse proxy server where we can accumulate data from one or more services which is API Gateway.
Likewise, we need to handle domain logic that spread across the microservices which is nothing but distributed transactions. Here, we should maintain the previous state of data-store in case of any failure.so, reverse proxy server is stateless, and it is impossible to maintain distributed transaction. Instead, we can have event sourcing. Event sourcing is nothing, but domain events will be treated as messages and published in queue. Subscribers/Listeners will get the notification about the event. So, corresponding microservice will get notified and process to fulfill the transaction.

Distributed Transaction

In above example scenario, we have a distributed transaction that should be consider as unit of work.
When Customer placed an order (order service), Review status must be set (employee service) which is nothing, but distributed transaction and it is consider as unit of work. Here is how our initial plan for handling distributed transaction that is without resilience.

Plan without Resilience (Publisher Subscriber Pattern)



Client: Web/Mobile application from where Client can able to place an Order.
API Gateway: Receives request from the client. Normally performs Routing, Request aggregation for GET calls to microservices. For POST, PUT, PATCH, DELETE kind of calls it will deal with Ingestion microservice.
Ingestion Service: Process the domain events into queues and store that in a service bus as Topics/Queues.
Microservices: Listen to the domain event and process that domain event into data when it gets notification on that event.
Imagine that Order is placed, and API Gateway will route to ingestion service and process that into messages and it gets notified to subscribers Employee Service and Order Service. Now Order service is processed and succeed and employee service got notification and can’t able proceed further due to some interruption from the datastore. Then Data Integrity problem arises, and that order will always in Placed status and will not process further and hence data anomalies.

Scheduler Agent Supervisor Pattern (Resilience)

This pattern ensures that distributed transaction with resilience (Recover or undo) the failed operation. Treat distributed transaction in sequence of steps of actions in case of failure undo the entire operation transparently.
Look at this below distributed transaction workflow

 

Place Order Workflow

Initially the ingestion service will inject the message of order place event into service bus. Order scheduler will listen to the topic message in service bus. On Notification, it will follow the following steps in order to achieve the distributed transaction
1.       Mark Order Place status – Call the order service REST API to Update Order Status to Order placed status.
2.       Mark Review Status – Once after step 1, call the Employee service REST API to Update Review Status.
3.       Mark In-Progress Status – Once after step 2, call the order service REST API to update order status In-Progress status

Compensation Transaction

In case of any failure in above mentioned workflow, the whole set of operation must be revoked by means of compensation transaction which means previous state of distributed data store.


This illustrates that when order is placed by client it will be routed to ingestion service via API Gateway and thus it will store message as topic like “order placed” in service bus.
Order Scheduler: Listener to the order placed event in service bus. It will get notified when order is placed. This takes the responsibility of orchestrating the steps as mentioned above workflow.
Responsibilities:
1.       Orchestrate workflow steps to agent / in our case agents are corresponding microservices.
2.       Maintain the State store with status like step stated, In-Progress, Completed and Failed.
3.        It should also maintain the compensation transaction to undo the operation if transaction is failed.
Agents: Agents are Employee and Order Service. They handle the business logic of steps individually by means of REST API.
Order Supervisor: This is Timer based service that run periodically and listen the status of state store. If it found any failures of steps and it will undo compensation transaction mentioned in state store.

Conclusion

Microservices are the new world of cloud computing which brings numerous advantages for cloud-based applications like scalability, independent deployment, heterogeneous sub system/microservices. On the inner face of this facade system brings lot of complexities and there are many design patterns to overcome those. We should choose wright flavor of patterns according to our business needs.

Comments

Popular posts from this blog

How to resolve ASP.NET core web API 2 mins timeout issue

Introduction We are in the new world of microservices and cross-platform applications which will be supported for multiple platforms and multiple heterogeneous teams can work on the same application. I like ASP.NET Core by the way its groomed to support modern architecture and adhere to the software principles. I am a big fan of dot net and now I become the craziest fan after seeing the sophisticated facility by dot net core to support infrastructure level where we can easily perform vertical and horizontal scaling. It very important design aspect is to keep things simple and short and by the way, RESTFul applications are build and it is a powerful mantra for REST-based application and frameworks. Some times we need to overrule some principles and order to handle some situations. I would like to share my situation of handling HTTP long polling to resolve the ASP.Net core 2 mins issue. What is HTTP Long polling? In the RESTFul term, when a client asks for a query from the serv

How to Resolve ASP.NET Core Key Protection Ring Problem in AWS Lambda

Introduction When it comes to server less web application design using asp.net core razor pages, we definitely need to consider a factor of data protection key management and its lifetime in asp.net core. I developed a site using AWS toolkit of ASP.NET Core Razor Pages. The main advantage of ASP.NET Core is cross-platform from where we can deploy our application in MAC, Linux or windows. I deployed my site initially in IIS Server from which I got the results as expected .but later period I decided to host my site in AWS Lambda in order to meet our client requirement. Strangely, I got unexpected behavior from my site. I just refer the cloud information Lambda Log to identify or pinpoint the case, I got the error Information like “Error Unprotecting the session cookie” from the log. In this article, I tried to explain the root cause of the problem and its solution to overcome such kind of issue. Data Protection in ASP.NET Core This is feature in ASP.NET Core which acts as repl

Which linq method performs better: Where(expression).FirstorDefault() vs .FirstOrDefault(expression)

 Introduction When it comes to LINQ, we always have multiple options to execute the query for the same scenario. Choosing correct one is always challenging aspect and debatable one. In one of our previous articles   Any Vs Count  , we have done performance testing about best LINQ methods over .NET types. In this article, I would like to share about  Where(expression).FirstorDefault() vs .FirstOrDefault(expression) Approaches Performance testing for  Where(expression).FirstorDefault() vs .FirstOrDefault(expression) is very interesting IEnumerable<T> or ICollcetion<T>  .FirstOrDefault(expression) is better than  Where(expression).FirstorDefault() Public API To check the performance, I need some amount of data which should already available. So I decided to choose this  public api . Thanks to publicapis Public API Models Entry class using System ; using System.Collections.Generic ; using System.Text ;   namespace AnyVsCount { public class Entry { pub