Introduction
First of all, what are Microservices? This blog is an introduction to the Microservices architectural style and the impact on how you may be used to designing your application at present. I will explain here first what the microservices are providing you with a definition and then more in-depth explanation mainly by using a monolithic application as a way to compare and contrast the microservices approach. Also, I will explain here the pros and cons of using micro service architecture.
Overview of Microservices
At present there are certainly a lot of industry hype around this topic. Microservices are best described as an architectural style for building applications. The best way to understand this style is to contrast it with the Monolithic applications. So microservices are an architectural style where a single application is built not as a single application but as a suit of small services each of which is running as an independent process and each of which communicate with the others through some type of open or at-least well known protocols (for ex:HTTP) with all of the benefits and risks that this approach applies.
Working Definition of Microservices
Microservices are about building individual applications as a suit of small services. This is in contrast to having a single monolithic application or executable. Each of these services runs as an independent process. So, services are not really modules or components of code within a single executable. They actually execute on their own. Microservices intercommunicate with each other via HTTP, TCP or FTP protocols. Microservices are separately written,separately deployed, separately scaled and separately maintained.
In fact, they can be written in different languages. The services are used to encapsulate the business logic or business functionality not really the technical functionality. They represent a different way to encapsulate functionality as opposed to different language constructs that were used to such as packages, classes or jars. The services themselves are independently replaceable and upgradable because they are separately maintained application.
Microservices are not the same as service-oriented architecture. As a way service-oriented architecture (SOA) is about integrating various enterprise applications. Microservices are about the design of single application. Microservices are certainly not going to be the solution to all of the problem that we are facing now. The truth is that there are situations where the microservice approach would introduce serious drawbacks which we should know about this.
It is possible to find many cases of existing applications composed of separate independent inter communicating processes and it is possible that you might have worked on the applications that have accepted the essence of what microservicesare all about. Microservices approach has been implemented by big industries in the market like twitter, Facebook and Netflix etc.
Netflix has done a great deal of work to eliminate their monolithic java applications in favor of smaller independent microservices.
Microservices vs Monolith Examples
Monolith architecture is used for traditional server-side systems. The entire system function is based on a single application. Monolithic apps can also be faster than microservices apps. Because they do not have the logic to communicate by APIs.But in Microservice based architecture, every feature has its own application.Let me now take you through a more practical explanation of microservices by exploring a traditional monolithic application.
Then we can see how microservices are different by comparing. Let’s think of a traditional shopping kart application something with a web interface. We can think of probable predictable items.: “Search” i.e. Searching for products.
We need to store all of our products in some kind of catalog. We need inventory management also. We have to let customers put their items to shopping cart and go through a check out process. Then we have to think about order fulfilment.
Now let’s take a look at how a traditional monolithic application would look like :
So, on the above diagram, in this approach, we would have data access objects talk to our database to handle persistence. We would have our use cases implemented by our service layer and also, we would have a controller layer serving up the traditional web pages to traditional web browsers. We might even have some dynamic java script code on our pages talking to the controllers too. So, here everything is basically represented by a layered architecture as below:
Now please take a closer look at the above image. There are many different kinds of controllers for the different pages in the application like the Search page, a product review page, card display page and so on. The service layer attempts to model our use cases and we probably have separate services to control Search functions and catalog management functions , review functions and cart functions and so on.
At the repository layer, there are typically DAO objects representing each table or perhaps small group of inter-related tables. So here we have DAP for products, inventory and carts and so on. We can except that within the database we have various tables set up to support the storage needs for various parts of the application.
Now the above application structure is well organized, and it is well understood. Then here question arise why is there a move to something different architectural style from this Layered style.
So, in this Layered architectural approach what we discussed above, we will face various challenges here:
- The controllers that were designed for our web interfaces were not designed for other channels like Smartphone, tablets, TVs etc. Also, we have to think different kind of networks like mobile network. We also have to think about different types of persistence and backend technology.
- Product search will be much faster and robust if we can get it out of a relational database and use elastic search. Product reviews can be stored flexibly in a document store like Mongo DB. In Mongo, we do no need to worry about schema changes. The shopping cart will be faster and simpler if we can sue simple key value store like Redis. Also, we need to access legacy backend technologies like SAP for orders and shipping, PayPal for handling all the payments.
- So, here we are more likely to accept group of backend technologies in our single application written in a single language. Here for one thing, we will have to support all the jars and supporting libraries for all of these technologies in a single executable.
Our monolithic code base is a single application. It is a single code base. If it is small enough, then it is pretty easy for a single team to implement features. Also, it is relatively easy to manage source code management. It is also very easy to test and deploy using contentious delivery pipeline. But now the problem arises here:
What if the system is large and complex? What if there are large number of features that need to be implemented very quickly?
- So, for this we need a larger team and larger code base. Large code base is very hard to manage. So, the management approach will be to break the big team down to little teams. Each team will be working on a subset of features. And each one will be dedicated to maintaining their separate code base for a single module of a larger application. With this process, there might be several problems.
- A big problem is what will happen when a flaw or a bug is discovered late in the pipeline such as user acceptance testing. Now we can not deploy the application until we fix that problem or at least back it out. Now each team has to fix the specific issues in specific versions of specific modules. So, this can quickly become a big mess. And most of this has nothing to do with coding but assembling and deploying the large application.
Advantages & Disadvantages of Monolithic Architecture
Advantages of Monolithic
- Easy to understand or comprehend.
- Easy to test as a single unit
- Easy to deploy as a single unit
- Easy to manage but up to a size limit
- Easy to scale using load balancer but up to a certain extent
- Easy to manage changes up to a limit
Explanation:
So, the monolithic is a single application executable and there are advantages and disadvantages to it.
It is quite easy to understand a single executable even a large one. Afterall the layer diagram I have given above, it is very easy to determine which module lived where. But it is not easy for the individual developer to digest the entire thing. There will be code specific to different storage technologies plus there will be millions of lines of code. Also, we have to work in a single language.
But there could be other languages frameworks for any individual module in application that can work quite better than what we are currently using now and committed to use. So, in this case we cannot change the language or framework or technology.
Next the ability for us to modularize our application is really subjected to the capabilities of the languages or frameworks that we have chosen. But imagine a situation in monolithic application, where we have to do some part of our system work in Microsoft SharePoint, then we have to use dot Net language. So, here we will be stuck with whatever language we are using for the entire application.
Monolithic Drawbacks
- Language / Technology / Framework Restriction
Entire app written with single technology stack. Can not experiment or take advantage of emerging technologies in the current market. - Digestion
Single developer can not digest a larger code base
Singe team can not manage even a single large application
Amazon’s “TWO PIZZA” rule: - Deployment as a single unit:
Can not independently deploy single change to single component
Changes are held by other changes - Explanation:
Our app is committed to a single technology stack forever.If there are portions that could get benefits from another new technology, then we will be trapped if we are using monolithic app. We will face rewrite situation.We also don’t have the freedom to experiment different technology. Here in this case we have to make wholesale adoption.
A single developer can not digest a large code base. Because of this single team can not manage a single large codebase and a large team has its own challenges. Amazon has a term for this. They call it two pizza rule which basically says that if you can not feed your team with two pizzas as the team is too big.
Deployment as a single unit is great for testing, versioning and manageability. But we become unable to independently deploy a small change to a single component. And as a result, all of the changes get held up. This affects our ability to rapidly deliver the value the way continuous delivery should happen.
Why Microservices? Microservices Architecture Anatomy with Example
(MicroService Architecture Diagram for Shoppping cart App Example)
- Microservices are small independent applications built around individual functional areas of our system. They freely intercommunicate with each other over open protocols when they need to work together. Because Microservices are small and focused, they are usually backed by one or two persistence technology so they can use framework best suited for that technology and business situation.
- Now we still have various client technologies that need to use our services and having each client access each service directly can lead to a number of issues. So, we usually have a component that we call an API Gateway. Its purpose is to present an easy to use interface for the client technology in question and it handles all of the complexities of talking to the individual services which it does on the sever side where it is much more efficient. It can also handle things like caching and Authentication etc.
- Now at first glance, Microservices look like individual application components but the differentiating concepts here is that the “Componentization”. Componentization is done by creating separate services not by using the constructs available in any specific programming language. The services become independent applications or small independently deployable applications.
Now when we break a system down to individual modules, then it forces us to be more disciplined in our interfaces.
When we put everything in to a single application it is very flexible. Also, the changes to any given application are scoped to their affected service. Let’s say we have decided to take major revisions to our “Product Search” capabilities in our application. But also, we have decided to make big revisions to “Payment” service. We can deploy each one of these differenceswhen they are ready without having to worry about whether the other set of changes is ready to go, and without having to set up source control management branches. Since microservices are small independently deployable application and not part of a single code base. Not only they can be deployed separately, but also, they do not necessarily need to be written in the same programming language. We can experiment with other language or frameworks without making deep commitments to unknown technology.
So, in this example , you can see that we have decided to some implementations in Scala in Python rather than limiting ourselves to just Java. Microservices communicate over different lightweight protocols like HTTP, TCP, UDP or messaging technology(AMQP). The payloads of these messages are also light weight. We can use JSON , XML or Google protocol buffers as payload. This forces us to be disciplined about our interfaces.
One of the things you may read about the outside Industry is what Netflix calls this as “Cloud Native Architecture”. This is based on its systems communicating via API. It is not based on throwing everything into the same DB. Having a common DB, most of the companies have tried to do on this way. This introduces unexpected dependencies and restricts in the process of rapidly innovation.
Now you can see in the below image that our services are speaking to each other over HTTP but some of them are using TCP or AMQP messaging what ever is the best suited.
(Microservices communicating with them using various protocols)
Microservices are intended to encapsulate business capabilities. But with the monolithic layer, we are primarily componentizing technical capabilities like the DAO layer or the controller layer. Now think of the vertical slices though the monolith by the business function. Everything related to search will go to the Search service. Everything related to the cart will go to “Cart” service like below structure:
(Each microservices exposing rest APIs to access them)
- Now we are allowed to have little services that perform purely technical tasks and we can use components like DAOs and Controllers inside our services but the emphasis on microservices is the separation of business capability into different independent services. If you look at the above services in the above image, you can tell from the names that each service is focused on a small or micro part of the application. Look at the “Cart” service in the above image. It has exposed many restful services for creating a cart, getting a cart or adding some items to the cart and so on.
- One element you can notice in the Microservices concept is the idea of “Decentralized government”. It is easy for each of the services to be managed in an independent way. Here not only we are able to choose right technology for each of the services but also, we can deploy them at different times.
- Few principles we have to keep in mind for our services that our services should be tolerant consumers. This means that services should be resilient to the changes made on the services that they call. If a new field is added in an interface, then this should not cause a failure. And on the other side we should treat the interfaces exposed by any services as a contract written by the needs of the consumer. So, we have to think about how everyone is going to consume our services and how changes may affect them.
- Microservices should not be Orchestrated but Choreographed. This means we want our individual services or microsystem to be like. We want our system to be composed of interactive components just like that are good human beings who work smoothly with each other without the need for centralized governance.
- Microservices are free to use the best technology for the job and this includes the persistence technology. The RDBMS is not always the best choice. The adoption of various types of storage technologies is called “Polyglot Persistence”.
Microservices Advantages
- It is very easy to digest individual services.
- Microservices allow us to align our organization to architecture.
- Through well-defined rest APIs The Services talk to each other with the use of various opensource protocols
- Microservices are very easy to test, deploy, manage and re-architect and re-write and scale individual applications. This is a huge advantage.
- Separate codebase allocated for each micro service, so it is relatively easy to manage the code base by a small team.
- There is no such criteria or restrictions that Each individual Services has to use the same technology or framework. Services can use different frameworks/libraries according to the business requirement or need.
- Change Cycle is decoupled. What does this mean by!! This is nothing but that we can roll out the changes to individual services as soon as they are ready without waiting for any other things.
- And from staffing perspective, we can scale easier. And we are also not locked into a particular programming language.
- It incorporates functional decomposition: Th idea thatby break up of functions we can scale individual components.
- Microservices enable segregation model and with microservices, we can target security concerns. This means we can look up once service and protect that service which contains the most sensitive data.
- Microservices are very easy to manage. The individual applications are easy to manage. We as a hire Java developer can walk in on the first day and can understand the code. A small team even an individual developer can modify the code, test it and deploy it or even completely modify it.
Challenges we may face with Microservices
- In Microservices, Complexities can not be eliminated. The complexity has just moved out of the application but into the operations layer.
- Instead of one bit of application code calling another, now we have a remote call. Microservices are inherently distributed applications. When we have remote calls, then we have to think about what happens when the target service is unavailable. But it is never needed to worry about when we work in monolithic application. So, in case of Microservices, we need to design for failure scenarios. There is an always a need of monitoring the application if it is up and running. And also, one more thing is that in Microservices, the remote call is always expensive in terms of resource and latency.
- For the most part, the transactions are absent in a microservice architecture as the operations are spread between services. Now individual services can make use of transactions but if we had to do something across the services, then we have to rely on eventually consistency techniques.
- Another irritation in microservices is sometimes features span multiple services and when this happens, the Monolithic architecture’s ease of testing and deployment comes into play. The monolithic becomes easier here. So basically “Change Management” becomes a tougher issue here. We have to think more carefully about the interaction of services.
- For the Microservices, it is easy to manage changes, but depending on the nature of the changes they become tougher and harder. Anytime that changes the spanned multiple services. Now related to this I will discuss the situation where there are any kind of refactoring that we might have to do across module boundaries. Individual microservices are really easy to refactor. But what if we want to split one service into two or if we want to combine two services into one. These types of things all become tough.
Best Principles of Microservices Implementation
- Now Assuming if want to adopt the Microservices and want to go for the microservices architecture. Then how do we break up an existing monolithic application.
- The primary driving force should be the business functionality. We can organize according to noun or the verb. But these are very limited approach.
- Primary Consideration: Business Functionality:
- Noun-based( for ex: catalog, cart, customer)
- Verb-based( Search, checkout, shipping)
- More mature principles are things like “Single ResponsibilityPrinciple” where the service has the responsibility for a single thing like a cart or a payment. The cart service is just for holding products in cart. It is not responsible for other stuffs like inventory or payment.
- But the best guidance comes from a concept called the “Bounded Context Principle”. This principle comes from domain driven design. Briefly you take a large domain and you divide it into exclusive contexts and where the data appears to be duplicated across the contexts, you have to define the interrelationships very precisely.
Conclusion
In Microservices, size is not the compelling factor but the freedom to implement the best solution for a focused domain. But if someone is looking for some type of size guidance, an individual developer should be able to digest an individual microservice. Microservices should be small enough to be built and managed by small team. If we were to document the service comprehensively then it should be small enough document to read and understand. Another way of speaking is that all software has its own secrets that are known to the original developers. The number of secrets inside the code or application should not be more but it should be merely of dozens.
One thing please remember that Microservices are not same as SOA. There are some similarities between them. SOA is about integration between systems. But Microservices is really about the architecture of the individual application taking individual application that we ordinarily create from single executable and breaking into multiple focused executables that work together.