8 Most Popular Architectural Design Patterns for Micro Services that any application architect must be aware

Sivasathivel Kandasamy
5 min readFeb 18, 2022

Micro-Service Architecture Pattern is one of the most popular architecture patterns for modern applications. In its simplest form the architecture would look like the figure below.

However, the above architecture don’t provide an option for the micro-services to interact with one another. Further limitations could be the scalability. Usually, a system sits between the UI and the Micro-Services to enable Inter-Service Communication, Orchestration, etc. Depending upon the purpose and application, many design patterns could be used. Some of the most commonly used patterns for developing these are:

Saga distributed transactions pattern

This pattern provides a way to manage data consistency across micro-services in a distributed transaction scenario.

A transaction is a single unit of logic or work, sometimes made up of multiple operations. Within a transaction, an event is a state change that occurs to an entity, and a command encapsulates all information needed to perform an action or trigger a later event. The transactions are ACID within in a single service. However, data consistency across services require a transaction management strategy. The Saga Pattern helps achieve this data consistency using a sequence of local transactions.

The Saga pattern provides transaction management using a sequence of local transactions. Each local transaction updates the database and publishes a message or event to trigger the next local transaction. If a local transaction fails, a series of compensating transactions would be executed to undo the changes.

The two common approaches for implementing this pattern are:

  • The choreography pattern
  • The Orchestrator pattern

Orchestrator pattern

In an application, the service communicate with one another using well defined APIs. Even for a simple task, there may be multiple point-to-point communications between the different services of the application.

An approach to managing these transactions between the services is to use a centralized service that acts as an orchestrator, which accepts requests and delegates tasks to the respective services. Thus, the orchestrator would manage the workflow of the entire business transaction, while the individual services themselves are not aware of the overall workflow.

Thus an orchestrator pattern reduces the point-to-point communication between services. However, in this approach the orchestrator is tightly coupled to the services and requires to have some domain knowledge of the responsibilities of the services. This tight coupling makes its maintenance difficult.

Choreography pattern

Choreography pattern is another implementation approach for the Saga pattern for inter-service communication. This pattern differs from the Orchestrator pattern by decentralizing the point of control. In this approach, the individual services decide on how and when a business logic is processed without the need for centralized control. However, this pattern requires an asynchronous message broker to coordinate business operations.

In simple terms, the client publishes the message to a message queue, which are then pushed to the subscribers to the message queue. Thus the services choreograph the business workflow among themselves without the need for a centralized orchestrator.

This pattern obviates the need for additional service implementation and maintenance, and issue of single point of failure.

Some of the design patterns implementing choreography are:

  • Ambassador Design Pattern for modularizing the business services
  • Queue-based load levelling pattern to handle workload spikes
  • Publisher-Subscriber pattern for asynchronous distributed messaging
  • Compensating Transactions pattern to undo operations upon failure

Ambassador Pattern

This pattern can be considered as a out-of-process proxy that is co-located with the client which offloads some of the client activity such as logging, monitoring, etc. The offloaded features can be treated as separate systems and can be deployed as a sidecar application.

However, this pattern introduces an overhead latency and may be a good candidate when network latency is critical, the connectivity features are consumed by a single language, or the connectivity features cannot be generalized.

Queue-Based Load Levelling pattern

This introduces a buffer between the events/tasks and the services they invoke to prevent failures due to intermittent heavy loads.

However, this pattern may not be a good option where latency is critical.

Publisher-Subscriber pattern

This pattern enables an asynchronous passing of information between the services. The source of the message/event is the publisher. The subscribers, are the consumers of these message.

This pattern decouples the subsystems that needs to communicate between themselves, also improve scalability and reliability of systems, etc. However, this pattern may not be of great use for limited number of consumers with differing requirements or applications that require real time interactions.

Some of the design patterns that implements this pattern are the event-driven architecture style, observer pattern or the message broker patterns.

Event-driven architecture style

This architecture consists of the event producers that generate a stream of events, and event consumers that listen for the events. The event are produced and consumed in real-time, but the producers and consumers are decoupled. This architecture can use a pub/sub model or an event stream model. Typical challenges of this architecture are the guaranteed delivery and processing of events only once.

Sidecar pattern

In a sidecar pattern, components of application are deployed as a separate process along with the main application. These components supports the main application and may use technologies different from the main applications.

The sidecar application runs independent and parallel to the main application and access the same resources. However, care has to be taken for the interprocess communication while developing the application.

An example would be a ‘gitsync’ application, in a CI/CD pipeline, deployed in kubernetes to keep one’s container code in sync with git repo.

Summary

I have a limited number of patterns here which I think may be more pertinent for micro-service based applications. There are other patterns that may help as well as patterns that could be adapted for use in implementing micro-service architecture.

--

--