top of page
Search

Implementing Microservices - Part I

Writer's picture: Sachin TahSachin Tah

Updated: Nov 25, 2020




"Divide and Rule" policy stands good for software applications as well, at least for larger ones. Application disintegration, isolation, smaller and autonomous teams are some of the factors which act as building blocks of successful software architecture.


Software architecture guidelines and principles evolve over time. Whatever is relevant today may not be of any importance tomorrow, that's why we will be always in business 😀. Before we talk about Microservice architecture, it is important to understand what are the driving factors which forced the evolution of Microservices.


Monolithic is an architecture pattern where the entire application is designed, developed, and deployed as a single, self-contained unit. Today's Monolithic is a lot better than what we use to have 20 years back, at least now we have Monolithic with multi-layered architecture.


Monolithic Architecture


Monolithic applications are easy to implement, they definitely provide a good amount of benefits that are lucrative initially, however, long-term problems are challenging and not cost-effective. A typical Monolithic application developed using layered architecture has the following components

  • Presentation Layer - User Interface (UI) layer which runs on the user browser. A Single Page Application (SPA) application is one such example that can be implemented using a javascript framework like React or Angular.

  • Business Layer (REST API) - Business layer developed as REST API layer which is called from the presentation layer. There is a tight coupling between UI and the business layer.

  • Database Layer - DB access layer which is responsible for database connection and operations.

Considering a typical online eRetailer marketplace application that connects customers and suppliers. Following are the different layers present in this Monolithic application




Deployment of a Monolithic application with horizontal scaling is pretty straight forward


  • Web or Mobile user talks to business (API) layer via HTTP

  • Horizontal scaling a business layer is possible by using a Load balancer

  • Business Layer talks to DB via DB layer

  • DB Layer can have a failover DB which is mirrored, it is possible to switch DB connection automatically if primary DB fails

Issues With Monolithic Architecture


Although this approach has is suitable for small-sized applications with small team sizes, it's not suitable for large-scale applications. Following are some of the issues with Monolithic implementations

  • Difficult to Understand - Monolithic application is developed as a single unit, therefore, making it extremely difficult for members to know the entire codebase and its dependencies

  • Maintainability - Modules of Monolithic applications are tightly coupled, changes or fixes in one module results in deployment of the entire application or application layer

  • Scalability - Horizontally scaling Monolithic applications enforce us to scale the entire deployable unit. For example, if we want to scale a customer module, we need to scale the entire business layer.

  • Polyglot Implementation - There is a constraint of developing the entire application or application layer in only one programming language

  • Fault Tolerance - Issue in one module affects the entire application

  • Same Data Store - Monolithic applications share the same database and therefore unable to utilize the advantage and features of multiple databases. For example, one module may require RDBMS while the other fits well with a document database

  • Lacks Agility - A monolithic application is big and has a lot of interconnected modules which makes it a bad candidate for Agile and DevOps automation.


Microservice Architecture


Microservice architecture advocates splitting big applications into smaller sets that can be deployed independently. A Microservice is an application in itself and has its own architecture pattern, database, and even development and deployment lifecycle.

If we consider the above example of a Monolithic application, we can break down our modules into multiple Microservices, for example, we can come up with Customer Microservice, Supplier Microservice, Sales Microservice, Inventory Microservice, and so on. So now instead of on one large application, we may have 8 applications.


Decomposition of Microservice is tricky, decomposition of an application into Microservices can be done using below guidelines,

  • By Business capability

  • By Subdomain

  • Self-contained Service

  • Service per team

Microservice architecture tries to address most of the problems associated with monolithic applications, however, it should not be considered as a silver bullet that will solve all of your architectural issues with a click. A decision needs to be taken depending upon application size, team size, team skills, and other functional and non-functional requirements.


Advantages Of Microservice Architecture


Following are the advantages of Microservice architecture over a Monolithic one


Easy To Understand - Microservice applications are smaller in size and developed by a small number of individuals, it is easy to understand, manage and support


Maintainability - Changes in one microservice does not affect other Microservices, we will talk about how to achieve this in the below section


Scalability - It is easy to scale Microservice as per need, a customer Microservice may have a different scaling requirement than a supplier Microservice. Autoscaling is also easy if you are scaling small application units.


Polyglot Pattern - Now you can take benefit from different programming languages depending upon requirements, language features, and team skill set. Different Microservices can be implemented using different programming languages.


Fault Tolerance - Since Microservices are independent of each other, issues in one Microservice do not have any impact on other running microservices


Polyglot Datastore - Different Microservices can use different data stores depending upon their need. For example, a document database can be used to maintain application logs.


Agility - Microservices architecture fits very well with Agile methodology and can be integrated seamlessly with DevOps automation


Deployment view of Microservice architecture will look something like this

You may have noticed a new entity API gateway (Web & Mobile), what exactly is API gateway and why it is important?


