The Evolution of Scalable Microservices
In this report, I will discuss strategies and techniques for building scalable and resilient microservices, working our way through the evolution of a microservices-based system.
Beginning with a monolithic application, we will refactor it, briefly land at the antipattern of single instance—not scalable or resilient—microliths (micro monoliths), before quickly moving on, and step by step work our way toward scalable and resilient microservices (microsystems).
Along the way, we will look at techniques from reactive systems, reactive programming, event-driven programming, events-first domain-driven design, event sourcing, command query responsibility segregation, and more.
We Can’t Make the Horse Faster
If I had asked people what they wanted, they would have said faster horses.
Today’s applications are deployed to everything from mobile devices to cloud-based clusters running thousands of multicore processors. Users have come to expect millisecond response times (latency) and close to 100 percent uptime. And, by “user,” I mean both humans and machines. Traditional architectures, tools, and products as such simply won’t cut it anymore. We need new solutions that are as different from monolithic systems as cars are from horses.
Figure P-1 sums up some of the changes that we have been through over the past 10 to 15 years.
To paraphrase Henry Ford’s classic quote: we can’t make the horse faster anymore; we need cars for where we are going.
So, it’s time to wake up, time to retire the monolith, and to decompose the system into manageable, discrete services that can be scaled individually, that can fail, be rolled out, and upgraded in isolation.
They have had many names over the years (DCOM, CORBA, EJBs, WebServices, etc.). Today, we call them microservices. We, as an industry, have gone full circle again. Fortunately, it is more of an upward spiral as we are getting a little bit better at it every time around.
We Need to Learn to Exploit Reality
Imagination is the only weapon in the war against reality.
Lewis Carroll, Alice in Wonderland
We have been spoiled by the once-believed-almighty monolith—with its single SQL database, in-process address space, and thread-per-request model—for far too long. It’s a fairytale world in which we could assume strong consistency, one single globally consistent “now” where we could comfortably forget our university classes on distributed systems.
Knock. Knock. Who’s There? Reality! We have been living in this illusion, far from reality.
We will look at microservices, not as tools to scale the organization and the development and release process (even though it’s one of the main reasons for adopting microservices), but from an architecture and design perspective, and put it in its true architectural context: distributed systems.
One of the major benefits of microservices-based architecture is that it gives us a set of tools to exploit reality, to create systems that closely mimic how the world works.
Don’t Just Drink the Kool-Aid
Everyone is talking about microservices in hype-cycle speak; they are reaching the peak of inflated expectations. It is very important to not just drink the Kool-Aid blindly. In computer science, it’s all about trade-offs, and microservices come with a cost. Microservices can do wonders for the development speed, time-to-market, and Continuous Delivery for a large organization, and it can provide a great foundation for building elastic and resilient systems that can take full advantage of the cloud.2 That said, it also can introduce unnecessary complexity and simply slow you down. In other words, do not apply microservices blindly. Think for yourself.