Read time: 5 minutes
Today I’ll go over one way to move from a monolith to microservices.
Many folks are eager to start reaping the benefits of microservices, usually after being stuck with a painful monolith for a while.
The problem is that it can be hard to tell where to start and how to get there.
Fortunately, there are multiple ways to move from a monolith to microservices, and today I’ll show you one that many teams have used successfully in the past.
Let’s dive in.
The Current Monolith
Let’s say we have a monolithic Match Making system that looks like this:
This system allows players to create and join game matches.
In simple terms, here’s how the system works today:
-
Players request to join a match via the /play endpoint in the Match Maker module REST API.
-
Match Maker creates or updates match requests in the Matches table of the database. A match that has at least 2 players is updated to the WaitingForGame state.
-
The Game Manager module polls the Matches table every 5 seconds to find new matches.
-
Once a match WaitingForGame is found, Game Manager starts provisioning a new game instance in the Game Server.
-
Once the game is ready, Game Manager stores the game details in the Games table and populates some of those details, like the server IP, in the Matches table.
Let’s see now one way to turn this monolith into microservices, step by step.
Step 1: Add a reverse proxy
The idea of the reverse proxy is to act as a gateway to the monolith.
The proxy will initially just forward all requests to the monolith but what’s important is that it will allow us to isolate the client.
That way the client will not be aware of the changes we’ll be making behind the proxy.
Step 2: Migrate the functionality
With the proxy in place, you can now start migrating the functionality from the monolith to microservices.
You can start by migrating the Match Maker module into a brand new microservice.
You should confirm that all Match Maker scenarios are working as expected in the new microservice.
Notice that you are not removing anything from the monolith yet, nor modifying the reverse proxy configuration.
You should also deploy the microservice to production, with no traffic yet, to confirm you are ready to fully rely on the microservice moving on.
Step 3: Redirect calls
Now you can reconfigure the proxy to redirect calls to the /play endpoint to the new microservice.
You can leave the original Match Maker module in the monolith for now.
That should allow you to quickly rollback to the monolith if something goes wrong by just changing the proxy configuration.
Step 4: Cleanup the monolith
After a few weeks or months of successfully running our first microservice in production, we can finally tear down the Match Maker module from the monolith.
In fact, we can also turn Game Manager into its own microservice, at which point the monolith can be completely removed.
At this point you can finally start reaping some of the benefits of microservices, but there is something very important we still need to tackle: the Database.
Step 5: Publish events
Microservices should never share a database because that would create a tight coupling between them.
So, we want to figure out a way for each microservice to work with their own database.
And, to get there the first thing to do is to not let Game Manager poll the Matches table anymore.
Should Match Maker expose a REST API for Game Manager to call?
Please don’t! That would be tight coupling as well and trigger a bunch of new issues.
Instead, we can update Match Maker to publish a WaitingForGame event into a message queue every time a match reaches the WaitingForGame state.
We can also update Game Manager to publish a GameCreated event any time a new game has completed provisioning.
Step 6: Consume events
With both microservices publishing events, we can now update them to also start consuming them.
So, any time a WaitingForGame event shows up in the queue, Game Manager will consume it and start working on game provisioning.
And, whenever Game Manager publishes the GameCreated event, Match Maker will consume it and update the match details in the Matches table.
This way Match Maker can now work exclusively with its Matches table and Game Manager with its Games table.
Just one more step to go.
Step 7: Split the database
There is no longer any reason to keep both the Matches and Games tables in the same database.
So, we can now split the database into two, one for each microservice.
Yes, easier said than done, and likely will involve a migration process in itself, but it’s totally worth it.
With each microservice owning their own DB, each microservice team is free to evolve their DB schema as needed without having to coordinate with other teams.
Mission accomplished!
Is it worth it?
First confirm that it is time for you to move to microservices.
After that, yes, totally worth it. With a microservices architecture, you will be able to:
- Onboard new devs quickly
- Always deliver on time
- Keep your customers delighted
- Stop wasting server resources
- Keep your developers happy
- Use new tech as needed
And that’s it for today.
I hope you enjoyed it.
Whenever you’re ready, there are 4 ways I can help you:
-
.NET Cloud Developer Bootcamp: Everything you need to build production ready .NET applications for the Azure cloud at scale.
-
All-Access Pass: A complete catalog of premium courses, with continuous access to new training and updates.
-
Patreon Community: Join for exclusive discounts on all my in-depth courses and access my Discord server for community support and discussions.
-
Promote yourself to 19,000+ subscribers by sponsoring this newsletter.