This series of articles on Microservices Architecture (MSA) started by covering the needs and motivations of microservices and moved on to this article, which discusses the shortcomings of Monolithic Architecture. We also covered microservices design patterns, the pitfalls of Microservices, and the major microservices infrastructure components, which included:
- Descriptions of microservices
- Evaluation and code samples
- An overview of containers
- An intro to native microservices, cloud platforms, messaging layers, security and logging.
This article will provide readers with Obelix, a Microservices Architecture reference implementation. You may use this as the starting point for your Microservices Architecture. You may also directly use this as a reference implementation for your microservices strategy or as code to learn and implement the Microservices Architecture for your company or development team.
Overview of Monolithic Architecture
One of the most common software architectures that a developer can safely say has been in existence since software development began is the Monolithic Architecture. There have been many forms of Monolith over the years, including single blocks of software like desktop apps, distributed architectures such as Tier-2, Tier-3, and N-Tier. These are all examples of Monolithic Architecture.
For this article, we will be using one of the most common and standardized examples of Monolithic Architecture. Prior to the advent of Microservices, most Enterprise systems would choose 3-Tier architecture for their software implementation.
Tier vs Layer
Before we dive into the details of Monolithic Architecture we should discuss the differences between Tiers and Layers. For starters, Tiers are physical separations of groups of similar functions or Layers. As an example, the User Interface (UI) renders in the Browser, qualifying as broad level functionality with a specific logical concern for the client-tier or presentation-tier.
The Presentation Layer, meanwhile, can exist alongside a Business Layer, either separately on a web server and application server or together on an application server. This qualifies as different physical functionalities that have similar logical concerns to the Business Tier.
Meanwhile, the database schema will be on a logical Database Tier, which by itself is concerning. Because of this, a developer has to take note that a Tier is different from a Layer. In some web development books – or even in usage – the Web Layer might be the first (or one of) Tiers among the three Tiers in this architecture. The User Interface gets rendered in the Client Tier by this Presentation Layer.
Presentation Layers prepare the User Interface for rendering based on the data that is returned from the Application Layer, which fetches the data from the Database Layer. With this in mind, you should better understand that Tier is a logical grouping of related physical layers. Tiers, meanwhile, are logical units, whereas Layers have a physical presence.
3-Tier Architecture Explained
In this next section, we will look at each important tier that makes up the 3-Tier Architecture.
The first important tier is the Client Tier. The Client Tier resides entirely on the client or the end-user interface of the application. This gets rendered by the web container. The end-user will interact with the application through this User Interface that is rendered on the Client Tier. Our example is based upon a web or DHTML User Interface rendered in the browser on a PC.
The Application Tier can be thought of as the J2EE Application Server Layer. Traditionally, this consists of two main Layers: the web container and the application container. The web container or web layer will hold the web rendering components of the application. You can visualize this as a separate physical deployment on a web server. The typical technologies in this Layer and container are JSP, Servlet, Struts (MVC), JAX-RS (REST), JAX-WS (SOAP), Spring (MVC), ASP.NET, and PHP.
The EJB container can best be described as the core application or business logic container of any application. This is an independent layer of deployment. Even though it is sometimes referenced as an EJB Container, you can also refer to it as the application container, Application Layer, or Business Layer. The brain, heart, or logic of an application will always lie in this Layer, which can be called simply, the application.
It’s primary functions include interacting with the database, processing business logic, and sending data or objects to the web container. Technologies in this Layer and container include EJB, Spring, Windows Service, and Core Java. Note, the Application Layer does not always need to be an application server; it could also be a web technology such as JAX-RS (REST) or JAX-WS (SOAP).
The Data Tier is also known as the Database Server or Data Layer. The purpose of this Tier might be obvious, based upon its name: it is used to store data. You can think of it as a RDBMS or database. The database might be made up of various schemas and tables that store the application data. Some of the flavors of RDBMS include Oracle, MySQL, PostgreSQL, and DB2. Note that some authors and developers may refer to this as the EIS Tier (Enterprise Information Services Tier). Further, note that the data may not always reside in a RDBMS. It can be NoSQL, other web services, streaming data sources, connected devices, unstructured data, file systems or any other form of data that might need to be accessed or processed by an application.
Disadvantages of Monolithic Architecture
Below are some of the disadvantages of using Monolithic Architecture
Monolithic systems are built by single focused development teams that may be geographically dispersed. The architecture, from a Layer or feature perspective, might represent the way development teams of varying specialities are organized. Usually, team members on these teams will possess the same skill set (broadly) or utilize the same technology stack. In some views this setup does not truly allow a team to completely concentrate on a singular problem or a feature. In addition, there is a chance within the same organization that people using different skills might want to come together in an organization to develop application features or components. Each of these team members might want to layer their individual components to their own specific needs or Ecosystem. This scenario is not possible within a Monolithic System.
Systems built using the Monolithic ideology are more tightly coupled across Layers or components. Since they live on the same ‘Server Function’ the majority of the time, services or components are typically more tightly coupled. Even though these services or components might be built using SOLID and OOP paradigms, they may still be considered more tightly coupled as a result of being packaged in the same binary.
Monolithic systems – especially those built with a lot of non-functional requirements related to performance and scalability can be marred by symmetric scalability. This can lead to system resources being shared between services that do not have scalability requirements and resources that do have scalability requirements. Typically, systems require asymmetric scalability, in which the core features or core business logic services may have higher scalability requirements and the helper – or non-core features might require less hardware or memory requirements.
In Monolithic Systems, if a server experiences downtime, most of the time the entire application stops responding – even If it is highly available, There may be times at peak load where the system stops responding or slows down to the point that the application is actually unavailable.
In Monolithic systems, performance needs to be planned for the entire application. This includes performance testing. As noted earlier, the parts of the system that are suffering from severe load might cause the entire system to slow down. Though this point is similar to the scalability point, you should note that the performance of a system or API will have to be accounted for separately from the scalability. Though the same reasons apply, it has to be thought of as localized or in an API specific notion.
Despite having existed since nearly the advent of software engineering, Monolithic systems have never had certain standardized infrastructure components. Even with the advent of SOA, only a few infrastructural components began finding their place within software architecture. Most of the time infrastructural abilities for service availability, failure recovery, configuration management, service health, service discovery, security infrastructure, messaging mechanisms, logging, log analysis and more were mostly built or incorporated in a very custom manner, dependent upon project or product need.
Perhaps the most important outcome of software engineering is the fact that the innovation or product is readily available and sellable to the marketplace. The greatest disadvantage is that the business versus engineering bridge is more complicated or may require more time to deliver when Monolithic Architecture is involved. In addition, the product is almost always thought of as a complete unit and will be sold as a subscription, fixed price, or pay as you go mechanism. Usually, when a customer wants only a few of the services or features, business teams would bundle them. In those instances, the product would still consist of one large unit of code or binary.
The topic of databases needs to be discussed in detail. as this is one of the primary causes of issues when it comes to performance, scalability, stability, and availability. One of the primary motivations of a Microservices Architecture is to provide a database per service architecture. In a lot of cases, a software architect is given the arduous task of meeting, delivering and exceeding not just the functional requirements, but also the non-functional requirements.
When we speak of non-functional requirements, we can speak in terms of performance, scalability, stability, and availability all in the same breath. Even though they are related, these elements all usually need to be handled separately. Most of the time, these Issues have a one-to-one correlation with database performance and scalability. If these issues are not related to the database, they may have to do with the data access layers of the application. Also, note when mentioning databases here we mean RDBMS; most Enterprise applications and products are built using RDBMS databases.
For nearly every request sent to an application, the database is the one critical resource that dictates the performance. As the Load or number of requests increases, the database can deteriorate in performance. Also, the Increase of requests to an application reduces the performance for each request or query to a point that the application response time may become unacceptable. This is what is known as the scalability of the application or database.
Once the requests exceed a given threshold, the application can become unstable and there might be requests that are served very slowly or not served at all. Even though measures exist to place this in check, the number of active requests may increase to such an extent that the application or database becomes unavailable or involuntarily terminates.
The entire effort in software application architecture and design is now focused to make sure that the application meets the performance, scalability, stability, and availability-based non-functional requirements. The point is that the database is one resource that is the biggest bottleneck when it comes to meeting requirements. Even with adequate functional, load, stress or soak tests, the application may fail while In real-world production environments.
Keeping the above in mind, It is clear that – more often than not – the database or RDBMS can easily become an Albatross around the software architect’s neck.
The Promise of Microservices Architecture
Below are the promises of the Microservices architecture and issues it seeks to resolve.
Promise of Microservices for Development Teams
With the advent of Microservices, the promise of allowing development teams to focus on their specific components or services, irrespective of the technology stack, Layering, or database. This allows global teams to concentrate on their development without needing coordinate with other teams except for common components, interaction mechanisms, or infrastructure services.
Promise of Microservices for More Independence
With Microservices, each of the services can be made independent of each other and therefore become ‘Loosely Coupled’. They can be deployed on disparate servers and can even be built with any technology that is the expertise of the company or development team.
Promise of Microservices for Scalability
One of the greatest advantages of Microservices is that it allows developers to architect or design systems that can scale independently at every level. This includes the service level, the database level, or any resource that may otherwise have been shared. This allows development teams to plan and size for systems accurately and more cost effectively. The organization will get almost every penny’s worth through accurate sizing and scaling exercises.
The resources can be allocated and used as the actual customer usage dictates in the budgeting. Despite this, the challenges introduced by communication mechanisms within Microservices or distributed database transaction mechanisms may result in negative outcomes.
Promise of Microservices for Availability
In the Microservices world, the independent nature of services now allows us to plan for high availability much easier. Fault tolerance, failure recovery, retry on fail mechanisms are now more automated and efficient. Also, the failure of a single service will never bring the entire application down. For mission critical systems, this is a great advantage as parts of systems or features will continue responding even though a few services have failed in the ecosystem.
Promise of Microservices for Performance
In theory, the performance of Microservices should be greater than the same Monolithic Service since the application or feature will now have its own server, database and resources. Since the Microservices have a lot of infrastructural services and communication overhead, some developers may experience a negative outcome. Note that If a Monolithic Service were to be built on a database per Microservice sort of architecture, it is bound to perform much better than it’s Monolithic counterpart.
Promise of Microservices for Infrastructure
With Microservices, there is a widely agreed upon, standardized architecture that is a master blueprint for organizations to follow for their Microservices Architecture. Even if companies were to adopt or implement only partial infrastructural components from the said standard it would still mean that there is uniformity in the way Microservices are implemented.
Promise of Microservices for Business
Inherently, using Microservices Architecture, the advantage for businesses is the ability to independently sell and size the services and the associated hardware or resources for a customer. The business can plan for subscriptions, pay as you go, or fixed price at a service level much easier. Also, any new service or custom services can be easily planned, independently built, and incorporated into the entire product ecosystem at a customer or product level.