Book Image

Designing Microservices Platforms with NATS

By : Chanaka Fernando
5 (1)
Book Image

Designing Microservices Platforms with NATS

5 (1)
By: Chanaka Fernando

Overview of this book

Building a scalable microservices platform that caters to business demands is critical to the success of that platform. In a microservices architecture, inter-service communication becomes a bottleneck when the platform scales. This book provides a reference architecture along with a practical example of how to implement it for building microservices-based platforms with NATS as the messaging backbone for inter-service communication. In Designing Microservices Platforms with NATS, you’ll learn how to build a scalable and manageable microservices platform with NATS. The book starts by introducing concepts relating to microservices architecture, inter-service communication, messaging backbones, and the basics of NATS messaging. You’ll be introduced to a reference architecture that uses these concepts to build a scalable microservices platform and guided through its implementation. Later, the book touches on important aspects of platform securing and monitoring with the help of the reference implementation. Finally, the book concludes with a chapter on best practices to follow when integrating with existing platforms and the future direction of microservices architecture and NATS messaging as a whole. By the end of this microservices book, you’ll have developed the skills to design and implement microservices platforms with NATS.
Table of Contents (15 chapters)
1
Section 1: The Basics of Microservices Architecture and NATS
5
Section 2: Building Microservices with NATS
11
Section 3: Best Practices and Future Developments

Breaking down a monolith into microservices

Let's try to understand the concepts of the microservice architecture with a practical example by decomposing a monolithic application into a set of microservices. We will be using a healthcare application for this purpose. The same application will be used throughout this book to demonstrate various concepts along the way.

Let's assume we are building an IT system for a hospital to increase the efficiency of the health services provided by the hospital to the community. In a typical hospital, many units exist, and each unit has one or more specific functionalities. Let's start with one particular unit, the outward patient department or OPD. In an OPD section, a few major functions are executed to provide services to people:

  • Patient registration
  • Patient inspection
  • Temporary treatment
  • Releasing the patient from the unit

We'll start with one unit of the hospital and eventually build an entire healthcare system with microservices as we complete this book. Given that there are only four main functions, the IT team at the hospital has developed one web application that covers all these different functional units. The current design is a simple web application with four different web pages, each of which contains a form to update the details captured at each stage with a simple login. Anyone with an account in this system can view the details of all four pages.

Figure 1.5 – Simple web application for the OPD unit of a hospital

Figure 1.5 – Simple web application for the OPD unit of a hospital

As depicted in the preceding diagram, the OPD web application is hosted in a web server (for example, Tomcat) and it uses a central database server to keep the data. This system works well, and users of this system are given a username and a password to access the system. Only authorized people can access the web application and it is hosted in a physical computing infrastructure inside the hospital.

Let's try to identify the challenges of this approach of building an application as a single unit or a monolith:

  • Adding new features and improving existing features is a tedious task that requires a total restart of the application, with possible downtimes.
  • The failure of one function can cause the entire application to be useless.
  • If one particular function needs more resources, the entire application needs to be scaled (vertically or horizontally).
  • Integrating with other systems is difficult since most of the functional logic is baked into the same service.
  • It contains large code bases that become complex and hard to manage.

As a result of these challenges, the overall efficiency of the system becomes low and the opportunity to serve more patients with new services becomes harder. Instead, let's try to break this monolithic application down into small microservices.

More often than not, the microservice architecture demands a change in the organizational IT culture, as well as the software architecture and tools. Most organizations follow the waterfall approach to building software products. It follows a sequential method where each step in the sequence depends on the previous step. These steps include design, implementation, testing, deployment, and support. This sort of model won't work well with the microservice architecture, which requires a team that consists of people from these various internal groups and can act as a single unit to release each microservice in an agile manner.

Figure 1.6 – Waterfall development culture

Figure 1.6 – Waterfall development culture

The preceding diagram depicts a typical organizational IT culture where different teams with different expertise (center of excellence or CoE teams) work sequentially to develop and manage the life cycle of a software application. This model poses several challenges, such as the following:

  • Longer product release cycles
  • Resistance to change causes a lack of frequent innovation
  • Friction between teams can cause delayed releases, missing features, and low-quality products
  • Higher risk of failure and uncertainty

