Strangler Pattern: Monoliths to Microservices

Strangler Pattern: Monoliths to Microservices

Due to the numerous benefits that microservices architecture offers over monolithic architecture, several organizations now prefer to develop new applications using microservices or convert their existing monolithic systems to microservices architecture.

However, it can be an arduous task to transform a large-scale monolithic application to microservices from the ground up, requiring considerable architecture and development efforts and posing significant risks to the organization. Nevertheless, some established patterns and practices can help to mitigate these risks.

One such pattern is the Strangler pattern, which can be employed to transform a monolithic application into microservices.

Why do we need the Strangler Pattern?

Statista reports that more than 80% of organizations across the globe have adopted microservices, and around 17.5% are planning to migrate their existing architectures to microservices. However, building a new microservices-based application from scratch to replace an existing monolithic one is a complex and risky task that demands significant developer effort.

Some of the challenges involved in such a rewriting process include its time-consuming nature, unexpected issues that can take a lot of time to resolve, and the inability to develop new features while the migration process is underway. Additionally, there is uncertainty regarding the new system's performance until the development process is complete.

To overcome these risks and uncertainties, organizations can use the Strangler Pattern to gradually refactor their monolithic applications into microservices instead of rewriting everything from scratch. This approach reduces the need for a complete pause in new feature development and eliminates the need to wait for a fully functional application to start using it.

Instead, organizations can prioritize components and gradually refactor them to microservices while keeping both the monolith and microservices as part of a single application. This approach minimizes risks while providing a pathway for transitioning from monolithic to microservices architecture.

Given the need for the Strangler Pattern, it is essential to explore it in more detail and understand how it works.

Strangler Pattern - What is it? 🤔

The Strangler Pattern is a design pattern that enables the gradual refactoring of monolithic applications into microservices. This pattern facilitates the replacement of outdated components of the monolith with newer, improved ones while preserving the same functionality.

In the Strangler Pattern, a wrapper is utilized to integrate the microservices with the monolith. This wrapper plays a vital role in the design pattern since it serves as a connection between the monolith and microservices, directing incoming requests to the appropriate component for processing. Additionally, the wrapper acts as a safeguard, allowing organizations to switch back to the monolith if any issues arise with the new microservice.

To better grasp the concept, let's take a look at a real-world scenario that illustrates how the Strangler Pattern functions.

How does a Strangler Pattern work?

Refactoring a monolith into microservices using the Strangler Pattern involves three main steps:

  • Transform: In the first step, you must identify the primary components of the monolithic application. This involves identifying the boundaries between the current application and the new components being developed.

  • Coexist: Next, create a wrapper around the monolith to enable the new components to coexist with the existing application.

  • Eliminate: Finally, remove the monolith by replacing its parts with new components. However, before integrating each microservice into the system, you must ensure that it functions as intended.

For instance, let's consider an e-commerce application with a monolithic architecture, which includes features like user registration, product search, shopping cart, payment handling, and inventory management.

To help you better comprehend the migration process, we can divide it into five steps:

Deciding the Microservices

The initial step is to identify the monolith components individually along with their capabilities and limitations.

Next, you must determine the first microservice to migrate. There are various factors to consider when ordering the components for refactoring, which I have detailed in the next section.

For this instance, I have opted to migrate the product search functionality as the first component since it is not critical to the application's operation.

Moreover, it is essential to recognize the dependencies between the chosen component and others. In this example, the product search component is directly linked to the inventory and shopping cart components.

Creating the new microservices

As the second step, you must start creating the new microservice and move all the relevant business logic to the new microservice. Then, it would help if you created an API for the microservice, which will act as the wrapper to handle communications between the monolith and the microservice.

After implementing the microservice, you need to run both the monolith's component and the microservice in parallel to verify the functionality.

Handling the Databases

To ensure the smooth functioning of both the monolith and microservices, it's crucial to create a separate database while creating a new microservice. Furthermore, since both monolith and microservices will coexist for some time, it's essential to maintain synchronization between the primary and microservices databases.

To accomplish this, a technique such as read-through-write-through caching can be employed. In this scenario, the microservices database can be used as a cache until the product search component is removed from the monolith. When a user searches for a product, the microservices database is first queried, and if the data is not found, it can be fetched from the primary database.

Handling Requests

To minimize the impact of the new microservice, it is recommended to start by directing a small percentage of traffic to the new search service. This can be achieved using a load balancer.

Test & Repeat

