How to Migrate a Java Monolith to Microservices
Microservices help us build, scale, and deploy software faster. Here's how to migrate your monolith, without losing your mind.
Build fast or die.
That’s the rule in software. And when I worked as a consultant, I saw the struggle for speed first hand.
I worked with a global bank that was building a credit approval application. It was massive – a mix of tens of services to ensure you were worthy of their APR.
But one day, their lead developer pulled me to the side and said,
“I’m afraid to make changes to our app. Because I know that something will break”
If he’s afraid to make changes, how fast do you think they’ll go?
Why do we use microservices?
Monoliths are large applications that are deployed as a single unit. They aren’t all bad, but as applications grow, monoliths become a nightmare to change. Development slows.
That’s why we use microservices.
Microservices help us build software fast. They are small services that we can build, change and scale quickly. And to get this speed, we can break down our monolith into a set of microservices.
But there are challenges on this journey.
How do we migrate a monolith to a microservices?
The most important part of a migration is to remember the goal. The “why” will dictate how we go about our migration. For us, it’s the need for speed.
To break our monolith into microservices, we’ll need to answer three questions:
- Which applications should we migrate first?
- How do we migrate our applications to microservices?
- How will we build, run, and manage these new microservices?
Which applications should we migrate first?
Not everything needs to be a microservice. To choose a good candidate application to migrate, we’ll try to maximize benefit and minimize risk. Think ROI. Here are signs of a good candidate.
Sign #1: The application changes frequently
This helps us get the most value of moving to microservices (and reduces most slowdown). Every time we make a change service, we’ll reap the speed benefits of our migration.
Sign #2: The application requires a low LOE to migrate
This may seem contrary to the first sign. But, monolithic applications that use modern runtimes or have well-defined boundaries require less refactoring and can be great candidates.
Sign #3: The application has few other ones depending on it
Avoid migrating a core application first. You’ll already be figuring how to build, deploy, and orchestrate new services. You don’t want to do that while getting tangled in a web of dependencies.
Pro Tip: Use Application Migration Toolkit
What if we could visualize your entire application inventory, run a code level analysis and assess the best candidates for migration? That’s what Migration Toolkit does. If you only do one thing, run this.
How do we migrate our application to microservices?
Note: I talk a lot about containers in the next sections. Microservices aren’t containers, but they’re a great way to deploy them.
Migrations are best done in stages. When teams try it in one go, it usually ends in frustration and scrapping the whole effort. For Java applications, we recommend three steps.
Step 1: Migrate to a modern application server
To make your migration efforts easier, move to an application server that is:
- Supported. Because, production.
- Conforms to open standards. Being locked in slows your ability to move fast. I’m looking at you, WebLogic and WebSphere.
- Can easily run on a container platform. This will help with future modernization efforts.
Full disclaimer: I work for Red Hat. But I’ll offer a shameless plug to JBoss EAP. It’s a lightweight, open source app server that meets all of the above criteria.
Pro Tip: The Migration Toolkit can give you a source level analysis of what needs to change if you’ve moving.
Step 2: Run your monolith on a container platform
If you did step one, you’ll be able to easily deploy your JBoss EAP application to a container platform. This isn’t our final destination, but running a monolith on a container platform has some speed benefits like:
- Automatic Scaling,
- Zero Downtime Deployments
Pro Tip: For now, leave your existing database intact and connected to the monolith
Step 3: Break apart your monolith
This could be an article all on its own. Now that our app is on a container platform, we’ll start to break apart our monolith. Here are a few tips when creating microservices.
Start at the edge first. Similar to sign #3, start with services that don’t have a ton of dependencies.
Think capability, not code. Break things out in terms of business function. This helps us deploy independently, move fast, and it’s key to arranging teams that can manage end-to-end delivery.
Don't forget the data. To get full benefits of speed, each service should have it’s own datastore. You can expose the data for other services through an API or replicate it in the microservice's database.
Pro Tip: Use messaging queue like AMQ to communicate with older apps without having to make drastic changes.
How will we build, run and manage our microservices?
To effectively build and run our new microservices, we’ll need a new runtime and a platform.
Container Native Java
You’ve probably realized that Java EE wasn’t built with microservices in mind. Loading a fat JVM is the opposite of “micro”. So we’ll need a runtime that can run well in a container. Enter Quarkus.
(Disclaimer: Quarkus is a RedHat brainchild)
It’s a container native java stack that helps developers go freaky fast. It’s the best part of Java, optimized for speed. You also may use other runtimes for different services:
- NodeJS / Angular - for web application frontend
- Vertx - building reactive microservices & real-time apps
Microservices help us go fast. But we have some new problems like:
- Deployment - How do we build & deploy five services instead of one?
- Orchestration - How do we manage hundreds of tiny microservices running?
- Communication - How will our services discover each other and communicate?
It's a waste of time to build this ourselves. Our best bet is to use a container platform to do all this for us. Like…OpenShift
OpenShift automates deployment, orchestration, and service discovery for microservices. And it runs anywhere. So when your CTO mandates that you’re going to Azure, you don’t have to change how you work.
Migrations can be a lot of work, but you can make your life easier.
- Do your migration in stages. Use the Migration Toolkit to assess your portfolio and see where to start.
- Build Good Microservices. Start at the edge, focus on business function, and don’t forget the data.
- Use container runtimes and platforms
Monoliths slow development, but microservices help us build software fast. They are small services that we can build, scale, and deploy quickly.
To break down your monolith, look for signs of candidates, migrate in stages, and choose a good runtime and platform for your services.
Project Code & Links
- Application Migration Toolkit
- How to break a Monolith to Microservices
- The Path to Cloud-Native Applications
- Application Modernization Patterns
- 5 Design Principles for Microservices