In terms of software architecture and design, how do microservices “stack up” (pun intended) against middleware? I’m coming from Java, and it seems like as you move away from straight REST as an API, and abstract away different layers and connection parameters, at least in Java, you’ve almost come full circle back to some very old school ideas. We’ve come back to virtualization…wheras the JVM is already virtual.
In an agnostic way, you can, and I would argue the advantages to, abstracting a RESTful API to CORBA. Or, in a more java-centric way, JMS or MDB.
At one time EJB was a big deal in Java, then it was recognized to a bit of a cluster eff, but, now, are we back to the beginning?
Or, do microservices offer something which CORBA, or even better, MDB, lacks? When I read (TLDR) Martin Fowler explaining microservices, it strikes me as a good solution to a bad problem, if you will. Or rather, a closed minded approach which introduces a level of complexity only pushing the problem around. If the services truly are micro, and are numerous, then each has a dollar cost to run and maintain it.
Furthermore, if one microservice amongst many changes its API, then everything depending on that service breaks. It doesn’t seem loosely coupled, it seems the opposite of agile. Or am I misusing those words?
Of course, there are an indeterminate amount of choices between these extremes.
Shark versus Gorilla…go! (For the pedantic, that’s meant to be ironic, and isn’t my intention at all. The question is meant to be taken at face value. If the question can be improved, please do so, or comment and I’ll fix.)
Envision a multitude of microservices running in docker, all on one machine, talking to each other…madness. Difficult to maintain or admin, and next to impossible to ever change anything because any change will cascade and cause unforeseeable errors. How is it somehow better that these services are scattered across different machines? And, if they’re distributed, then surely some very, very old school techniques have solved, at least to a degree, distributed computing.
Why is horizontal scaling so prevalent, or at least desirable?
10
TL;DR. I have had the pleasure of drinking a lot of Microserver flavored Kool-Aid, so I can speak a bit to the reasons behind them.
Pros:
- Services know that their dependencies are stable and have had time to bake in
- Allow rolling deployments of new versions
- Allow components to be reverted without affecting higher layers.
Cons:
- You cannot use the new and shiny features of your dependencies.
- You can never break API backwards compatibility (or at least not for a many development cycles).
I think that you fundamentally misunderstand how a microservice architecture is supposed to work. The way it is supposed to be run is that every microservice (referred to from here on in as MS) has a rigid API that all of its clients agree upon. The MS is allowed to make any changes that it wants as long as the API is preserved. The MS can be thrown out and rewritten from scratch, as long as the API is preserved.
To aid in loose coupling, every MS depends on version n-1 of its dependencies. This allows for the current version of the service to be less stable and a bit more risky. It also allows versions to come out in waves. First 1 server is upgraded, then half, and finally the rest. If the current version ever develops any serious issues, the MS can be rolled back to a previous version with no loss of functionality in other layers.
If the API needs to be changed, it must be changed in a way that is backwards compatible.
2
Every software development technique we’ve ever invented has been about managing complexity somehow. A huge portion of them have been and continue to be about abstraction, encapsulation and loose coupling. Microservices are yet another way of doing those things, which is probably why it resembles a lot of older techniques at a high theoretical level, but that doesn’t make it any less useful or relevant.
Regarding loose coupling, I think you’ve misunderstood the goal a bit. If task A needs to call task B, there’s never going to be way to make A and B 100% decoupled. Never going to happen. What you can do is ensure that, if task B calls task C, then task C should never have to worry about changes to A. If these three tasks are all linked together in one big blob, passing structs to each other, then there’s a significant chance they’ll all have to change if any one of them does. But if all three are microservices, then you’re basically guaranteed that a change to A will only force B to update (unless it’s such a huge change to A’s core functionality that you probably should’ve made it a brand new service). This is especially true if all microservice updates are done in a backwards compatible way, which they should be.
Regarding the agile comment, I can tell you from personal experience that our microservice-y code plays far better with agile than our “linked into a big blob” code. In the latter, whenever someone fixes a bug in a low level function, he literally has to send the entire R&D department an e-mail saying “please relink your tasks or they’ll all crash on Friday”. We get a couple of these every week. If his code was in a microservice, we would all automagically benefit from the fix as soon as he deployed a new version.
I don’t fully understand the comment about COBRA and MDB, as they don’t seem to be software architectures but rather components of one; to my understanding they’re potential ways of defining your microservices’ messaging protocols and/or implementing said microservices, not in and of themselves alternatives to microservices.
3
How is it somehow better that these services are scattered across different machines?
Because of the cloud.
Done laughing yet? Seriously though – for many businesses, the biggest cost for software isn’t the software anymore. It’s the bandwidth, hardware, CDN costs, etc. Now that everyone has a mobile device, there’s just that much more traffic. And that will only get worse as your toaster gets its own internet connectivity.
So businesses are looking to manage those costs. Specifically, they’re trying to handle the business problem of “if this thing blows up, how can I serve millions of people getting/using my software – without paying ahead of time for the servers to serve millions of people getting/using my software?”.
Why is horizontal scaling so prevalent, or at least desirable?
Because it answers this (huge and increasing) business problem.
When you have a dozen users, you can toss all of the services on one box. This is good, since you only want to pay for one box. And you also don’t want to pay for changes to the app to split up the various services when your business scales. These days, you don’t have time to do that before the mob of customers lights your servers on fire anyways.
It’s also good because it allows you to juggle server allocations so that you can:
- use the most of the servers you have, leaving little to “waste”.
- measure the performance individual elements of your software.
- reduce deployment/down time caused by releases.
Having very granular deployments makes those two things easier/better (in addition to helping to enforce better separation of concerns).
3