Tuesday, April 25, 2023

Microservices Architecture design patterns & considerations interview Q&As – Part 1

 


This extends 10+ Key Microservices Interview Questions Answered. The architects & developers need to know these microservices design patterns & these are best practices to build robust systems.

Q1. Why do we need design patterns for Microservices?
A1. The goal of microservices is to increase the velocity of application releases, by decomposing the application into small autonomous services that can be deployed independently. For example, the picture below is an actual environment where hundreds of services collaborate with each other (a circle is a service). It is clearly a challenge to monitor and analyse a microservice environment.

Microservices complexity

Microservices complexity – REF: https://www.instana.com/blog/taming-the-complexity-of-microservices-using-application-perspectives/

Microservices architecture brings its own challenges in terms of complexity, maintainability, availability, scalability, distributed debugging, distributed logging/tracing, deployment, code duplication, fault tolerance, efficiency, etc. These design patterns help solve these architectural challenges & reduce the risk of failure.

Q2. What are the different design patterns?
A2. The diagram below summarises the various design patterns. Each design pattern address one more problem statement (or use case)

Microservices Architecture Patterns & considerations

Microservices Architecture Patterns & considerations

Let’s look at some of the problem statements & the design patterns.

1. Integration Design Patterns

Problem Statements: 1) Interacting with multiple microservices directly to build a single UI screen increases the number of round trips across the Internet. This approach increases latency and complexity on the UI side. This increases coupling between client & services, and any changes to services in terms of host, port number, etc will impact all the clients.

2) Protocols used on the server side like AMQP, Web Socket, gRPC or binary protocols are not supported in web, mobile or other client apps.

3) Manage complexities where common concerns (aka cross-cutting concerns) like authentication, auditing, logging, load balancing, throttling, threat protection, etc are shared by all microservices. Why repeat these services.

Microservices - Client direct to services Vs. Client via API Gateway

Microservices – Client direct to services Vs. Client via API Gateway

Design Pattern: The API Gateway Integration pattern to the rescue. This was discussed in detail at 10+ Key Microservices Interview Questions Answered.

Design Pattern: The Aggregator Integration pattern. The Aggregator Design Pattern is a service that receives a request, then makes requests of multiple services, combines the results and responds to the initiating request as depicted below.

Microservice Integration Pattern - Aggregator

Microservice Integration Pattern – Aggregator

There are 2 types of aggregators:

1) Chained Microservice Design Pattern where the request from the client is received by Service A, which is then communicating with Service B, which in turn may be communicating with Service C. All the services will be using a synchronous HTTP request/response messaging.

Microservices Architecture Pattern - Chain Aggregator

Microservices Architecture Pattern – Chain Aggregator

2) Branch Microservice Design Pattern where it allows simultaneous response processing from two or more microservices. This pattern can also be used to call different chains, or a single chain, based upon the business needs.

Microservices Architecture Pattern - Branch Aggregator

Microservices Architecture Pattern – Branch Aggregator

Problem Statements: How to implement a UI screen or page that displays data from multiple services? Modern UIs have a single page application with multiple tabs invoking different microservices.

Design Pattern: The Client-side UI composition Integration pattern where each team develops a client-side UI component, such as an AngularJS directive, that implements the region of the page/screen for their service. A UI team is responsible implementing the page skeletons that build pages/screens by composing multiple, service-specific UI components.

2. Database Design Patterns

Problem Statements: A monolithic application interacts with a single database. The data is shared between all components of the application. On the contrary, in a microservices application, data ownership is decentralised. Every service is autonomous and has its own private data store relevant to its functionality. This means that one service can’t modify any data stored inside the other service’s database.

The second problem in microservices is that you can’t use ACID transactions for transactions outside a single service. Not having ACID transactions can lead to consistency issues like duplicate records.

So, in a microservices architecture queries & transactions span multiple databases.

Let’s look these databases patterns:

Design Pattern: The Database-per-Service pattern is one of the main characteristics of microservices architecture as it promotes loose coupling of services as each microservice will be having its own private database like MySQL, MongDB, Cassandra, Redis, etc. This means designing microservices will almost always requires the database-per-service pattern.

The key benefit of database per microservice pattern is that any schema changes can be performed without any impact to other microservices. This also allows each microservice to independently scale. We can also select the best SQL or NoSQL database that suits the use case.

Design Pattern: The CQRS design pattern stands for Command Query Responsibility Segregation, which segregates CUD commands like Create, Update & Delete from Read query.

1. Command that changes the state.
2. Query that does not change the state.

Microservices Architecture Pattern - CQRS

Microservices Architecture Pattern – CQRS

This approach is good for write less & read more use cases. Learn more at Event sourcing & CQRS interview Q&As.

Design Pattern: The Event Sourcing design Ppattern ensures that all changes to application state are stored as a sequence of events. The application can reconstruct the current or past state of an entity by replaying these sequence of events. The Saga design pattern, which we will be discussing next creates the need for event sourcing. Learn more at Event sourcing & CQRS interview Q&As.

Design Pattern: The Saga design pattern is required for adopting database-per-service pattern to implement transactions that span services and to maintain data consistency. In microservices, saga pattern using a sequence of local transactions is favoured over traditional distributed transactions (XA/2PC-based).

Each local transaction updates the database and publishes a message or event to trigger the next local transaction in the saga. If a local transaction fails, the saga executes a series of compensating transactions that undo the changes that were made by the preceding local transactions.

There are 2 types of communication:

1) Saga via Orchestration: Saga Execution Coordinator (i.e SEC) is an orchestration service that:

Microservices Architecture Pattarns: Saga Orchestration.

Microservices Architecture Pattarns: Saga Orchestration.

a) Stores & interprets a Saga’s state machine.

b) Executes the Requests of a Saga by talking to other services.

c) Handles failure recovery by executing Compensating Requests.

The Saga orchestration is easier to implement, but the SEC is a single point of failure.

2) Saga via Choreography: In this approach we don’t have a Saga cordinator. Each service performs its transaction and publishes a domain event to a topic, and these events will triggers other services so that they can perform their transactions. If a local transaction fails, a rollback event is published to topic to rollback any previously committed transaction.

Microservices Architecture Patterns: Saga Choreogrpahy

Microservices Architecture Patterns: Saga Choreogrpahy

Design Pattern: The Shared database pattern could be an antipattern. In the shared-database-per-service pattern, the same database is shared by several microservices. You need to carefully assess the application architecture before adopting this pattern, and make sure that you avoid hot tables (i.e. single tables that are shared among multiple microservices).

No comments:

Post a Comment