Microservices is often likened to MSA. MSA refers to the way in which a complex system is built from a collection of smaller applications, where each application is designed for a specific limited-scope function. These small applications (or services, or microservices) are independently developed and can be independently deployed.
Each microservice has an API interface for communicating with other microservices in the system. The way all these individual microservices are organized together forms the larger system function.
In order to understand the value of microservices and the challenges one faces in designing an MSA, it is imperative to understand how microservices communicate and interact with each other.
Microservices can communicate together in a linear or non-linear fashion. In a linear microservices pipeline, each microservice communicates with another microservice, processing data across the system in a sequential manner. The input is always passed to the first microservice, and the output is always generated by the last microservice in the system:
Figure 1.1: Linear microservices pipeline
Practically, however, most existing systems are formed using a non-linear microservices pipeline. In a non-linear microservices pipeline, data is distributed across different functions in the system. You can pass the input to any function in the system, and the output can be generated from any function in the system. You can therefore have multiple pipelines with multiple inputs, serving multiple functions and producing multiple outputs:
Figure 1.2: Non-linear microservices pipeline
Consider the following diagram of a simplified order fulfillment process in a typical e-commerce system. Each function within the Placing an Order process represents a microservice. Once an order is placed by a customer, an API call is triggered to the Add/Update Customer Information microservice to save that customer’s information or update it if needed. This microservice sole responsibility is just that: manage customer information based on the data input it receives from the API caller.
Another API call is issued at the same time to the Verify Payment part of the process. The call will be directed to either the Process PayPal Payment or the Process Credit Card Payment microservice depending on the payment type of the API call. Notice here how the payment verification process is broken down into two different microservices—each is specifically designed and developed for a specific payment function. This enables the flexibility and portability of these microservices to other parts of the system or to another system if needed.
After payment is processed, API calls are triggered simultaneously to other microservices in the system to fulfill the order:
Figure 1.3: A non-linear microservices pipeline example – customer order
The order placement example shows how modular and flexible designing an MSA enterprise system can be. We will often use this example to show some of the advantages and challenges one may face when designing, deploying, and operating an MSA enterprise system.
It is essential that we go over some of the advantages and disadvantages of building enterprise systems using MSA to help decide whether MSA is a better option for your organization or not.
Note that some of the advantages listed next could also be considered disadvantages in other situations (and vice versa).
Advantages of microservices
There is some significant value to implementing MSA. The following are some of the advantages we see applicable to today’s market.
Autonomy
One of the biggest advantages of microservices is their autonomy—it is the keystone for many of the other advantages of MSA. And because of their autonomy, microservices have their own technology stack, which means that each system service can be developed with completely different tools, libraries, frameworks, or programming languages than any other system service, yet they integrate with each other smoothly.
Microservices can be developed and tested independently of any other application within the system, which enables each microservice to have its own life cycle, including quality assurance (QA), change management, upgrades, updates, and so on, which in return greatly minimizes application dependencies.
Portability
Microservices’ autonomy enables them to be portable across platforms, operating systems, and different systems, all independent of the coding language in which these services were written.
Reuse
When reusing microservices, you don’t need to reinvent the wheel. Because of their autonomy, microservices can be reused without the need to add additional coding, changes, or testing. Each service can be reused as needed, which largely increases system flexibility and scalability, significantly reduces the development time, cost, and deployment time, and reduces the system’s TTM.
Loosely coupled, highly modular, flexible, and scalable
Microservices form the main building blocks of an MSA enterprise system. Each block is loosely coupled with the other blocks in the system. Just like Lego blocks, the manner in which these blocks are organized together can form a complex enterprise MSA system building a specific business solution.
The following diagram shows an example of how we can build three different systems with multiple microservices.
The diagram shows nine services, and seven out of these services are organized in such a manner to reuse and build three different systems—system A, system B, and system C. This shows how loose coupling enables flexibility in MSA in such a way that you can reuse each service to build a different system function.
You can build a system with minimal development added to existing microservices either acquired by a third party or previously developed in house. This largely enables rapid system development, new feature releases, very short TTM, and reliable, flexible, and much more stable hot updates and upgrades. All of this increases business continuity (BC) and makes the enterprise system much more scalable:
Figure 1.4: Flexibility and modularity in microservices
Shorter release cycle and TTM
Because of the individual and independent services features we previously mentioned, the deployment of microservices becomes much easier and faster to perform. Automation can play a great role in reducing time-of-service testing and deployment, as we will discuss later in this chapter.
Fault tolerance and fault isolation
Each microservice has its own separate fault domain. Failures in one microservice will be contained within that microservice, hence it is easier to troubleshoot and faster to fix and bring back the system to full operations.
Consider the order fulfillment example we mentioned earlier; the system can still be functional if the Message/Email Customer microservice—for example—experiences any failures. And because of the nature of the failure and the small fault domain, it will be easy to pinpoint where that failure is and how to fix it. Mean Time to Resolution (MTTR) is therefore significantly reduced, and BC is greatly enhanced.
Architects are sometimes able to build the system with high embedded tolerance to prevent these failures to begin with or have other backup microservices on standby to take over once a failure is detected in the primary microservice. One of the primary objectives of this book, as we will see later, is to be able to design a system with high enough intelligence to provide the desired high resilience.
What software architects have to bear in mind, however, is that, with too many system components in the MSA, too many things can go wrong. Architects and developers, therefore, have to have solid fallback and error handling to manage the system’s resilience.
The communication between the different microservices, for example, can simply time out for whatever reason; it could be a network issue, a server issue, or too many API calls at the receiving microservices or at the event-handling mechanism developed in the system, overwhelming this system component and causing failures or delayed response.
There are many data flow streams and data processing points in the system that all need to be synchronized. A single failure, if not taken care of properly by the system, can create system-cascading failures, and accordingly could cause a failure to the entire system.
How fault tolerance is designed will be a big factor in how system performance and reliability are impacted.
Reliability and the Single Responsibility Principle (SRP)
If you come from the programming world, you are probably familiar with the SRP in object-oriented programming (OOP): A class should have one, and only one, reason to change. Every object, class, or function in the system should have a responsibility over only that functionality of the system, and hence that class, once developed, should only change for the reason it was originally created for. This principle is one of the main drivers of increased system reliability and BC in MSA.
At the initial phases of developing an MSA enterprise system, and during the phase of developing new microservices from scratch, the MSA enterprise system may not be fully tested or fully matured yet, and reliability may still be building up. When the system matures, changes to individual microservices are minimal—if any— and microservices’ code reliability is, therefore, higher, the operation is more stable, fault domains are contained, fault tolerance is high, and the system’s reliability thus becomes much higher than similar systems with a monolithic architecture. Reliability is highly contingent on how well the system is designed, developed, and deployed.
Reducing system development and operational cost
Reusing microservices largely reduces the development efforts and time needed to bring the system to life. The more microservices you can reuse, the lower the development time and cost will become.
Microservices do not have to be developed from scratch; you can purchase already developed microservices that you may need to plug into your MSA enterprise system, cutting the development time significantly.
When these microservices are stable and mature, reliability is higher, MTTR is much shorter, and hence system faults are lower and BC is higher. All these factors can play a major role in reducing the development cost, operational cost, and total cost of ownership (TCO).
Automation and operational orchestration are ideal for microservices; this enables agile development and can also decrease operational costs significantly.
Disadvantages of microservices
Microservices come with a set of challenges that need to be taken into consideration before considering an MSA in your organization. The good news is that many of these challenges—if not all—can effectively be addressed to have in the end a robust MSA enterprise system.
Mentioned here are some of the challenges of microservices, and we will later in this chapter talk about some of the methodologies that help address these challenges.
Complexity
MSA systems contain many components that must work together and communicate together to form the overall solution. The system’s microservices in most cases are built with different frameworks, programming languages, and data structures.
Communication between microservices has to be in perfect synchronization for the system to properly function. Interface calls could at times overwhelm the microservice itself or the system as a whole, and therefore, system architects and developers have to continuously look for mechanisms to efficiently handle interface calls and try to eliminate dependencies as much as they can.
Designing the system to handle call loads, data flows, and data synchronization, along with the operational aspects of it, could be a very daunting process and creates layers of complexity that are hard to overlook.
Complexity is one of the main trade-off factors in implementing and running an MSA enterprise system.
Initial cost
MSA systems usually require a large number of resources to be able to handle the individual processing needs of each microservice, the high level of communication between microservices, and the different development and staging environments for developing these microservices.
If these microservices are being developed from scratch, the initial cost of building an MSA system would therefore be too high. You have to account for the cost of the many individual development environments, the many microservices to develop and test, and the different teams to do all these tasks and integrate all these components. All this adds to the cost of the initial system development.
Tight API control
Each microservice has its own API calls to be able to integrate with other microservices in the system. Any change in the API command reference set—such as updates in any API call arguments, deprecated APIs, or changes in the return values—may require a change in how other microservices handle the data flow from and to that updated microservice. This can pose a real challenge.
Developers have to either maintain backward compatibility (which can be a big constraint at times) or change the API calls’ code of every other component in the system that interacts with the updated microservice.
System architects and developers have therefore to maintain very tight control over API changes in order to maintain system stability.
Data structure control and consistency
The drawback of having independent applications within the enterprise system is that each microservice will have to maintain its own data structure, which creates a challenge in maintaining data consistency across your system.
If we take the earlier example of customer order fulfillment, the Add/Update Customer Information microservice should have its own database totally independent from any other database in the system. Similarly, the Update Item Inventory microservice should be the microservice responsible for the item information database, the Update Orders Database microservice should have the orders database, and so on.
The challenge now is that the shipping database will need to be in sync with the customer information database, and the orders database will have to contain some of the customer information. Also, the Message/Email Customer microservice has to have a way to access customer information (or receive customer information through API calls), and so on. In a larger system, the process of keeping data consistent across the different microservices becomes problematic. The more microservices we have, the more complex the data synchronization becomes.
Once again, designing and developing a system with all that work in mind becomes another burden on the system architects and developers.
Performance
As we mentioned earlier, microservices have to communicate with each other to perform the entire system function. This communication, data flows, error handling, and fault-tolerance design—among many other factors—are susceptible to network latency, network congestions, network errors, application data processing time, database processing time, and data synchronization issues. All these factors greatly impact system performance.
Performance is another major trade-off factor in adopting and running an MSA enterprise system.
Security
Because of microservices’ autonomy and their loose coupling, a high number of data exchanges between the different services is necessary for the MSA to function. This data flow, data storage within each microservice, data processing, the API call itself, and transaction logging all significantly increase the system attack surface and develop considerable security concerns.
Organizational culture
Each microservice in the MSA has its own development cycle and therefore has its silo of architects, developers, testers, and the entire development and release cycle teams, all to maintain the main objective of microservices: their autonomy.
MSA enterprise systems are built from a large number of microservices and mechanisms to manage the interaction between the different system components. Developers have to therefore have system operational knowledge, and the operational teams need to have development knowledge.
Testing such complex distributed environments that one will have in the MSA system becomes a very daunting process that needs a different set of expertise.
The traditional organizational structure of one big development team solely focused on development, one QA team only doing basic testing, and so on is no longer sufficient for the way MSA is structured and operated.
Agile development and DevOps methodologies are very well suited for microservices development. You need agile processes to help maintain the fast development and release cycles MSA promises to deliver. You need DevOps teams who are very familiar with the end-to-end process of designing the application itself and how it fits in the big picture, testing the application, testing how it functions within the entire system, the release cycle, and how to monitor the application post release.
All this requires a cultural shift and significant organizational transformation that can enable DevOps and agile development.
Important note
We rarely see a failure in MSA adoption because of technical limitations; rather, failure in adopting MSA is almost always due to a failure to shift the organization’s culture toward a true DevOps and agile culture.
The benefits outweigh the detriments
The main questions you need to answer now are: Is building an MSA worth it? Can we make it happen given the current organizational culture? How long will it take the organization to transform and be ready for MSA? Do we have the luxury of waiting? Can we do both the organizational transformation and the building of the MSA enterprise system at the same time? Do we have the resources and the caliber necessary for the new organizational structure? Is cost an issue, and do I have the budget to cover that?
Well, first of all, if you are planning to build a large enterprise system, and you have the budget and necessary resources for starting this project, building the system as MSA is definitely worth it. All initial costs endured and time spent will eventually be offset by the long-term cost and time-saving benefits of having an MSA system.
Nevertheless, you are still the one to best address all these previous questions. There are overwhelming and compelling advantages to adopting MSA, but as we have seen, this is not a simple undertaking; so, whether an organization is willing to walk that path or not is something it—and only it—can answer.
Now we know what the advantages of deploying an MSA are, and the challenges that come with MSA adoption, we will now go over different enterprise architecture styles, what they are, and the differences between each other.