So you’re sitting on hundreds of thousands of lines of legacy C++. Oh, who are we trying to kid? It’s millions of lines of Vectran, a short-lived Fortran variant created by IBM in the ’70s. But hey, if it ain’t broke, right?
Except it is broken. Anytime someone tries to add a feature, the thing breaks. Even trying to fix bugs creates more bugs. But if you just don’t touch it, it keeps on working.
The problem is that innovation demands agility and velocity. All the cool companies that never had to worry about Y2K are outpacing your clunky old legacy software. Investors are demanding the next big thing. Customers are jumping ship in droves.
The good news is that you’re not alone. Believe it or not, even the cool kids have faced similar problems. Netflix, eBay, Amazon, Twitter, PayPal, and more didn’t start out with beautifully architected scalable code that was fast and agile.
In 2006, eBay did a presentation at the SD Forum [PDF] about its architecture. The company confessed to having built a monolithic 3.3-million-line C++ ISAPI DLL that compiled into a 150MB binary. eBay developers were hitting compiler limits on the number of methods per class, while being expected to add more 1,200 new features per year with 99.94 percent availability.
How did eBay overcome its overburdened legacy architecture? The same way PayPal, Twitter, Amazon, and Netflix did: by killing their application monolith. They re-architected their infrastructure using microservices, a technique that breaks large applications into lightweight apps that can be scaled horizontally.
Breaking down monoliths
Microservices segment functionality into separate applications that are loosely coupled by RESTful APIs. For example, eBay created different Java servlet applications that handled users, items, accounts, feedback, transactions, and more than 70 other elements back in 2006. Each of those logical functional applications is now considered a microservice. Now eBay probably runs hundreds of microservices.
Each of these microservices is self-contained. They do not share a data layer. Each one has its own database and load balancer. Isolation is a critical component of microservices architectures; different microservices require different scaling techniques. For example, some microservices might use relational databases whereas others might employ NoSQL databases.
Building applications this way increases the scalability of teams building applications. With monolithic code, you have one big team of people working on one big piece of code and stepping on each other’s feet all the time. The speed of development slows exponentially with the growth of the code monolith. With microservices architecture, apps are built by small, decentralized development teams that work and change microservices independently. This makes it easier to upgrade services and add functionality. Both the software and the development process become more agile.
For all these reasons, microservices have enjoyed increasing popularity. But every architecture has its strengths and weaknesses. Microservices architectures bring a whole new set of problems that are hard to tackle.
In this article, we’ll explore the pros and cons of microservices as we unpack this modern method of building applications. Then we’ll walk through how to build a microservices-based blogging application to show how microservices work in the real world. Finally, we’ll address some of the most frequent concerns about microservices and answer the biggest question: Should you be making use of microservices?
The answer to that last question may surprise you.
The pros and cons of microservices
Microservices philosophy tears down large monolithic applications with massive complex internal architectures into smaller, independently scalable applications. If you’re eBay, for example, you might expect that the user feedback microservice would be smaller and less complex than the bidding microservice.
When you think about it, why should those functionalities need to be built into a single application in the first place? In theory, at least, you can imagine they would live in separate application and data silos without major problems. For example, if the average auction received two bids, but only a quarter of all sales received feedback, the bidding service would be at least eight times as active as the feedback application at any time of day.
In that way, separating different functionality groups into separate applications makes intuitive sense. Yet the benefit of being able to build and scale different parts of your application indepen- dently comes with a whole new set of concerns—specifically around logging, monitoring, testing, and debugging your newly decentralized, loosely coupled application.
If there’s a bug, which microservice is responsible for it? The interdependencies between microservices can make that question maddeningly hard to answer. Microservices communicate with each other, generally through lightweight JSON REST APIs. Unlike their predecessors XML-RPC and SOAP, REST interfaces tend to be more loosely defined. These lighter-weight APIs are more flexible and easier to extend, but they also add a new interface that needs monitoring and may break or cause bugs.
In the old days with monolithic applications, you could add debugging hooks within the code and logically step through every execution layer to discover the problem areas. When you are dealing with a mesh of dozens or even hundreds of separate applications talking to each other with loosely defined APIs, you lose that luxury.
Nonetheless, with careful planning youcan overcome these difficulties. At the present moment, you have relatively few off-the-shelf microservices debugging tools to choose from. You will probably have to stitch together your own solutions based on other, partial situations out there. But when you architect around microservices philosophies, you gain hidden benefits, such as tying in with other new technologies such as PaaS, Docker, and Linux containers.
Microservices, containers, and PaaS
There is a common misconception floating around right now that to use microservices you need to use PaaS or Linux containers or something similar. It’s simply not true. You can use PaaS and Linux containers without microservices, and you can use microservices without PaaS or Linux containers. Neither requires the other.
But in many ways, they do complement each other well. PaaS environments, whether in the form of public clouds such as Heroku or private clouds such as Cloud Foundry or OpenShift, optimize for running many smaller applications. Portinga 3.3-million-line C++ application to a PaaS platform will never happen.
If you deconstruct your application into smaller, bite-sized applications that are each self-contained and scale independently, those bite-sized applications often end up being good candidates for a PaaS environment.
For that reason, thinking about adopting microservices architectures can help accelerate adoption of other technologies that might already be on your road map. Likewise, Linux containers are better suited for small, stateless applications than large monolithic ones.
After all, one of the biggest and most obvious differences between a virtual machine and a Linux container is the lack of state. Virtual machines can be configured to keep their state, whereas the architecture of Linux containers intrinsically throws out any differences from the base image. With Linux containers, you can mount stateful folders in them, but the container itself won’t change unless you commit the change.
The horizontal scaling philosophy of microservices architecture promotes the concept of share-nothing, stateless applications. That is, they do not store or modify the underlying file system. You can see why people conflate microservices with Linux containers: Neither retain their state.
Microservices offer a sound approach to application development, as long as you are aware of the problems and shortcomings. It’s not just another tech trend that will go away next season. It’s the way many of the biggest names in technology have tackled the problems of large-scale growth during the past 10 years.