This kind of organizational culture is not suitable for the highly demanding, innovation-driven enterprise platforms of today. Hence, it is necessary to reduce these boundaries and formulate truly agile teams before starting microservice-style development. Sometimes, it may be difficult to fully remove these boundaries at the beginning. But with time, the individuals and management will realize the advantages of the agile approach.

Figure 1.7 – Sprint-based agile development approach

Figure 1.7 – Sprint-based agile development approach

The preceding diagram depicts an approach where the development of microservices is done as sprints. These focus on certain aspects of the software development life cycle within a defined time frame. One clear difference in this approach, compared to the waterfall approach, is that the team consists of people from different CoE teams, and a virtual team is formed for the sprint's duration. The responsibility of delivering the expected outcome is on their shoulders.

Let's focus on the application architecture where we identified the challenges with the monolithic approach, which was followed by the OPD web application. Instead of having several functions baked into one single application, the microservice architecture suggests building separate microservices for each function and making them communicate over the network whenever they need to interact with each other.

In the existing design, a common database is used to share data among different functions. In a microservice architecture, it makes sense for each microservice to have its data store and if there is a need to share data across services, services can use messaging or a separate microservice with that common data store instead of directly accessing a shared data store. We can decompose the application into separate microservices, as depicted in the following diagram:

Figure 1.8 – OPD application with microservices

Figure 1.8 – OPD application with microservices

If you find the preceding diagram too complicated, I suggest that you read this book until the end. By doing so, you will realize that this complexity comes with many advantages that outweigh the complexity in most cases. As we can see, the OPD web application is divided into a set of independent microservices that act as a cohesive unit to provide the necessary functionality to the consumers. The following is a list of major changes we made to the architecture of the application:

  • Each function is implemented as a separate microservice
  • Each microservice has a datastore
  • A message broker is introduced for inter-service communication
  • The web interface is designed as a single-page application

Let's explore these changes in a bit more detail so that we understand the practicalities of the approach.

Business functions implemented as separate microservices

In the book Domain-Driven Design by Eric Evans, he explained the approaches to follow when deciding on the boundaries for each microservice with many practical examples. At the same time, he reiterated the fact that this is not straightforward and that it takes some practice to achieve higher levels of efficiency. In the OPD example, this is somewhat straightforward since the existing application has certain levels of functional isolation at the presentation layer (web pages), though this is not reflected in the implementation. As depicted in the preceding diagram, we have identified six different microservices to implement for the OPD application. Each service has a clearly defined scope of functionality, as mentioned here:

  • Registration microservice: This service is responsible for capturing the details of the patient who is visiting the OPD unit and generates a unique ID for the patient if they have not visited before. If the patient is already in the system, their visit details are updated and they are marked as a patient to inspect.
  • Inspection microservice: Once the registration is done, the patient is directed to the inspection unit, where a medical officer inspects the patient, updates the details of the inspection results, and provides their recommendation on the next step to take. The next step might involve temporary treatment, discharging the patient from the unit and moving them to the ward unit, or releasing the patient with medication.
  • Temporary treatment microservice: If the medical officer recommends a temporary treatment, the patient will be admitted to this unit and the required medication will be provided. This service will capture the medication provided against the patient ID and the frequency. After a certain time, the patient will be inspected again by the medical officer, who will decide on the next step.
  • Discharge microservice: Once the medical officer gives their final verdict on the patient, they will be discharged from the OPD unit to either a long-term treatment unit (ward) or their home. This service will capture the details of the discharge state and any treatment that needs to be provided in case the patient is sent back home.
  • Authentication microservice: This microservice is implemented to provide authentication and authorization to the application based on users and roles, as well as to protect the valuable patient details from unauthorized access. This service will store the user credentials, along with their roles, and grant access to the relevant microservice based on the user.
  • Common data microservice: Since the overall OPD unit acts as a single unit that acts on a given common patient, each microservice has to update one common data store for requirements, such as exposing a summary to the external applications. Instead of exposing each service to the external applications, having this sort of common microservice can help with such a function by providing a separate interface that is different from each microservice interface.

