A long time ago in a galaxy far, far away, programmers used to build applications that were as fast as possible with the extremely expensive hardware that was available—no cloud computing, no multi-cores, just one CPU and some lines of code trying to run quickly enough to provide a decent user experience. And it worked… for a while. Though not every piece of code that got churned out was truly optimal, hardware was evolving so rapidly that most problems could be fixed simply by adding more processing power. Moore’s Law stated that processing power should double—and the cost of computers should halve—every two years, and for a while that held true. The result was that hardware got faster and faster and faster, consistently coming to the rescue of programs that might have otherwise run too slowly.
So, what gives? Why has the cloud seemingly failed to deliver on its promise of making processing power irrelevant and scalability a breeze? To answer that, we first have to talk about microservices.
Microservices, for the uninitiated, are essentially loosely coupled, independently deployable apps that are organized around specific business functions. Microservice architecture allows small teams to rapidly and easily deliver, test, and maintain small segments of a much larger system without risking the stability of the system in its entirety. In more traditional monolithic applications, all of your functionality resides in one code base, and changes to any piece of the application have the potential to impact functionality elsewhere—meaning that things often move slowly and require a lot of oversight. With microservice architecture, you essentially avoid these issues, resulting in a number of distinct benefits.
In theory, this is a great way to get the most of your cloud deployment. Microservices power easy deployment for scalable applications that take advantage of having essentially limitless processing capacity in the cloud—so what’s the catch?
Scalability. Now, we know what you’re thinking—the whole point of microservice architecture is to improve scalability, so why is scalability an issue? Simply put, scalability becomes a trap when it’s being used to solve performance issues that stem from poor application design. Moore’s law taught programmers to believe that when things weren’t running well, more processing power would eventually save the day. But that’s not really the case anymore: piling up instances after instances on a component that’s performing transactions too slowly isn’t going to speed it up. Why? Because the issue isn’t a lack of computing power, it’s the code itself. And though one problematic microservice won’t impact any other services on an architectural level, those discrete programs do have to work together to perform larger workflows. That means that not only will the user have to wait for this slow microservice to finish running its transaction, there will also be a bunch of other live microservice instances sitting idle and unused.
If this sounds like it runs contrary to the way that people talk about scalability, remember this: scaling works for managing loads. If a ton of people are requesting a specific service at the same time, you can scale up by running more instances to process those transactions all at once—but those extra instances don’t speed up each individual process. The only way you can make that happen is by writing an efficient program in the first place.
Let’s look at a real life example as an elucidation of this point: recently, I was working with a new system that was built using microservice architecture. One of its goals was to keep queries flat, which it sought to accomplish by doing all of the filtering, joining, and data ordering on the application side. The idea here was that application components can be scaled up easily, and database functions can’t—but there’s a crucial flaw in this logic: databases are much, much faster when it comes to fetching data than application-side functions are. Can you guess what that result was? That’s right—extremely slow transactions, with a high rate of bottlenecks. In this case, adding more instances to power the application-side code wasn’t helpful, because this code is slower than normal database functionality by its very nature. The goal was to prevent the database from becoming overloaded; they succeeded in that goal, but only at the expense of speed.
In the scenario we sketched out above, it took several code refactors to make the individual transactions perform well. Obviously, if your goal is to build and maintain apps more rapidly, lengthy rework is the last thing you want. This means that even when it comes to microservices, you really want to do it right the first time by building something that’s designed to run efficiently. If you can’t make that happen, you’re potentially doomed to slow run times no matter how much processing power you throw at a particular application.
So what’s the key to making that happen? Balance. You need to design applications in such a way that you can exploit strengths on every layer, and thereby address every task in the most performance-optimal way. Scaling can’t be used as a tool in your code or your design for an individual component, because what essentially doing is papering over inefficiencies that will come back to haunt you later. Especially if you’re working the principles of microservice architecture, the right design is the one that will perform just as efficiently with one instance running as with ten.
Keep in mind, to make microservices work, you need to hold true to the philosophy behind them. That means no program-coupling just to try and make things faster—because this jeopardizes that benefits that come from the discrete chunks of code to begin with. If you can keep all that in mind, you can build applications that scale seamlessly when there’s more load to deal with than usual, meaning that you can conduct critical business functions with confidence that your infrastructure is going to support you. Whether you’re trying to beef up an internal accounting tool so that it will maintain low latency during crunch time, or you’re building out client-facing search functionality for a database of products and you expect a lot of seasonality, if you start with microservices that are built out efficiently you can create something that’s truly scalable and will support changing load volumes across different business functions.
There’s nothing more exciting than new, game-changing technology—but as technologies evolve we have to evolve with them. The cloud promises virtually infinite scalability, but with the rise of microservices we’re learning that that’s only true if you take an extremely careful and conscientious approach to these tiny pieces of code. If you can’t deal with any performance issue in a small scale deployment, those performance issues aren’t going to go away in larger scale environments with more processing power—meaning that your operational efficiency, and thus your health as a business, is potentially at risk. This might sound like a lot to grapple with, and in a way it is, but if you can use the right approach, with the right tools and techniques, it can be a game-changer for the performance of applications, and you can avoid the scalability trap.
Intertec specializes in building and supporting custom software for its diverse clients. Our experienced team of interdisciplinary professionals have experience at all stages of the software development lifecycle. Click here to learn more. Prefer a personal consultation? Go ahead and schedule a meeting with us here!