Consider a situation where a web client needs to interact with all 4 underlying Microservices deployed separately on different servers with different endpoints all together. It is practically not possible to publish so many endpoints to consumers of these services. Also if one service endpoint changes or server address changes then all clients need to modify their code. Therefore to overcome such issues, a new element is introduced which is called API Gateway. API gateway is nothing but a facade for all underlying Microservices. A service consumer will talk to only this facade without even having a knowledge of underlying Microservices locations and hence provide an abstraction over all underlying Microservices. This API gateway can also provide mechanisms like authentication, authorization, logging, etc. You can write your own API gateway or if you are using a cloud platform, you can use ready-made API gateways available with leading Cloud providers like AWS, Azure. Nginx which is a reverse proxy can also be used as an API gateway.

As you can see from the above architecture diagram, all four microservices have isolated physical boundaries, it also has its own database which is not shared by any other Microservice, pretty cool right? Well, not yet, isolation Microservices has its own set of challenges to look after and the most difficult part of implementing a Microservice.


Challenges in Implementation Microservice Architecture

Following are some of the challenges we may face during Microservice implementation

Service Decomposition - Sometimes it is difficult and tricky to come up with an exact number of Microservices in a system. We need to take a call on where to stop while breaking down a system into modules and submodules

Interservice Communication - Microservices at some point in time need to communicate with each other or exchange data. For example, the Order Microservice is dependent on Customer Microservice to process an order. It is crucial to decide upon a strategy on how these Microservices will communicate with each other considering the fact that the failure of one service may create a ripple effect on all dependent services.

Integration Testing - Testing individual Microservice is easy and can be automated as well. Integration testing of multiple dependent Microservice is a difficult task and takes time. It is important to know how one Microservice responds when its dependent service fails.

Distributed Transactions - Managing data consistency is one the most difficult part during Microservice implementation. Transactions spanning across multiple microservices will not comply with the ACID properties of a transaction.


Microservices Implementation Techniques

Following are some of the implementation techniques used while implementing Microservices


Shared Database

One of the simplest implementations with Microservice is using a database that is shared by all Microservices. Tables present in the database are accessible to all Microservices. You also get the advantage of maintaining relationships between tables belonging to other Microservice along with ease of managing ACID properties of a transaction.


The shared database approach does not provide full independence to a Microservice and still has tight coupling. Also as different teams are responsible for implementing different Microservices, any change in the database needs to be communicated to other teams, creating communication gaps and dependencies within teams.

Also using a shared database defeats the agenda of independence and isolation.

As per my suggestion, we can go for this approach as an initial step (First Phase), if we planning to re-architect our existing system from Monolithic to Microservice. We can break down Monolithic applications into a smaller set of Microservices while keeping the database intact and shared. In subsequent phases, you can decide upon a plan on how to disintegrate and make the database private to respective Microservices.

Database Per Microservice

This pattern provides the highest level of Microservice isolation and deployment independence.

In this implementation, persistent data of each Microservice is kept private to that service only. Now whether to keep the database on a separate physical server or not is something you need to decide based upon application requirements.

You have the following options

  1. Separate DB instance per Microservice

  2. One DB with one schema per service, so if you have 10 Microservices, you will have 10 database schema in your DB instance

  3. One DB with one schema, however, table-level access rights for each service needs to be managed.

In the above example, if Order Microservice needs customer credit data, it will get so by calling Customer Microservice, Microservices are not allowed to access private data of other Microservices. This implementation opens up a can of worms that you need to deal with. Luckily industry-proven patterns and tools are available to take care of these issues.

Let me first outline challenges you face by implementing DB per service approach for Microservices

  1. Queries Joining Multiple Databases

  2. Distributed Transactions

In this blog we will target the first challenge, I will cover the distributed transaction issue in Part II of this blog


Queries Joining Multiple Databases


Consider a simple use case where you need to display customer name along with customer Order. You do not want to store customer information like customer name in your Order as customers may update his/her name in the future. You need to make a join on Order table (which is in Order database managed by Order Microservice) and Customer table (which is in customer database managed by Customer Microservice).


Following are two patterns which help in overcoming the above problem


1. API Composition


API composition pattern is one way of performing joins where the data comes from more than one Microservice. This pattern act as an abstract layer that performs an in-memory join of the result collected from different Microservices. You can not rule out performance overheads associate with this approach especially for large datasets and therefore an efficient implementation approach is required when performing joins. We can definitely implement some sort of caching mechanism where subsequent retrievals are fast. API composer can be implemented as a separate Microservice or can be a part of the same microservice.



2. Command Query Responsibility Segregation (CQRS)


CQRS pattern suggests the implementation of a new view only database which is a read-only replica designed to support join queries. You can consider this pattern as an event-based implementation of API composition pattern where data is not generated on the fly but is already created and kept aside for faster retrievals. A new Microservice needs to be created which subscribes to events raised by other Microservices and generates relevant data accordingly. Other Microservice will use this service to get the desired data. There are implementation overheads and costs associated with the implementation of this approach.


As per my suggestion, you should go for CQRS only if you have too many joins and performance is very critical in your application. Also if you are performing joins are on huge datasets where API composition won't work, CQRS is the way forward.


As you may have realized by now, there are implementation overheads associate with Microservices, but as I said before, it totally depends upon pain versus gain and you should do a thorough analysis before considering Microservice implementation in your project.


In my next article, I will highlight issues associated with distributed transactions and design patterns to implement for managing data consistencies.


Till then Happy Reading.....

93 views0 comments

Recent Posts

See All

Comments


bottom of page