Design Patterns for Microservices

Jalitha Dewapura
Geek Culture
Published in
6 min readJun 25, 2021

--

In the previous blog post, we walked over the migration of Monolithic to Microservices architecture. If you haven’t read the previous post yet, I suggest you read that before proceeding with this article.

At the end of this article, you will understand three different design patterns used for microservices.

  • Aggregator pattern
  • Circuit breaker pattern
  • Proxy pattern

Aggregator Pattern

We all know that microservices is designing the application as a collection of independent services. These services may not represent a particular functionality of the application. So, the aggregator pattern invokes several microservices to achieve its functionality. In other words, the aggregator pattern is used to develop aggregator services on top of the services.

Let’s take an example to understand it properly. Assume we have to design an employee management system. So, the project architecture will end up with a few different services and here I consider four of them.

  • Get employee information
  • Get attendance information
  • Get performance information
  • Get project allocation information

These services alone won’t do anything. So, this application should have the functionality to calculate employee salary. It has to invoke two different services such as employee information and attendance information. These two services should be integrated to implement this functionality. Therefore, we can develop an aggregate service to manipulate these two services and send the response to the client. It is not a much time-wasting thing to implement aggregate service. Assume one day, this company change its business plan. So, their salary calculation should be integrated with the employee performance. Here is the importance of the aggregation pattern. You can simply develop another aggregate service to obtain new functionality.

Aggregator Pattern

There are three different ways to use the aggregation pattern.

  • Chain Pattern
  • Parallel Pattern (Scatter gather pattern)
  • Branch Pattern

Chain Pattern

Let’s assume we have two services called A and B. We need some information from A’s response before proceeding with the request of service B. In other words, A needs to be completed before starting B. This is called the chaining process and it can be implemented by the chain pattern.

This usually happens when the conversion of monolithic applications to microservices. And also, some processes should happen one after the other. For example, consider a banking application, a transaction should proceed after verifying account balance is more than the transaction amount.

Parallel Pattern

In an application, some services can proceed simultaneously to obtain a single functionality. Let’s assume A and B services can execute independently. Each service takes 10ms to complete. The aggregation happens after receiving each response from both services. Theoretically, if we use parallel aggregation, this functionality can be completed within 10–15ms. But the chain pattern proceeds these services one after another. It means the whole functionality takes more than 20ms. So, microservices encourage to use of parallel aggregation as much as possible.

Branch Pattern

Some applications have decision-making situations before executing the next service. Let’s assume A, B, and C are three different services. First, A executes, and then B or C executes depending on the response of A. So, there is a decision-making situation after A executed. It is called branch aggregation.

Circuit Breaker Pattern

Before jumping into the circuit breaker pattern, you should aware of the circuit breaker which is used in electricity. The circuit breaker is placed between the main grid and the house internal circuit. It protects your house's electric circuit from damage caused by overcurrent/overload or short circuit. The basic idea behind the circuit breaker pattern is much similar to this process.

When you have multiple services, There’s a possibility that services call from several backends. As I mentioned above, those services are aggregated to provide application functionalities. When the server gets a request from the client, it will allocate one thread for call the back-end. For example, A, B, and C services may involve providing P functionality(aggregator service). Sometimes, these services(service B) are not available due to slow network connection, timeouts, etc. Therefore, these requests will wait in the thread pool until the timeout happens or response reaches. As a result, the remaining request will be blocked until the service is back. It is called a cascade queue. However, if service B is recovered, it will try to process those requests in the queue. As a result, the service will be break again. The circuit breaker pattern can overcome this problem.

In the circuit breaker pattern, all the services have pre-defined thresholds and they are monitored with their response time. Assume service B usually takes less than 100ms to respond and the threshold timeout value is 200ms. In some situations, more than 50% of requests reach the upper threshold (150–200ms). Then this service is marked as falling slowly. If the number of occurrences exceeds 200ms, the consumer understands the service B is not responding anymore. Therefore, the next request which wants to access service B is failed immediately. That means it breaks the connection between aggregate service and service B. So, the request will not wait until the time out.

The consumer frequently sends a ping request to service B in the background. If it is back, it will be connected to the aggregator service again. Because of the failure of all requests during the service downtime, the service can start with new requests.

Proxy Pattern

When considering a typical application, the client requirement may be changed frequently. Because of that, the services need to change with the new features. Moreover, the application may have some patch updates. This is the place the proxy pattern will fit into the system. The proxy pattern can be used to manage a few different versions of a particular service until consumers upgrade to the new version.

Let’s take an example to understand it. In our employee management system, the salary calculation service is working with 3 different services. The attendance information service is one of them. With time, the company wants to log the attendance in a proper way. So, the attendance service is changed with new standards. But still, the consumers like salary calculation service may not change their services. Therefore, we need to deploy two different versions of the attendance service until all consumers migrate to the new version.

To obtain it, the developers need to create a proxy service between the consumer and different versions of the service. If the consumer addresses the old version of the service, the proxy service directs the request to the old version. Otherwise, it will direct to the new version.

With the proxy pattern, you can independently deploy your service without disturbing your consumers. In the future, if you don't see any traffic for the old version, you can decommission that version.

Semantic version

As I mentioned above, when deploying several versions of the service, it should be a standard like semantic versioning. There are three numbers called major, minor, and patch in semantic versioning.

Major — When the developers add new features that could potentially break the existing APIs.

Minor — When the developers adding new features which will not break the existing API.

Patch — When the bug fixing.

--

--

Jalitha Dewapura
Geek Culture

BSc. (Hons) in Engineering, Software Engineer at Virtusa