Book Image

Microservices with Clojure

By : Anuj Kumar
Book Image

Microservices with Clojure

By: Anuj Kumar

Overview of this book

The microservice architecture is sweeping the world as the de facto pattern with which to design and build scalable, easy-tomaintain web applications. This book will teach you common patterns and practices, and will show you how to apply these using the Clojure programming language. This book will teach you the fundamental concepts of architectural design and RESTful communication, and show you patterns that provide manageable code that is supportable in development and at scale in production. We will provide you with examples of how to put these concepts and patterns into practice with Clojure. This book will explain and illustrate, with practical examples, how teams of all sizes can start solving problems with microservices. You will learn the importance of writing code that is asynchronous and non-blocking and how Pedestal helps us do this. Later, the book explains how to build Reactive microservices in Clojure that adhere to the principles underlying the Reactive Manifesto. We finish off by showing you various ways to monitor, test, and secure your microservices. By the end, you will be fully capable of setting up, modifying, and deploying a microservice with Clojure and Pedestal.
Table of Contents (18 chapters)
Title Page
Dedication
Packt Upsell
Contributors
Preface
Index

Monolithic applications to microservices


Most applications start as a monolith. Amazon (http://highscalability.com/amazon-architecture) started with a monolithic Perl (https://en.wikipedia.org/wiki/Perl) /C++ (https://en.wikipedia.org/wiki/C%2B%2B) application, and Twitter (http://highscalability.com/blog/2013/7/8/the-architecture-twitter-uses-to-deal-with-150m-active-users.html) started with a monolithic Rails (https://en.wikipedia.org/wiki/Ruby_on_Rails) application. Both organizations have not only gone through more than three generations of software architectural changes, but have also transformed their organizational structures over time. Today, all of them are running on microservices with teams organized around services that are developed, deployed, scaled, and monitored by the same team independently. They have mastered continuous integration and continuous delivery pipelines with automated deployment, scaling, and monitoring of services for real-time feedback to the team.

Identifying candidates for microservices

The top-most challenge in migrating from a monolithic application to microservices is to identify the right candidates for microservices. A well structured and modularized monolithic application already has well-defined boundaries (bounded contexts) that can help disintegrate the application into microservices. For example, the User, Orders, and Interest modules already have well-defined boundaries and are good candidates to create microservices for. If the application does not have well-defined boundaries, the first step is to refactor the existing application to create such bounded contexts for microservices. Each bounded context must be tied to a business capability for which a service can be created.

Another approach in identifying the right candidates for microservices is to look at the data access patterns and associated business logic. If the same database is being updated by multiple components of a monolithic application, then it makes sense to create a service for the primary component with associated business logic that manages the database and makes it accessible to other services via APIs. This process can be repeated until databases and the associated business logic are managed by one and only one service that has a small set of responsibilities, modeled around a business capability.

For example, a monolithic application consisting of User, Interest, and Orders components can be migrated into microservices by picking one component at a time and creating a microservice with an isolated database, as shown in the preceding diagram. To start with, first pick the one with the least dependency, the User module, and create the User Service service around it. All other components can now talk to this new User Service for User Management, including authentication, authorization, and getting user profiles. Next, pick the Orders module based on the least dependency logic, and create a service around it. Finally, pick the Interest module as it is dependent on both the User and Orders modules. Since we have the databases isolated, we can also swap out the database for Interest with maybe a graph database that is efficient to store and retrieve user interests due to its inherent capability of storing relationships as a graph.

Note

In addition to organizing your microservices around business capabilities and database access patterns, look for common areas, such as authentication, authorization, and notification, that can be perfected once as a service and can be leveraged by one or more microservices later.

Release cycle and the deployment process

Once a monolithic application is disintegrated into microservices, the next step is to deploy them into production. Monolithic application are mostly deployed as a single artifact (JARs, WARs, EXEs, and more) that are released after extensive testing by the quality assurance (QA) team. Typically, developers work on various components of the application and release versions for the QA team to pick and validate against the specification, as shown under the Org Structure of monolithic architecture in the following diagram. Each iteration may involve the addition or removal of features and bug fixes. The release goes through multiple developers (dev) and QA team iterations until the QA team flags off the release as stable. Once the QA team flags off the release, the released artifact is handed over to the IT ops team to deploy it in production. If there are any issues in production, the IT ops team asks the dev team to fix them. Once the issues are fixed, the dev team tags a new release for QA that again goes through the same dev-QA iterations before being marked as stable and eventually handed over to IT/ops. Due to this process, any release for a monolithic applications may easily take up to a month, often three months.

On the other hand, for microservices, teams are organized into groups that fully own a service. The team is responsible for not only developing the service, but also for putting together automated test cases that can test the entire service against each change submitted for the service. Since the service is to be tested in isolation for its features, it is faster to run entire test suites for the service for each change submitted by the developers. Additionally, the team itself creates deployable binaries often packaged into containers (https://en.wikipedia.org/wiki/Linux_containers), such as Docker (https://en.wikipedia.org/wiki/Docker_(software)), that are published to a central repository from where they can be automatically deployed into production by some well-known tools, such as Kubernetes (https://en.wikipedia.org/wiki/Kubernetes). The entire development to production timeline is cut short to days, often hours, as the entire deployment process is automated. We will learn more about deploying microservices in production and how to use these deployment tools in Part-4, the last part of this book.

There is a reason why a lot of microservice projects fail and only a few succeed. Migrating from a monolithic architecture to microservices must not only focus on identifying the bounded contexts, but also the organizational structure and deployment methodologies. Teams must be organized around services and not projects. Each team must own the service right from development to production. Since each team owns the responsibility for testing, validation, and deployment, the entire process should be automated and the organization must master it. Development and deployment cycles must be short with immediate feedback via fine-grained monitoring of the deployed microservices.

Note

Automation is key for any successful microservices project. Testing, deployment, and monitoring must be automated before moving microservices to production.