Designing Microservices Architecture

Ishan Liyanage
7 min readMay 3, 2021

--

There is a process we need to follow when designing Microservices architecture. We must not forget that designing Microservices architecture should be methodical. The worst thing that can happen when designing Microservices architecture is to rush into development. It should be like “Plan more, Code less”.

The more you plan, the more you think about the overall system mapping, the more you know what you are going into, the less you will code later.

And of course, the less we code, the fewer bugs we create and the less maintenance we have.

Following this process is critical to the project’s success. I would highlight below 4 points in the process.

  1. Map the components
  2. Define communication pattern
  3. Select technology stack
  4. Design the architecture

Mapping the Components

This step will literally shape the system and a lot of thinking should be invested in it. This process will determine how the system will look like in the long run and once set, its not easy to change.

What is it?

In this step, we are defining various components of the system. In other words, we map the various parts of the system that when working together, compose the whole system.

When talking about components in Microservices architecture, we are mainly talking about services.

How do we decide what are our components?

The component mapping should based on several factors. These factors are,

  1. Business requirements.
  2. Functional autonomy.
  3. Data entities.
  4. Data autonomy.

Business Requirements

Here we are talking about the collection of requirements around a specific business capability. We need to identify various business capabilities of the system and understand what are the requirements.

So when mapping the components of the system, we usually use the business capability as a frame for the component and the requirements are the actions the component can do.

Functional Autonomy

This means the maximum functionality that does not involve other business requirements. However when mapping components, you will always stumble upon some grey areas. Its really difficult but not impossible to design a system where the services are really fully isolated. Therefore, be prepared to have some functionality that rely on duplicate data and inter-service communication. The real deal is to have little as possible such cases.

Data Entities

In this case, the service is designed around well specified data entities. This should be the most easiest factor to understand and most adapted by architects. Data can be related to other entities, but may not store the entire entity.

Data Autonomy

This factor actually builds on the data entities factor and added to it that underline data is an atomic unit. This means that the service does not depend on data from other services to function properly. If that happens, it’s sign we missed our architecture and we should work with it again.

This is demonstrated “Organized around business capability” attribute of Microservices.

Lets take below image for small example.

System Functions

This is in theory easy to explain, but in reality, systems tend to be more complicated that this and you will probably stumble upon some edge cases which you will have to consider.

Lets discuss how do deal with if face an edge case. Let me take previous Orders and Customers example. Imagine you need to get customers who have made more than 5 orders. How do we link orders and customers services?

We can think about 3 ways,

Data Duplication

Some Order data are there in Customers service too

Service Query

Customer service will query Order service to get data

Aggregation Service

Aggregation service will form data by querying both Orders and Customer services.

Also worth to mention here about cross-cutting services. These are services that are not specific to business scenario, but ones that almost every service can benefit from. Some common examples are logging, caching, user management etc..

Defining Communication Patterns

The efficient communication between services is crucial since the various services live in separate processes. Anytime one service wants to access other service, it requires come kind of communication. Even in medium size Microservices system, there is going to be a lot of inter-service communication. Therefore its important to choose the correct communication pattern. The usage of wrong pattern can lead to slow performance.

There are 3 main patterns,

  1. 1-to-1 Sync
  2. 1-to-1 Async
  3. Pub-Sub or Event Driven

1-to-1 Sync

In this pattern, service calls another service and waits for the response. The calling service process is blocked until a response is returned from the other service. If the response takes time, the calling service will have to wait. This is called a synchronous request, one that the calling side is waiting for the other side to respond.

This pattern is used mainly when the first service needs the response from the other service to continue. This is usually the case when the first service wants to retrieve some data that is needed for the flow.

Pros

  1. Immediate response
  2. Error Handling is simple
  3. Easy to implement

Cons

  1. Performance can be an issue

1-to-1 Async

In this pattern, a service calls another service and then continue working. In other words, it does not wait for response (Fire and Forget). This is using mainly when the first service wants to pass a message to the other service. So the other service can handle further processing.

Order service push logs to Logging service and continue to work

Pros

  1. Performance is good

Cons

  1. Need more setup (most of the time need to use Queue)
  2. Error handling is difficult

Pub-Sub/ Event Driven

In this pattern, a service wants to notify other services about something. Note the plural work “Services”. The service has no idea how many services listen. In the 1-to-1 async, the service usually directs the message to a specific service, even if it has no direct contacts with it. With the pub-sub or published/subscribed, the service publishes a message and other services who subscribe to this kind of message will receive. This is same as 1-to-1 async and will implement in fire and forget pattern.

This is used mainly when service needs to notify an important event in the system.

Pros

  1. Good performance
  2. Notify multiple services at once

Cons

  1. Needs more setup (Needs to use a queue)
  2. Error handling is difficult
  3. Might cause load on the system (based on message count to queue)

Selecting Technology Stack

In monolith app, this tasks has a lots of weight as it sets the tech stack for the whole application. In Microservices, the decentralized governance allows selecting different technology stack for each service. This gives the team a lot of independence is selecting this stack and allows them to pick more suitable platform the service.

Tech stack selection usually have some emotional side. We should always make our decision based on facts and figures and should not select a platform based on our personal preference and love ;)

We can pick platforms like .NET, .NET Core, Java, node.js etc…based on various factors which we can discuss in separate article.

Data Store

There are 4 data stores. I will not discuss facts selecting data store as it should be discussed in a separate article. The four types are,

  1. Relational Database (MySQL, PostgreSQL, MS SQL Server)
  2. NoSQL Database (MongoDB, Couchbase, Amazon dynamodb)
  3. Cache (redis)
  4. Object Store (Amazon S3, Azure Blog, MiniO)

Design the Architecture

This will not differ much from regular software architectural process. The ideas and pasterns/practices are the same.

Layers

This represents horizontal functionality of a software component.

UI/ SI (Service Interface)

  1. Expose API
  2. JSON (or other format) handling
  3. Auth

Business Logic (BL)

  1. Validation
  2. Enrichment
  3. Computations

Data Access Layer (DAL)

  1. Connection handling
  2. Query/ Saving Data
  3. Transaction Handling

Conclusion

I hope you get the idea and I hope you feel that you know and posses the knowledge you need to begin.

Above I discussed some important points, but they are not hard and fast rules. Of course situations in real world are different and we need to take things case by case basis.

--

--

Ishan Liyanage

Passionate Technical Lead, Senior Software Developer and free and open source software advocate. Based in Singapore.