I wonder if there is a difference in terminology between the way I use microservices and the industry? I have worked on a number of systems, both monoliths and microservices, and when a service gets big enough (think Spotify or Uber) monoliths simply don't scale. I will agree that doing microservices before you have to is unnecessary complexity and what I would consider overengineering, however if the consensus is they provide no technical advantage I have to disagree, here are some that come to mind:
1) A monolith will have to consume a large amount of resources per request due to having all the models available at runtime. Lets say I have a system that handles 100 RPS but only 1 RPS uses that model, and that model is GB's of RAM and requires GPU, that means I will have to have this memory and GPU allocated for every request, making scaling much more costly. (Note: your mileage will vary depending on your complexity)
2) A monolith is a central point of failure, if I make a mistake in that service it can affect all of my requests, rather than just the request that calls out to that microservice, this is a difference between my entire service going down and just a feature.
These are just 2 I thought of off the top of my head, but I wonder why I seem to be out of step with HN consensus here.
There's a difference between a microservices architecture and putting in services where they make sense. We build mostly monoliths at work but we still split things into services where necessary. Necessary meaning the benefit is both large and obvious for the company.
Not all systems that use services is a microservice architecture.
#2 makes sense if you're taking advantage of that. In contrast, I've seen lots of microservices code that does little to no error handling. And if it's unicorn code that has error handling, they haven't really tested all the ramifications of their services going down in all the ways they can go down. Instead of having a system with a single point of failure, they have a system with N single points of failure. Their microservices are less fault tolerant than a monolith.
The backlash against microservices on HN is unsurprising. Over the years a ton of articles have been written vaguely about microservices and people cargo culted the architecture based upon these vague articles. Even reading comments people talk vaguely about "scaling" - what do people really mean? Before this backlash there had been non-ironic articles posted AND upvoted on HN about using microservices to scale to... a hundred requests per minute!
Lots of people seem to think that your architectural choices are either a single threaded rails app vs an eventually consistent distributed transaction CQRS nanoservice system that needs 99.999999% uptime. Meanwhile that eventually consistent distributed transaction CQRS nanoservice system that needs 99.999999% uptime is, for some reason, only running in one availability zone and falls down and corrupts your database as soon as any of your services fall over.
Oh, and it serves pictures of cats and it has 10 users and they're all family members. But someday that architecture will come in handy.
> There's a difference between a microservices architecture and putting in services where they make sense. We build mostly monoliths at work but we still split things into services where necessary.
It seems that your problem has more to do with semantics than with what microservices are.
Arguably, the definition of a microservices architecture is "not a monolith", in the sense that it's a distributed system not only with regard to support and infrastructure services but also with regards to business logic.
> 1) A monolith will have to consume a large amount of resources per request due to having all the models available at runtime. Lets say I have a system that handles 100 RPS but only 1 RPS uses that model, and that model is GB's of RAM and requires GPU, that means I will have to have this memory and GPU allocated for every request, making scaling much more costly. (Note: your mileage will vary depending on your complexity)
Needing a heavy model per-request is very much the exception rather than the rule; even if you're doing ML, for most cases you'd do that with a single shared copy of your model. If you're somehow loading a model for each request, surely you can just not do that for requests that don't need it?
> 2) A monolith is a central point of failure, if I make a mistake in that service it can affect all of my requests, rather than just the request that calls out to that microservice, this is a difference between my entire service going down and just a feature.
I can understand people doing that in languages like Python or especially Ruby, where metaclasses / monkeypatching mean that it's easy for one part of the code to interfere with another. But I think it's a mistake to apply that to more structured languages where it's relatively easy to have an enforced separation between different modules within a single deployable.
1. Yes, if you have an application that works this way you will have to manage your deployment to compensate. But you can use configuration as feature flags to keep a monolith but when you deploy it to X servers you enable one feature set and to Y servers you enable another. So you get the benefits of developing in a monolith but the isolation of microservices.
2. See #1, but also use proper error handling. It's been a while since I've seen a single request take down the whole app.
I wonder if this is why my issue is with the terminology, what you have described in 1 to me is a microservice architecture. I currently have a monorepo deploying microservices in order to get the benefits of developing in a monolith but with the isolation of microservices, but I do consider it a microservice architecture on the whole.
There are definitely ways each approach can approximate the benefits of the other:
- Microservices can be deployed as processes on the same machine and communicate over the loopback interface or domain sockets without much network-related risk. This is still more complicated than function calls, and I wouldn't quite call it a monolith.
- Monoliths can have traffic for different endpoints partitioned over different deployment groups. So the behavior of one endpoint can be changed independent of the others. But a module deep in the stack, potentially consumed by many endpoints, cannot be deployed on its own in a way that affects all its consumers. So I wouldn't quite call this microservices.
Nah, it can be one service just deployed with different configuration. Or as another commenter said, a different binary based on compilation flags/config.
Monolith doesn't mean you couldn't have fault tolerance, e.g. if the monolith is distributed. Monolith is just a term that means "all encompassing", or that "you've thought of everything". In contrast, a microservice is basically "I can't think of everything so I break up my system into smaller, easier to understand pieces, and hope for the best".
1) A monolith will have to consume a large amount of resources per request due to having all the models available at runtime. Lets say I have a system that handles 100 RPS but only 1 RPS uses that model, and that model is GB's of RAM and requires GPU, that means I will have to have this memory and GPU allocated for every request, making scaling much more costly. (Note: your mileage will vary depending on your complexity)
2) A monolith is a central point of failure, if I make a mistake in that service it can affect all of my requests, rather than just the request that calls out to that microservice, this is a difference between my entire service going down and just a feature.
These are just 2 I thought of off the top of my head, but I wonder why I seem to be out of step with HN consensus here.