Everything old is new again: Microservices
blogs.dxc.technology
blogs.dxc.technology
What made "Service-orientated-architecture" stand out in the 90's and 2000's was standardized communication protocols. It made integrating across teams, and even across companies easier than it's ever been before.
But there were no best practices around service architecture. Sure, methods were decoupled by responsibility (maybe). But when companies thought about their "Web Service" strategy that meant putting up ONE service exposed to the world, and moving on.
Internally, "SOA" meant 1-5 services for a mid-sized shop.
This worked for a while until it didn't. First, the services became monoliths of conflicting responsibilities, then the mobile revolution and big data led to scalability challenges that the era of SOA never had to consider.
THAT is what microservices promised to solve. By being brutal with decomposing and decoupling your concerns you could scale each intelligently and independently. Containers are just an implementation detail, and weren't around yet when Microservices first made their impact.
Of course, plenty of people don't get this. They think of microservices as just another buzzword. So, it's been ruined like "agile" has, and you hear companies about their "Microservice architecture", when really all they've done is migrated their backend to node.js and moved to the cloud.
Shame. It's a good idea a lot of the time (and sometimes it isn't, as with all good ideas).
In my experience it's exactly the opposite that has happened. I see microservices being abused all the time, just because someone read a blog and thought they were cool. The same thing happened with SOA by the way.
We just switched to SVN. The migration was an easy < one day job, a few weeks of pain with some developers grumbling that it was too complex and then everyone was (mostly) happy that we no longer had to hunt down the consultant who had locked a particularly critical file and was now out of the office the rest of the week.
Also, why SVN? That seems an antiquated choice at this point.
Although a couple of years ago I did have a job where they used it, but I quit after 2 months. For some reason a couple of the Devs would constantly check in blank commits. Not sure if that was a product of VSS or because the Devs were awful (part of the many reasons I left so quickly).
It's not quite as bad any more, but still terrible when compared to Git or SVN.
I’m a big fan of vanilla tooling. Complex build, version control, etc gets no love and ends up ten years later as a big mess that no one understands or wants to support.
(I wasn't around in the SOA era)
In reality the definition of both was always fairly fuzzy.
There are a lot of advantages to having a monolith, especially in statically typed languages.
Every extra service you add is costly, it involves setup, build steps that can break, extra things to monitor, more complex development environment, less flexibility, harder to redesign, harder to fix flaws in the original architecture, etc.
Deploying an extra service to a kubernetes cluster, for example, is neither costly nor prone to breaking nor harder to monitor, etc.
I think the best practice nowadays is for a small startup to first write a monolith and then later split it out into microservices when they're ready.
There's always something that can break. More parts, more breakdowns. The services have to communicate, those communication channels are extra points of failure. What happens when one service inadvertently passes along something another one can't decode properly?
Ooops, wasn't expecting unicode! Ooops, wasn't expecting a long int! Oops, the JSON encoder we used in this service spits out stuff the JSON decoder in this one hates! Ooops, we upgraded a package in this service, but not that one! And on, and on.
And when something does inevitably break in the chain, there's the extra cost in debugging of figuring out which bit actually broke.
But here's the dirty secret: if you have a load balancer in front of your application, you already have a way to send requests for feature X to a separate pool of machines if that feature is a hot spot for you currently--and unless your application hits some really degenerate cases your base RAM load Simply Should Not be that high for your application in the first place, making the marginal cost and machine sizing floor less of an issue.
There are benefits to microservices in some environments, chiefly to reflect your org chart when your human protocols are breaking down. They tend to be marginal, and whether they outstrip the increased overhead of dealing with more moving parts (whether in your code or not; I quite like k8s but I still wouldn't want somebody less comfortable with it than I am running it in production, and plenty of those folks do!) is in many ways up in the air.
If your application is composed of single-purpose modules, which are well documented, which have clean public interfaces, which are instrumented for monitoring, which can be scaled by using a load-balancing message router of some kind... and it works well, who cares whether you call it micro-services, Web Services, SOA, or FactoryFactory-Producer/Consumer Ecosystem?
This may be hard to plan out from the beginning, but if all is basically sound, you may be able to reduce that number later. (E.g. when a module is called only by one other module, and there's no requirement for them to scale independently, maybe they should be one module.)
Most development doesn't happen in a "we know exactly where we're going" way.
This all sounds like some perfect, waterfall development cycle, everything's designed on paper in UML and the code is then written to spec without any changes, no requirements change, no interfaces change.
That model of development simply doesn't exist in the real world.
Your profile and blog say you're a sysadmin, do micro-services keep you in a job ;) It's one thing to make a bunch of micro-services as a sysadmin. It's quite another to base an ever growing and mutating production code base around them that actually has no clear path to success and an only vague understanding of future requirements.
We keep development and operations staff tied closely together as a team, and have done since well before "devops" was coined.
I'm on the architecture side so am bearing the brunt of the complexity but the senior and especially mid level developers who have code open 7.8 hours a day say the few things we do that have real microservices are the easiest to debug and work on. The monolithic apps take longer to get less done.
Agreed though that it certainly adds complexity on the admin/arch/ops side.
Microservice: a->async->serialization->network->serialization->scheduling->b
A monolith is extremely simple to traverse with a debugger, a microservice is not. I can make a dozen jumps over/into/out in less time than it would take me to open Fiddler or man tcpdump.
I have heard that some companies have tooling that makes the microservices debugging situation tolerable or sometimes even better than monolith (e.g. writing tests for you by snooping the network layer), but I have yet to play with any. Do you have recommendations?
It may be worthwhile for really complex and "business vice separated" services to be written as micro services because it gives you clear separation of concerns. But, in reality, to often you see a single logical service getting implemented with a lot of (N/W + serialization + management) costs unnecessarily just because it is cool to say that you did micro services.
My thumb rule is : If you don't foresee different teams of devs working on these different services, then you're better off leaving it as a monolith and scaling it as a whole application instead.
Basically having separate teams work on one code base with one deployment cycle can sometimes be really tough. And sometimes you can get a big win by splitting up this service so multiple teams can each have their own service to focus on.
This whole team of one developer supporting 8 microservices seems ludicrious to me.
I tend to like the idea of the 2 pizzas rule from Jeff Bezos.
Having a small team (let say under 10 people) manage a service end to end (from spec to code to production) can be really efficient.
On large code bases/large products, this can help a lot, offsetting the cost of a more complex architecture.
However in a microservice architecture, the APIs between services is critical. It's a contract between services, and it should be clearly stated, you cannot go berserk every other day and change it. You also need to establish clear rules about versioning, deprecation and end of life of said APIs.
(by the way, it would be nice if we had a standard to negotiate API versions, for example stating that a rest API must always have a /version which lists the available versions, if some versions are deprecated and when they will be EOLed).
You won't just jam another getter in that Singleton if that Singleton is in another process.
If you're not running in High Availability, and can tolerate one copy of everything, then monolithic probably makes more sense. Glue it all together and roll out improvements across all the parts at once.
And frankly, for the 95% and probably the 99% case, running a copy of each monolithic application its own auto-scaling group is probably significantly less work and less hair-pulling than the chasing the microservice dragon.
I'll argue that if you're building something, you should probably build it as a monolith, with the exception of some well-defined services (like authentication & authorisation). Once you've got version 1 built, then you know enough about the problem that you're ready to consider breaking stuff off into microservices (this is why auth^2 make sense to break off from the get-go: they're pretty well-understood at this point, so we all should know how to handle them).
Premature microservicement is the root of much evil. Trying to break things up into services before you actually understand the problem will only lead to tears & suffering.
Really depends on how they were written and how they were maintained.
>then the mobile revolution and big data led to scalability challenges that the era of SOA never had to consider.
Can you describe this in more detail?
Yep. This is the first concept he misses.
"They think of microservices as just another buzzword. "
And this is the second one.
What he's describing as SOA doesn't match what I've seen. Even your 1-5 services example is rare. It was mostly taking a buzzword, loading up on some tooling, and cranking WSDLs. You could end up with dozens of those little rascals right out of the starting gate. (It should have been 1-5, agreed. I just never saw it work like that in shops of any significant size)
http://harmful.cat-v.org/software/xml/soap/simple
Maybe SOAP wasn't the entirety of SOA, but back then it was a big part of it.
I agree the term "microservices" has been ruined by those who came in with a very specific agenda. When I was at Timeout.com, in 2013, I used the phrase "an architecture of small apps":
http://www.smashcompany.com/technology/an-architecture-of-sm...
It was a few months later, when Martin Fowler wrote his essay about it, that I first heard the term "microservices". When I read his essay, I assumed he was talking about the same thing that I was talking about. But I later found that the people promoting microservices defined it entirely in terms of HTTP, so I've gone back to talking about "an architecture of small apps" when I am talking about small apps that talk to each other with something other than HTTP, such as this kind of architecture:
http://matthiasnehlsen.com/blog/2014/11/07/Building-Systems-...
In that example, Mattias Nehlsen builds a system where the communication is via Redis.
Well, SOAP and Wiz-Dull.
Many of the robotics platforms in common use (e.g., ROS) consist of independent, single-responsibility services that communicate over a shared message bus using a protocol that's not HTTP.
But for enterprise apps, it's 2018. Other protocols? What other protocols? You should be using HTTP/2. It can MUX multiple streams over the same connection. FINALLY! At long last! We're no longer limited to a single concurrent stream!
REST lost that.
I think GraphQL has it back again. Any GraphQL people want to comment?
If you share something, you create a dependency; and that dependency needs to be managed both technically and domain-wise. Group X now has to depend on Group Y's decisions if they both use/share service Z. If X and Y don't buy off on a common dependency on Z, they get frustrated and blame devs and the other service users.
Stored procedures and SQL allow data/service sharing with less code anyhow.
Although frankly I have to admit when I first heard about the "newest" trend in "static websites" I got a bit flabbergasted.
Most changes over time are evolutionary vs. revolutionary. This often means at an abstract level, new things look very similar to old things because they are. But, there is change (sometimes minor) that makes the new thing new. That minor change can also be the difference between something being used or going away into history.
Then they realized that they needed some type of way to validate the JSON so they introduced JSON schema.
Then they realized that they needed some method to make a REST Api discoverable so they added the Swagger protocol (OpenAI). Now we are right back to being as complicated as SOAP.
WSDL is the ultimate api :) it would make my day to see the wsdl comeback of 2018
But since they provided WSDL before, their "REST" APIs now come with WADL files that offer zero value to anyone. Swagger would be a massive step up from that.
At least with current JSON and REST API I stand a good chance of experimenting using just an editor and curl - good luck trying that with SOAP.
REST is getting there.
My experiences with SOAP were that 99% of the time it was fine - but those other 1% seems to take the other 99% of my time... ;-)
In many cases, I'll simply formulate xml requests myself and use a generic http request client because the implementation ended up being simpler & easier to maintain than all the confusing hacks I had to do to make zeep or suds (the most popular SOAP clients implemented in python) function properly.
string DoStuff(string params)
Where the response and params are strings containing XML documents :-)Which is silly, because REST is discoverable by definition, since you should be using hypermedia. And if your API is not discoverable, that's a good sign your service is not actually REST.
That's pretty much what I said! Web frameworks don't help you at all in this regard, which is why REST is unncessarily difficult to implement. Most web frameworks give you just enough for HTTP-based RPC.
As for the nightmare of REST, the real question is whether this difficult is intrinsic, or merely a product of immature tooling and poor understanding. No web framework I've seen, apart from the Waterken server, actually helps you achieve REST. They're largely all HTTP-based RPC frameworks.
This is not necessary in many languages that centre around domain objects. The validation is done automatically when the JSON gets mapped back to the object. It's far better than JSON schema anyway since you can enforce whatever custom validation you like.
> Then they realized that they needed some method to make a REST Api discoverable
But it doesn't have to be discoverable. And if you do want it then you could write the documentation by hand or expose a simple REST index endpoint.
> Now we are right back to being as complicated as SOAP.
You chose to make it complicated though.
Like all documentation written by hand, it rapidly gets out of date with the actual implementation if you're not careful.
Also tools can automatically create proxy classes from WSDL's and now Swagger endpoints.
IMO, the value of JSON Schema isn't that you have no validation that exists outside of JSON Schema, the value is that you can front load a TON of the validation into it, and share that vocabulary between your services. If you publish a JSON Schema about your endpoint, I can read that or feed it into tooling to produce a form to consume it. As someone working on the Elixir JSON Schema lib currently, the places where we COULDN'T express the validation with JSON Schema were often more interesting.
For one, Swagger is for humans not machines to consume. At it's core it is a way to standardize documentation that can be easily displayed to humans. WSDL is not only used by humans but also by client and server apps.
REST APIs themselves if done right though hypermedia can be self-documenting and require no download of large spec files to use it.
SOAP also suppers from a number of quirks. One for example, that order often matters. Yes you can write a WSDL that doesn't require order but nothing is worse than having a bug because <price> has to appear after <token> but before <expirationMonth> and any other order throws anon-specific validation error. Yes, I know there are tools that can help with this but I have never felt compelled to download a tool for REST. Curl does just fine for me. And to top it off a lot of the best SOAP tools are Windows only.
What I think you really should be pointing at is RPC (of which SOAP is a terrible no good implementation of). RPC indeed offers some benefits over REST and can even be simpler. At the expense of losing the discover and hypermedia aspects of REST if done right.
For one, Swagger is for humans not machines to consume. At it's core it is a way to standardize documentation that can be easily displayed to humans.
c# - https://github.com/Azure/autorest
Java - https://github.com/swagger-api/swagger-parser/blob/master/RE...
And basically everything else.
https://github.com/swagger-api/swagger-codegen/blob/master/R...
I am not aware of any code generators that read the swagger file every single API call and use that as if it were the code.
Re: statefulness ("order matters"): there are intrinsical stateful processes that aren't represented adequately by a REST service. Think of a basic "Purchase Order" resource representing purchased items on an e-commerce website. You generally can't add and delete line items freely once you have placed your order, but you may cancel individual items (unless they're already physically on your way), you may RMA items, etc. Representing this as a flat "Purchase Order" resource with GET, POST, DELETE, PUT primitives is useless as it isn't telling your web shop front-end developers what actions are available at any one time.
As a consultant who has talked at conferences on APIs and is brought in to explicitly fix these kind of issues I have seen a lot of this too but correct REST APIs do exist. I know because my team builds them.
You're experience is anecdotal and as is mine. But just because a lot of people assume REST is something it isn't doesn't mean REST is inferior to SOAP.
> Re: statefulness ("order matters")
My order matters comment had nothing to do with statefulness. I mean in the XML. In SOP this might work:
<order>
<token>ABC</token>
<price>19.95</price>
</order>
But this will fail: <order>
<price>19.95</price>
<token>ABC</token>
</order>
Why the heck does the order of keys in my object make the API fail!?Granted that is not a limitation of SOAP but more XML schemas in general. Json is more likely to be order of values agnostic.
But to play devil's advocate I can see the argument where if you are using SOAP to make multiple RPC calls in the same envelope than order is important.
Moreover, you could design your XML Schema such that both variants are accepted (using XSD "all-groups"), though typically record-like data structures are indeed described using XSD sequences which would cause the issue you mentioned. Again I agree XML/XSD isn't a great payload/schema mechanism for data structures such as maps; after all SGML/XML was invented for encoding text. It's being used because it was the first mechanism on the scene, and it continues to be used because it's still much more capable and mature/established in terms of data validation than anything JSON, especially for protocols used in communication with external partners/banks/authorities.
Except you can ignore the schema and swagger and have it just be simple, if that's all you need.
The biggest problem with SOAP is that it is too easy for the service provider to just dump their internal data structures without any thought to how it should be serialized for people using the data. XML is Particularly nasty in this regard, because it doesn't map well to the data primitives of most dynamic languages.
That said, I usually just treat SOAP APIs as if they were REST. By writing a class, and some wrapper methods for the parts I need. Instead of trying to consume the WSDL and use it the way they envisioned I would. Then again, if Python had better SOAP support I probably wouldn't even do that.
Both of these are wrong.
A SOA service of yore would be much lighter (in CPU, if not memory) than a microservice of today. Heck, it had to be -- in the 90s they couldn't afford to run a JS runtime to power their service. It was either C++ or Java.
The protocols were also lighter, then, not now. Except if the author means simpler and easier to work with. Else, CORBA or DCOC are lighter than serializing to JSON and back.
By the way, Server Side JS was a thing in the 90s, though little used. On the other hand, Perl was quite common on websites, despite being much slower than C/C++.
The early days of running a cgi script for every request had awful performance, caused by the overhead of loading and compiling the Perl code before executing it. But there were ways to avoid that by pre-loading the code. One way was to use Mod_Perl on Apache, for example. I wrote a number of services that way, and also wrote my own pure-Perl standalone http server that could pre-load an entire web application.
The other key factor was to use canonical expressions when writing your Perl code. There was always "more than one way to do it", but there were only a few ways that the compiler would recognize and use optimized functions for. Once you learned to take advantage of that, you could get your code running mostly in hand-written C functions. It wasn't as fast as native C because of the way Perl variables were represented, but it could be pretty close.
As other have pointed out he's ignoring key failings of SOA and critical differences between SOA and microservices.
Overall I like the article but I think he's misstating a few key things.
And maybe a nitpick but:
> It lends itself to the Continuous Integration/Continuous Deployment (CI/CD) model of developing large, complex applications.
Really? Because I thought CICD was the standard way to deploy any application more complex than a spike or proof of concept (which probably doesn't need to be deployed anyway).
Can you describe the fundamental differences?
A few smart non-graybeards eventually play around with $OLD_THING enough that they actually stumble upon the original definition of it, but don't realize that they are really just rediscovering the original definition. So of course they (re)name their discovery as the next $NEW_THING. Then cue the graybeards.
SOA is really just object oriented programming.
Microservices is really just object oriented programming.
Object oriented programming is really just dependency management.
And then people running around screaming SOA, MICROSERVICES, JSON and I like "You don't say? o_O?"
EDIT: spelling
(I am basing myself on just a superficial interest for MS so I might be wrong - here is what I am talking about: http://blog.christianposta.com/microservices/the-hardest-par...)
If this is correct, than no, Microservices are really not "just like SOA".
(If I am wrong, please correct me - I am here to learn).
I am in a team now that is just started using to use microservices. And I am noticing that we are stuck on a lot of DB changes we want to make because there are various applications accessing the same tables. So now we are getting into the habit of constraining back-end data stores (tables and collections) to just one microservice because we feel the pain of not doing that now.
There's no "data layer" that is managed outside the microservice. It _is_ a microservice.
That's one of the reasons Google uses a monorepo: any microservice can easily import a database instance and start using it as part of it's structure.
That said, there is nothing "micro" about most microservices I've come across over the years. They're "miniservices" at best.
Long an short of it is the ESB is an anti-pattern, always has been and SOA and microservices are the same thing.
It just seemed weird to me to leave that out.
ESB simply add more complexity in the middle that needs yet another team to manage.
Enterprise Service Bus was coined by Progress/Sonic Software for their middleware product around 2002
Service Oriented Architecture as a term to describe an enterprise architecture around web services was only used after SOAP became a thing in 1999
In the end SOA just had too much overhead, rules, and protocols. I remember seeing what these guys were doing with SOA and I would just ignore it and create REST services with JSON. We were able to get stuff in production. Eventually I found out that what we were doing was part of a movement called microservices and then started following and learning what other folks were doing.
On all the code bases I saw, I never told myself (micro) services are helpful, I will redo that. And if I had to rewrite any of them, I would use a single 'service' that can do everything. IMHO it's more sane to optimize for the developer instead of whatever micro-services try to optimize.
http://rvirding.blogspot.com/2008/01/virdings-first-rule-of-...
I do not agree with this at all. I think one of the biggest problems microservices face is the over-application of pre-existing paradigms. The failures I see are big object models, large frameworks, dependency on shared resources, complexity in the service, and so forth -- all signs of 90s and 00s thinking moving over to microservices.
I agree that everything old is new again. I'd suggest you need to go back further. Good microservices, in my opinion, are not only loosely coupled, any sort of coupling at all is provided by the OS, nothing else. So you'd need to go back to JCL days to find a good analogy for microservices. Trying to stick these other concepts into the microservices bucket looks like a non-starter to me.
SOA was not that big of a hit because the time wasn't right. Just like MySpace before Facebook, the market wasn't ready. And to say they are the same is to ignore the advances each tech made.
You could push this argument to the extremes and say "well, Microservices are just Processes on different computers talking through a network IPC and this $unknownProject has done that back when Ethernet first started".
Nothing in tech is original and everything is.
Huh? It dominated the 90s, especially in enterprise, in a way that micro-services today don't.
But I do think microservices will become bigger, we'll have to wait and see how k8s pans out.
Containers have nothing to do with it.
- you can keep a service running long after the project that created it has disbanded and/or the runtime and build environment is deprecated on a given O/S
- you don't necessarily need to deep-dive into the business logic of legacy services
- you can replace a service implementation with another one running on another stack without having to adapt service clients
- you can change auth mechanism outside of the service implementations
- you can scale out (CPU-bound) services onto multiple hosts
Mind you, these benefits are not achieved by using microservices/SOA in itself; the contribution of microservices/SOA, however, is that these design goals aren't impossible to achieve because of architected reasons.
That's the main property that sets microservices apart from mere SOAs: Microservices reduce the risk of change.
With properly architected microservices a single deployment is unlikely to impair an application as a whole whereas with traditional monolithic deployments a single change can severely affect the functionality and operations of an application.
This is also why you probably don't need microservices if you don't need that kind of fine-grained control and risk mitigation.
Microservices lend themselves to being used in conjunction with domain-driven design. A single microservice should only deal with one domain.
If you have a service that covers cross-cutting concerns such as orders that service is not a microservice. In order to improve the design in your case each microservice could access and manipulate order data according to its scope.
That way, if one of the services fails only the small part of the order functionality implemented by that service will fail while the remaining order features will remain intact (to some extent; steps in a linear order process that depend on each other of course will still fail without successful outcomes from previous steps).
I know of some architectures where the API Gateway has a lot of logic put into it... And you have to go through it to reach any of the microservices in the network.
Isn't this a single point of failure and similar to an ESB?
We have broken off two of our monolith’s components into a microservice and for now it’s working great - but there are just some things I don’t think make sense to decouple and isolate. I’m afraid I’d get in an integration hell. Has anyone had such an issue?
When that will happen in your case is highly dependent on what you're doing, but it will happen. Eventually you will run into situations where implementing a single small feature requires changes to 3 or more systems, plus deploying all of those systems to all of your environments, code reviews for each service, etc. The overhead explodes as you break more things apart.
They may be, but don't have to be. Like many other technology terms that go through a hype cycle, microservices also vary in definition by a large measure. This talk from 2014 by Martin Fowler [1] is about the breadth of definitions as well as contrasts with monoliths.
Microservices by theory are a return to the early theory of SOA, which may frequently have been diverged from in practice, but that probably happens with microservices, too.
> Services in 90s & 2000 are SOA in a monolith.
The theory of SOA is loose coupling through independent services interacting through a shared communication medium. That may not always have been observed strictly in practice, but that's true of microservices, too.