Once you verify the functionality of the new microservice, you can remove the component in the monolith and route all the traffic to the microservice. Then, you must repeat these steps for each component and gradually convert the monolith into microservices.

How to select the component order for refactoring?

Another crucial challenge faced by developers while using the Strangler Pattern is selecting the correct order of components for refactoring. Although there are no defined hard and fast rules for this selection process, it is vital to determine which components should be migrated first to avoid unexpected delays.

Here are some factors that you should consider while deciding on the order of components:

  • Consider dependencies: Start with components that have fewer dependencies as they are likely to be easier to refactor.

  • Begin with low-risk components: Starting with low-risk components will minimize the impact on the system in case of early-stage issues and help build experience and confidence in the process.

  • Business needs: If a high-demand component requires scaling as soon as possible, you should start with that component to meet the business requirement.

  • Components with frequent changes: Refactor components that require frequent updates and deployments as microservices to manage separate deployment pipelines for those services.

  • User experience: Start with components that have a negligible impact on end-users to reduce disruptions and maintain a good user experience during the transition.

  • Integrations: Refactor components with minimal integration with other systems first.

In addition to these factors, several others can be taken into account. However, ultimately you should prioritize the most significant factors for your project and order the components for the refactoring process accordingly.

Ways to implement the Strangler Pattern

Unlike other design patterns, the Strangler Pattern has no language-specific libraries to help developers implement it. Instead, developers must use technologies, frameworks, and best practices to implement the Strangler Pattern.

Here are some of the most used approaches in implementing the Strangler Pattern:

  • Using ready-made platforms: Instead of building the infrastructure and platform architecture for microservices from the ground up, you can consider utilizing ready-made platforms that mostly do the heavy lifting. Examples include Amplication, Strapi, and AppWrite.

  • Using serverless: You can use AWS Lambda or Google Cloud Functions to implement independent functions triggered by specific events and eventually replace the parts of the monolith with them.

  • API gateways: An API gateway can be the wrapper when implementing the Strangler Pattern. It provides a unified interface and can be configured to redirect requests to the appropriate component. Examples of popular API gateways you can use include Amazon API Gateway, Kong, and Tyk.

  • Reverse proxies: A reverse proxy like Nginx can also be used as the wrapper in the Strangler Pattern.

  • Routing and load balancing: Routing and load balancing technologies can redirect traffic to the appropriate components. DNS-based routing and software-defined load balancers are popular options you can use.

  • Service discovery: You can get the help of the service discovery pattern to find the locations of new microservices.

  • Service mesh: You can use technologies like Istio or Linkerd to manage the communication between the new components.

These are only a subset of tools and technologies you can use to implement the Strangler Pattern. But make sure to only select a limited number of technologies from them based on your requirement. Otherwise, you will end up over-engineering the system.

Advantages of the Strangler Pattern 🙌

  • Incremental migration: Allows for an incremental migration from a monolith to microservices and reduces the risk associated with the migration process.

  • Reduced downtime: Ensures the system remains operational throughout the migration.

  • Improved resilience: Improve the system's resilience by ensuring that the monolith and microservices coexist and work together seamlessly.

  • Increased flexibility: Allow the organization to choose the best technology for each part of the system, rather than being forced to use a single technology for the entire system.

  • Better maintainability: Breaking down the monolith into microservices makes it easier to maintain the system over time.

Challenges of the Strangler Pattern 😟

  • Modularizing complexity: Breaking a monolith into components is difficult when the functionalities are tightly coupled.

  • Data compatibility: Sometimes, you may need to perform a data migration or transformation when the monolith and the microservices use different data formats.

  • Testing effort: Extensive testing is required to ensure the new microservices work as expected.

  • Skill requirements: Using the Strangler Pattern requires a high level of technical skill. Implementing the pattern in organizations that need more technical expertise can make it challenging.

Speeding up the Process⚡

In this article, we explored the benefits and obstacles of using the Strangler Pattern to streamline the conversion of monoliths to microservices.

Nevertheless, the conversion of a monolith with numerous components is still a daunting task, even with the Strangler Pattern. You must devise a microservices-oriented architecture and create each service from scratch.

One solution to this challenge is to devise a blueprint for each microservice and develop tools that can generate it. You might even consider developing a domain-specific language to standardize and reuse code and configuration best practices. However, this approach also adds complexity and cost to your architecture, as you must maintain and evolve these tools over time.

Did you find this article valuable?

Support Nitish Kumar by becoming a sponsor. Any amount is appreciated!