Once the microservice boundaries have been defined, the implementation can follow an agile approach where one or more microservices are implemented at the same time, depending on the availability of the resources. Once the interfaces have been defined, teams do not need to wait until another service has been fully implemented. The resources can rotate among teams, depending on their availability. We will discuss additional details regarding the deployment architecture and its implementation details later in this book.

Each microservice has a datastore

One of the main differences between the microservice-based approach and the monolithic approach we discussed in the previous sections is how data is handled. In the monolithic approach, there is a central data store (database) that stores the data related to each section of the OPD unit.

Whenever there is a need for data sharing, the application directly uses the database, and different functions access the same database (same table) without any control. This kind of approach can result in situations where data is corrupted due to an error in the implementation of a certain function and all the functions fail due to that. At the same time, finding the root cause would be hard since multiple components of the application access the same database or table. This kind of design will cause more problems when the applications have a higher load on the database, where all the parts of the application are affected due to the performance of one particular function.  

Due to these reasons and many others, the microservice architecture suggests following an approach where each microservice has a data store. At the same time, if there is a need to share a common database across multiple microservices, it recommends having a separate microservice that wraps the database and provides controlled access. If there is a need to share data between microservices, that will be done through an inter-service communication mechanism via messages. We will discuss how to deploy these local data stores, along with microservices, later in this book.

Message broker for inter-service communication

In the monolithic approach, each function runs within the same application runtime (for example, JVM for Java) and whenever there is a need to communicate between functions, it uses an in-memory call such as a method call or function invocation. This is much more reliable and faster since everything happens within the same computer.

The microservice architecture follows a different approach for inter-service communication since each microservice runs on separate runtime environments. Also, these runtime environments may run on different networked computers. Many approaches can be used for inter-service communication, and we will explore all those options in Chapter 2, Why Is Messaging Important in a Microservice Architecture, of this book. For this initial introduction, we will use the message broker-based approach. We will also be using this throughout this book, so we will discuss it in more detail later in this book.

At the beginning of this chapter, we discussed the different networking topologies and the evolution of distributed systems. There, we identified that having a mesh topology can complicate the overall system architecture and make it harder to maintain the system. Hence, we suggest using a message broker-based approach for inter-service communication throughout this book. The advantages of this approach are as follows:

  • A less complicated system
  • Loose coupling
  • Supports both synchronous and asynchronous communication
  • Easier to maintain
  • Supports the growth of the architecture with less complexity

We will discuss the advantages of using message brokers for inter-service communication throughout this book.

The web interface is designed as a single-page application (SPA)

As we discussed earlier in this chapter, the microservice style of application development involves making a lot of changes to the way engineers build applications. Traditional web applications are built in a manner where different sections of the application are developed as separate web pages and when the user needs to access a different section, the browser will load an entirely different web page, causing delays and a less optimal user experience.

Figure 1.9 – Multi-page OPD web application

Figure 1.9 – Multi-page OPD web application

As depicted in the preceding diagram, the user is accessing two pages of the web application. Each action triggers the following:

  • A request to the web server
  • The web server calling the database to retrieve data
  • The web server generating the HTML content based on the data
  • Responding to the web browser with generated HTML content

These traditional, multi-page applications can cause a significant performance impact to the user due to this multi-step process of loading a web page on the browser.

The concept of SPA addresses these issues and suggests an approach where the entire web application is designed as a single page that will be loaded to the browser at once. A page refresh won't occur when accessing different sections of the application, which will result in better performance and a better user experience.

Figure 1.10 – Single-page application with microservices

Figure 1.10 – Single-page application with microservices

While there is only a single page for the presentation layer of the application, different microservices implemented at the backend provide the required data to be displayed in the web frontend. The advantage of having separate microservices with an SPA is that users with different privileges will only get access to the authorized details. They will also get access to those details in the shortest possible time since no additional data loading happens.

The preceding diagram only depicts a couple of microservices for the sake of simplicity. The real implementation would interact with all the different microservices we discussed in the previous section.

So far, we've discussed the approach that can be followed when decomposing a monolithic application into a microservice architecture at a very high level while providing a few details on certain aspects. We will be continuing with this topic throughout this book, which means you will get the opportunity to learn more along the way.