Istio: Part 3 – Microservices vs Monoliths

Microservices

In the first 2 articles for this series, I provide an introduction to what this series will be about and also give feedback on my time spent testing out the sample app on IBM Bluemix. We are slowly getting to the point where Istio will be discussed in detail, but we first need to ensure we have a good understanding of Microservices, Containerization and Kubernetes. This article introduces some of the core differences between Microservices and Monoliths.

Introduction to Microservices

Let’s kick things off with a formal definition:

Microservices is a variant of the SOA (service-oriented architecture) architectural style that structures an application as a collection of loosely coupled services – Wikipedia

You’ll notice the reference to SOA. Believe it or not, the idea of Microservices has been around since 1994. Back then it was coined SOA or “Service-oriented Architecture”. But, to save you from a boring detailed explanation of the past, Microservices is, in a nutshell, SOA 2.0 or SOA next. The strategy is to take a complex application that contains heavy amounts of code, design and business logic, and convert it into small, fine-grained services.

The Monolithic Application

To understand what constitutes a Monolith application, take a look at the following diagram:

Monolith Single Page App - Example Diagram

Figure 1: Monolith Single Page App

In this example, we have a Single Page Application that’s primarily made up of 3 CRUD Processes:

  • Purchase Requisitions
  • Credit Requests
  • Leave Requests

Each of these processes require Create, Read, Update and Delete functionality. They are also driven by rules and business processes, making them more complex than a typical Reminder or To Do app. Single Page Applications have been a favorite for modern web application development, providing users with a responsive and optimized interface. Now, not all SPAs are considered Monoliths. To this day I highly recommend a SPA strategy. The issue is how the design is put together.

It’s a Monolith Application because…

Using the example application above, we could easily call it a Monolith because:

  • All logic exists in 1 design

If you have 3 developers who are each responsible for a CRUD process, they’d have to carefully apply changes, bug fixes and enhancements to the design. If not done right, they risk code conflicts or worse, overwriting of someone else’s code. Sometimes developers even land up waiting for others to finish certain tasks before they can continue.

  • Duplication of functionality

This unfortunately happens a lot with multiple developers working on the same design. Each process requires functionality similar to the others. What happens is, functions and logic get created uniquely for each process. Then, later on in the development cycle, the team realize that a lot of the logic can be centralized and reused.

  • Client-side and Server-side communication happens natively

Because the application doesn’t have to look anywhere else for logic, most calls to the server-side happen locally and not via an API. If a separate application wanted to query one of the CRUD processes above, it would have to exist on the same server and platform. In other words, our application is silo’d from everything else.

  • Unnecessary scaling of application

In the example application above, let’s say only 1 of the CRUD processes gets used aggressively, while the other 2 are rarely used. To provide enough machine resources, you would need to scale the entire application.

 

These are just some of the reasons why we would call our application a Monolith. Trust me there are more, but I think i’ve made a good enough point? Next, we’re going to see what our application would look like if we developed it using a Microservice strategy.

The Microservice Alternative

A common misconception of a Microservice strategy is that the entire design needs to be converted in one go. This is not true at all. The beauty of Microservices is that small steps can be taken in phases, leading to the end goal of having a complete Microservice architecture in place. As an example, let’s divide our Monolith into 3 phases:

  • Phase 1: Separate Client-side from Server-side

To separate the UI and client-side design from the server-side logic is a perfect start. Even if you have no API endpoints for the client-side to connect to, depending on your application platform, you could still have the client-side separated, but keep it on the same platform/server. This way the calls would still happen locally. Obviously there are many application platforms out there and each one has their own way of doing things, but if you have to look carefully, I’m sure you would find a way to implement this kind of phase.

Microservices Phase 1 - Example Diagram

Figure 2: Microservices Phase 1 Conversion

  • Phase 2: Everything is an API

This is where things get a bit more involved, but pays off dividends in the end. Expose all the core functionality on the server-side as API endpoints. An example set of APIs for each process could be as easy and fulfilling the CRUD process flow:

  1. Saving new or updating existing records
  2. Deleting  1 or more records
  3. Fetching records based on certain conditions

You may have certain feature functions for each process that related to that specific process. For example, for the Leave Requests, you could have a function that checks available leave for an individual. Wouldn’t this be awesome as a consumable API not only for the current application, but for other applications as well?

Microservices Phase 2 - Example Diagram

Figure 3: Microservices Phase 2 Conversion

 

  • Phase 3: Separate CRUD Processes

Here’s where it starts getting fun. Now that each of the CRUD processes’ core functions are APIs, we can split the server-side logic for each of these processes into separate services. Using the example application above, you could now have 4 server-side runtimes:

  1. Core Server-side Runtime – Responsible for core functionality that gets used by all 3 CRUD processes
    1. Approver Roles
    2. Business Process Management
    3. Other Random Functionality
  2. Purchase Requisitions Runtime – Logic only relevant to Purchase Requisitions, but still available as web services
  3. Credit Requests Runtime – Logic only relevant to Credit Requests, but still available as web services
  4. Leave Requests Runtime – Logic only relevant to Leave Requests, but still available as web services

Even if at this point, some of the logic is still duplicated, you’ve ended up with 4 runtimes that can stand by themselves and easily communicate with each other using APIs. You are well on your way to implementing a Microservices architecture.

Microservices Phase 3 - Example Diagram

Figure 4: Microservices Phase 3 Conversion

Closing

In my next article, I will discuss the use of Containers and how they could be used to deploy our application to a cloud cluster like Kubernetes. Once that’s out the way, I’ll finally focus on Istio itself and the benefits it brings to the table.

Cheers for now
John

Leave a comment

Your email address will not be published. Required fields are marked *