[The assumption: only by - ] .. packaging your services as discrete units .. [you can] via .. Docker .. [achieve] horizontal scalability.
However, it’s incorrect ... [to assume it can] only .. [with a] microservice.
Interesting, how monolith can do the same?
You can create logical clusters of your monolith
which only handle a certain subset of your traffic.
Oh... so MS... but with extra steps. lol. not to mention we usually care about the DB scale also, which is harder to scale as a monolith with segmented traffic.
It's not necessarily much in the way of extra steps. The Elasticsearch Cloud-on-K8s operator IMO does this quite well.
You define 'node sets' which each play a role in the cluster. Node sets can have tags applied to them, and this affects the procedures they run.
For example, you could say:
1. Let's have a node set of 3 master nodes.
2. Let's have a nodeset of 10 hot data nodes, backed with SSDs and tagged with 'hot'.
3. Let's have a nodeset of 5 cold data nodes, backed with HDDs and tagged with 'cold'.
4. 4 client nodes for load balancing.
You could also say - let's have 3 nodes that play all roles.
On startup, each node starts only the parts of the app that correspond to the roles it's playing.
It's fairly seamless and I think this model would expand quite nicely to 'business logic' services
Anecdotally, have seem some people attempt to retrofit a poor man's version of this model into their microservice in response to e.g. performance problems.
Not quite: since with monoliths that are deployed in parallel or have sets of functionality behind feature flags, you're still dealing primarily with one codebase and each instance should be able to service requests on its own, instead of making further network requests across N other instances.
A single codebase will generally be easier and quicker to develop against (up to a certain scale), since you don't need so much "internal glue" code between your microservices (network calls and error handling, data type marshalling etc.).
That said, personally I'd prefer microservices for other reasons - so that I could let old parts of the overall system (possibly developed by others) not get in the way of progress, such as not being able to update the application/service to JDK 11/17 because of a PDF library only runs on JDK 8 or something like that.
Furthermore, if you work on a project for long enough, the slow startup and compile times of a large monolith (without the modularization at least, which might not be possible to ensure in certain stacks), the high resource usage and possibly sluggish performance, the numerous approaches that have been utilized to get something like logging or scheduled processes over 5-10 years of development clashing with one another and many other things will just get very annoying and painful to deal with.
Being able to spin up a new service with whatever is easy to work with for the particular case, making it your own little corner of the overall system with good tests and arguably good code (at least for now) is really nice. Until you have 20 of these services, written by people with varying approaches/standards and it's a mess again.
I think there's really no winning with either approach, each has their benefits and shortcomings.
not to mention we usually care about the DB scale also, which is harder to scale as a monolith with segmented traffic.
This is a fair point!
Though I think that GitLab recently split their database across the boundary of CI functionality and everything else, which was a pretty good example of how far you can get with a single DB (no doubt with replication/clustering and standby instances though): https://about.gitlab.com/blog/2022/06/02/splitting-database-...
In contrast, forgoing something like foreign keys and ending up with distributed transactions (sagas or similar), having to enforce your own data consistency etc. can be asking for trouble before you actually need to care about scaling and split everything up so much.
It's probably a matter of choosing whichever approach works for your scale now and will work for you in the near future.
There is no reason microservices can't be in the same codebase. In fact, for things like infrastructure and testing that may need to touch more than one service at a time, it's incredibly useful to have a monorepo.
At my current job we have this setup - one repo contains 14 different services. Admittedly there are still way more services than their need to be but having everything in one place helps to keep bit rot at bay, and it avoids the need to deploy and synchronise patches across multiple repos.
Comments
Interesting, how monolith can do the same?
Oh... so MS... but with extra steps. lol. not to mention we usually care about the DB scale also, which is harder to scale as a monolith with segmented traffic.
It's not necessarily much in the way of extra steps. The Elasticsearch Cloud-on-K8s operator IMO does this quite well.
You define 'node sets' which each play a role in the cluster. Node sets can have tags applied to them, and this affects the procedures they run.
For example, you could say:
1. Let's have a node set of 3 master nodes. 2. Let's have a nodeset of 10 hot data nodes, backed with SSDs and tagged with 'hot'. 3. Let's have a nodeset of 5 cold data nodes, backed with HDDs and tagged with 'cold'. 4. 4 client nodes for load balancing.
You could also say - let's have 3 nodes that play all roles.
On startup, each node starts only the parts of the app that correspond to the roles it's playing.
It's fairly seamless and I think this model would expand quite nicely to 'business logic' services
Anecdotally, have seem some people attempt to retrofit a poor man's version of this model into their microservice in response to e.g. performance problems.
Not quite: since with monoliths that are deployed in parallel or have sets of functionality behind feature flags, you're still dealing primarily with one codebase and each instance should be able to service requests on its own, instead of making further network requests across N other instances.
I actually wrote more about this a while ago, "Moduliths: because we need to scale, but we also cannot afford microservices": https://blog.kronis.dev/articles/modulith-because-we-need-to...
A single codebase will generally be easier and quicker to develop against (up to a certain scale), since you don't need so much "internal glue" code between your microservices (network calls and error handling, data type marshalling etc.).
That said, personally I'd prefer microservices for other reasons - so that I could let old parts of the overall system (possibly developed by others) not get in the way of progress, such as not being able to update the application/service to JDK 11/17 because of a PDF library only runs on JDK 8 or something like that.
Furthermore, if you work on a project for long enough, the slow startup and compile times of a large monolith (without the modularization at least, which might not be possible to ensure in certain stacks), the high resource usage and possibly sluggish performance, the numerous approaches that have been utilized to get something like logging or scheduled processes over 5-10 years of development clashing with one another and many other things will just get very annoying and painful to deal with.
Being able to spin up a new service with whatever is easy to work with for the particular case, making it your own little corner of the overall system with good tests and arguably good code (at least for now) is really nice. Until you have 20 of these services, written by people with varying approaches/standards and it's a mess again.
I think there's really no winning with either approach, each has their benefits and shortcomings.
This is a fair point!
Though I think that GitLab recently split their database across the boundary of CI functionality and everything else, which was a pretty good example of how far you can get with a single DB (no doubt with replication/clustering and standby instances though): https://about.gitlab.com/blog/2022/06/02/splitting-database-...
In contrast, forgoing something like foreign keys and ending up with distributed transactions (sagas or similar), having to enforce your own data consistency etc. can be asking for trouble before you actually need to care about scaling and split everything up so much.
It's probably a matter of choosing whichever approach works for your scale now and will work for you in the near future.
There is no reason microservices can't be in the same codebase. In fact, for things like infrastructure and testing that may need to touch more than one service at a time, it's incredibly useful to have a monorepo.
I need a t-shirt: monorepos, not monoliths!
At my current job we have this setup - one repo contains 14 different services. Admittedly there are still way more services than their need to be but having everything in one place helps to keep bit rot at bay, and it avoids the need to deploy and synchronise patches across multiple repos.