I used to hate my monolith online banking platform, but it was due to ignored technical debt. I see a place for microservices, but I would gladly take my monolith over 1600 of them any day.
Having worked with monolith applications before, operation (wrt availability) and scalability was hard. That's what microservices hope to fix, but to fix the other problems they introduce you have to build what the presenters point out: container orchestration, distributed tracing, aggregated logging, uniform and ubiquitous application metrics, and a monorepo codebase... The cost of these things start to pay off at a certain scale, but definitely not worth paying in every case.
How do we reached 1600 microservice? - We overrides the new operator, so every time you create a new Object, we spawn a new microservice to store the Object information in our nice Cassandra Database and expose a nice RPC API to handle the functions. We call the concept: "Microservice Oriented Programming" MOP.
There are 2 things that are easy to do. Create a system with one service and create a system with an infinite number of services. Finding the balance between the two is the tricky part.
Comment section, in a large microservice ecosystem, how are you guys handling: Authentication? - do large number of microservices all share the same security roles? Does each microservice verify roles or do they make assumptions that they are internal only? Deployments and testing? - if 10% of your microservices change on a weekend, are we testing just those microservices? Or are we also testing all products which use those microservices? Versioning? realistically speaking are these microservices versioned or do they really just make lots of changes that are backwards compatible? Products? If microservice C creates a new version which now takes full date of birth instead of age, just as an example. How are we troubleshooting issues when microservice A still calls V1, and microservice B calls V2 of microservice C? Total transaction time? What's the average number of microservice calls or network calls that occur for your requests? Repos? - are people using mono repos or does each microservice have its own? With the right tooling, does it even matter these days?
I think this implementation example is one of those "microservice architecture" where the persistent data store is shared between the 1600 microservices.
Having such granular services, how do they manage distributed transactions. I thought transactions usually define service boundaries. Secondly, what is the cost of network latencies for time-sensitive operations? Making so many network calls, how reliable is the application?
For microservices, distributed transactions should be avoided at all costs. They typically use what's called "Sagas" instead. Basically, it's a series of transactions that can be rolled back. Network calls also should be kept to a minimum. For example, when doing a GET, if the data being requested is sourced from multiple services, there would usually be a service that acts as a VIEW to that data, and it would be updated based on subscribing to the sourced services events.
landon baker the distributed saga I guess is similar to a 2 PC where you have an intermediate state before commit right. If there is a way to deal with it, what is the case against it?
@@Amithn90 There are a couple of reasons to choose a saga over 2-phase commit. 1.) Each microservice should have it's own data store, and each microservice should have the ability to choose different data stores. For example, one microservice may use MongoDB while another uses SQL, but if 2 services use MongoDB, then it should be different database instances for each service. 2.) 2 phase commit locks the objects for the entire commit while a saga only locks the object during its short local transaction. This is mostly a problem because the services exist over the network, so each additional resource would add some overhead. So a 2PC could become a bottleneck pretty quickly when needing to lock resources from multiple services many times per second. Additionally, 2 phase commits can potentially lead to deadlocks, while Sagas won't. With that being said, with everything in the Microservices vs Monoliths debate, it adds complexity that must be planned for. if it is not done well, you'll wish you had the 2PC/monolith, but if it's done well, it'll be better.
@@landonbaker3951 as far as I understand, the problem with sagas is that the dbs can still be in an inconsistent state for a short period of time between when all the data is commited or rolled back, so there seem to be some tradeoffs. 2pc transaction coordinator should be more consistent. Why not use something like cockroachdb, spanner, faunadb, yugabytedb, tidb instead, as they keep the db at serializable isolation and you don't have to think about it as long as it keeps working ofc 😂
Perhaps they did not clarify the flows or verticals boundaries between those services, because it seems something went horrible wrong with that design.
I reviewed this in quite a bit of detail. When you watch the video you are left with the impression that they have created this incredibly flexible architecture that is extremely efficient. When you dig into the comments you find they have 1551 employees in of which half are developers. That is an amazing number of developers and does not imply efficiency at all. When you check their financial statement you see they lost 130 million in 2021 and are heavily dependent on investor money and are at risk of failing completely. (check out video "Monzo in trouble") I am mostly interested in it from a technology perspective though. It makes me wonder when you create a banking system based on Cassandra which is not ACID compliant whether this contributes to the issues. As a result of not being ACID compliant, it forces developers to make up for it in code and do things like transaction processing (lock, rollback and commit). On a side note, I am confused by the response when the presenter is asked about Cassandra not being ACID compliant, and he says there is a common misconception that banks must be ACID compliant. (44:00)
You should have information about which service calls which in the logs. And then you can use visualization tools or libraries like d3js to make simple Graph chart - observablehq.com/@bstaats/graph-visualization-introduction
IT industry needs architects to make simple things really complex and call it "architecture", but in fact everyone tries to get piece of big pie while it's warm.
@@miketyson7274 1551 employees doesn't mean 1551 developers. I would say that at most half of them are devs. So that gives you at least two microservices per developer 😂
@@EduardCB Thinking about it over night, if the 2 micro services I have responsibility for are ~2000 lines of code this doesn't sound as bad as it looks. Reality might be more complex tho.
That 1,000 lines doesn't include the infrastructure/dependencies they use for communicating with each other, security etc. Also they use Go, the good thing about Go is you just write the business logic and change as you need to, not writing code that needs to be abstract, needing big factories or complex just straight to the point.
@@BradleyWeston92 yeah, but if you just write a monolith you don't need the communication libraries. Also it is faster. We are in year 2021, I want to be abstract, I want the computer to work for me, not write C like boomers.
@Marc Green the same thing that happens when you have to change code in 100 microservices to implement 1 feature. You just write your monolith with well designed interfaces between the modules, like you have well defined api definitions for your microservices. The separation between the microservices is not real, they are still just procedure/method calls or more generally messages, but remote in this case. Ofc I am not advocating for always using the same language or programming model if it doesn't make sense, just saying that writing a microservice for 1-3 classes is stupid and everyone who does this needs to stop or the whole software industry will turn to shit. Only separate them on bounded contexts/transaction boundaries and if you need to have separate databases for each microservice. Distributed transactions are nasty, you are basically building a broken database with your microservices as stored procedures.
What worry me the most is the shitstorm that must be their network... 1600 services all doing api calls to each other. but I guess the network is provided by amazon in this case ?
I thank you so much for this video. This gives me a realistic perception of how much code and time it takes to build something of this scale. It was also very informational and a HUGE guidance on how to start building these evolving massive companies. Thank you very much!!!
That's it !!! I couldn't figure out why there was a strong urge to tune him out. I guess it's hard for his colleagues to critique that. Hopefully he reads the comments. 😏
@Marc Green complexity does not disappear, it is shifted somewhere. You have to maintain hundreds of services with hundreds of teams which have to communicate etc. Maintaining SLA and security is much harder when number of services grows.
LOL here is why this is bad idea... what's a microservice (ms). basically think of functions but on their own servers and to call them you need to call a url. so every function is behind a http server theoretically making it very scalable but coding is 1. Most code is synchronous - once transaction is verified then transfer funds) any point in making them a separate ms if 2nd part is stuck 1-to-1. 2. Conditional code - if this happens, do that, if not then this, but finally do this. A logic that could fit in 10 lines of code, but if they are in ms you are really in the world of hurt....you can emulate if this then that... by having service A call service B, but what about finally..Service C needs to be called once data from both A and B have been returned. To do that you call them in reverse. Service D would call A and C then wait for them. Complexity increases and if A calls B then it has error, now you are going propagate that error all the way to D. 3. Debugging - do you like your debugger have control over entire program's state and step through it one by one.. lol. debugger can't do that if all of your code is on different server. To debug, you have to provide mock state for every possible state that your microservices upstream can give to a particular service and if you dont find an error here, keep moving. now do that for every function. Oh you want actual data, there is no stack trace.. go read over 1000000 lines of logs 4. Global state, often functions have access to global state, that is shared by many functions, there is none of that, you either do read operation on DB or pass along bloated objects. 5. Traffic / http - before unless cpu crashed you could expect abc() to always run. Now you have to worry about http request failing, or timing out due to severs starting or dying, load balancing and plain traffic congestion. So you have to implement retries, throttling, queues, events systems. before you could have done abc(). 6. Code / Business requirements change - as a result now you have either 30 versions of same function purely because other code relies on it and to modify it you'd have to modify everything. It's classic problem in all code bases, but here refactoring is impossible as it'd take 10x longer. Often microservices are under different teams so good lucking opening requests tickets and telling them EXACTLY what you want, never mind that development is trial and error process, but surely you wont waste other time so tell them what you want, wait a week, and then cry if you need to change it again.
Also using microservices is basically using stringly-typed data. Atleast in monoliths a lot of errors of using the wrong API, sending only year instead of FullDateFormat would be caught by the static type checker.
@@comradepeter87 honestly I think a compiler should exist that takes CPU heavy code paths and automatically spawn that code onto new machines and then instead of using running code locally complier could make rpc calls
I'd be more interested in their use of Go, than their microservice architecture. 1000 lines per service is basically not possible with Java due to the enormous amount of boilerplate code that Java requires. It feels like they are successful despite their big ball of mud architecture, because of their use of Go.
Dev : declares a string in code
Manager : create a microservice for this.
Dev : This is useless
Manager : Just do it
Dev : StringService
I used to hate my monolith online banking platform, but it was due to ignored technical debt. I see a place for microservices, but I would gladly take my monolith over 1600 of them any day.
Having worked with monolith applications before, operation (wrt availability) and scalability was hard. That's what microservices hope to fix, but to fix the other problems they introduce you have to build what the presenters point out: container orchestration, distributed tracing, aggregated logging, uniform and ubiquitous application metrics, and a monorepo codebase... The cost of these things start to pay off at a certain scale, but definitely not worth paying in every case.
How do we reached 1600 microservice?
- We overrides the new operator, so every time you create a new Object, we spawn a new microservice to store the Object information in our nice Cassandra Database and expose a nice
RPC API to handle the functions. We call the concept: "Microservice Oriented Programming" MOP.
calm down Satan
This makes me feel so horrible just by reading it.
1600 services and almost zero words about:
- deployment
- service-discovery
- versioning
- scaling
- documentation
- dependency management
- chaos engineering
😭
and yet stability and performance is going pretty darn well.
the number of microservices should not be a proud thing to exaggerate
Yup, it's very stupid
There are 2 things that are easy to do. Create a system with one service and create a system with an infinite number of services. Finding the balance between the two is the tricky part.
I hope you created a micro service to post that comment
Comment section, in a large microservice ecosystem, how are you guys handling:
Authentication? - do large number of microservices all share the same security roles? Does each microservice verify roles or do they make assumptions that they are internal only?
Deployments and testing? - if 10% of your microservices change on a weekend, are we testing just those microservices? Or are we also testing all products which use those microservices?
Versioning? realistically speaking are these microservices versioned or do they really just make lots of changes that are backwards compatible?
Products? If microservice C creates a new version which now takes full date of birth instead of age, just as an example. How are we troubleshooting issues when microservice A still calls V1, and microservice B calls V2 of microservice C?
Total transaction time? What's the average number of microservice calls or network calls that occur for your requests?
Repos? - are people using mono repos or does each microservice have its own? With the right tooling, does it even matter these days?
Working for Monzo be like: This code is over 10 lines long... it should be a microservice!
I think we figured out why the Monzo app is very slow loading.
I think this implementation example is one of those "microservice architecture" where the persistent data store is shared between the 1600 microservices.
Yeah, essentially microservices demand for own independent schema not strictly always a own database.
KISS methodology , right? XD
Having such granular services, how do they manage distributed transactions. I thought transactions usually define service boundaries. Secondly, what is the cost of network latencies for time-sensitive operations? Making so many network calls, how reliable is the application?
For microservices, distributed transactions should be avoided at all costs. They typically use what's called "Sagas" instead. Basically, it's a series of transactions that can be rolled back.
Network calls also should be kept to a minimum. For example, when doing a GET, if the data being requested is sourced from multiple services, there would usually be a service that acts as a VIEW to that data, and it would be updated based on subscribing to the sourced services events.
landon baker the distributed saga I guess is similar to a 2 PC where you have an intermediate state before commit right. If there is a way to deal with it, what is the case against it?
@@Amithn90 There are a couple of reasons to choose a saga over 2-phase commit.
1.) Each microservice should have it's own data store, and each microservice should have the ability to choose different data stores. For example, one microservice may use MongoDB while another uses SQL, but if 2 services use MongoDB, then it should be different database instances for each service.
2.) 2 phase commit locks the objects for the entire commit while a saga only locks the object during its short local transaction. This is mostly a problem because the services exist over the network, so each additional resource would add some overhead. So a 2PC could become a bottleneck pretty quickly when needing to lock resources from multiple services many times per second. Additionally, 2 phase commits can potentially lead to deadlocks, while Sagas won't.
With that being said, with everything in the Microservices vs Monoliths debate, it adds complexity that must be planned for. if it is not done well, you'll wish you had the 2PC/monolith, but if it's done well, it'll be better.
@@landonbaker3951 as far as I understand, the problem with sagas is that the dbs can still be in an inconsistent state for a short period of time between when all the data is commited or rolled back, so there seem to be some tradeoffs. 2pc transaction coordinator should be more consistent. Why not use something like cockroachdb, spanner, faunadb, yugabytedb, tidb instead, as they keep the db at serializable isolation and you don't have to think about it as long as it keeps working ofc 😂
I thought this video would be interesting. But actually the comments are most interesting.
hahahah, exactly. I haven't even watched the video but I have gotten full entertainment from the comments
Perhaps they did not clarify the flows or verticals boundaries between those services, because it seems something went horrible wrong with that design.
This is madness
This . . . is . . . SPARTA!!!
@@williamdavies1977 well played man , well played ......
Number of microservices aside, I really think they have a solid engineering practice there
I reviewed this in quite a bit of detail. When you watch the video you are left with the impression that they have created this incredibly flexible architecture that is extremely efficient. When you dig into the comments you find they have 1551 employees in of which half are developers. That is an amazing number of developers and does not imply efficiency at all. When you check their financial statement you see they lost 130 million in 2021 and are heavily dependent on investor money and are at risk of failing completely. (check out video "Monzo in trouble")
I am mostly interested in it from a technology perspective though. It makes me wonder when you create a banking system based on Cassandra which is not ACID compliant whether this contributes to the issues. As a result of not being ACID compliant, it forces developers to make up for it in code and do things like transaction processing (lock, rollback and commit).
On a side note, I am confused by the response when the presenter is asked about Cassandra not being ACID compliant, and he says there is a common misconception that banks must be ACID compliant. (44:00)
Yaa keen observation
Nano-Services is the right term.
Hey I am interested in how the microservices calling graph is generated? Are there any tools ?
Only tool I know is called Vizceral, I doubt they used it for this overview.
You should have information about which service calls which in the logs. And then you can use visualization tools or libraries like d3js to make simple Graph chart - observablehq.com/@bstaats/graph-visualization-introduction
AppDynamics and DynaTrace
Weave Scope if you have k8s, but watch out for the recent vulnerability.
IT industry needs architects to make simple things really complex and call it "architecture", but in fact everyone tries to get piece of big pie while it's warm.
So that's 1 microservice for every 2,500 customers...
Gotta be flexible and ready to scale, man. Now, if only there would be more customers...
lol.. did every developer in the company created their own service?
😂🤣😂
It's onboarding task for newcomers
According to wikipedia, Monzo have 1,551 employees... so yeah 1 micro service per employee lol
@@miketyson7274 1551 employees doesn't mean 1551 developers. I would say that at most half of them are devs. So that gives you at least two microservices per developer 😂
@@EduardCB Thinking about it over night, if the 2 micro services I have responsibility for are ~2000 lines of code this doesn't sound as bad as it looks. Reality might be more complex tho.
1000 lines per service... so basically a microservice for each class?
That 1,000 lines doesn't include the infrastructure/dependencies they use for communicating with each other, security etc. Also they use Go, the good thing about Go is you just write the business logic and change as you need to, not writing code that needs to be abstract, needing big factories or complex just straight to the point.
@@BradleyWeston92 yeah, but if you just write a monolith you don't need the communication libraries. Also it is faster. We are in year 2021, I want to be abstract, I want the computer to work for me, not write C like boomers.
@Adithya R yeah well guess what linus torvalds builds monoliths not shitty 1000 lines microservices
@@gigiduru125 ~ 'not write C like boomers'... how disrespectful to those that paved the path you're now walking.
@Marc Green the same thing that happens when you have to change code in 100 microservices to implement 1 feature. You just write your monolith with well designed interfaces between the modules, like you have well defined api definitions for your microservices. The separation between the microservices is not real, they are still just procedure/method calls or more generally messages, but remote in this case. Ofc I am not advocating for always using the same language or programming model if it doesn't make sense, just saying that writing a microservice for 1-3 classes is stupid and everyone who does this needs to stop or the whole software industry will turn to shit.
Only separate them on bounded contexts/transaction boundaries and if you need to have separate databases for each microservice. Distributed transactions are nasty, you are basically building a broken database with your microservices as stored procedures.
I wanna know if each of their microservices has its own instance of cassandra, or if they all share one massive database??
where can I see that speech he mentioned "Support at the speed of thought" by Sophie ?
This sounds crazy to me tbh. 1600 services?!
Is it skynet?
What worry me the most is the shitstorm that must be their network... 1600 services all doing api calls to each other. but I guess the network is provided by amazon in this case ?
I thank you so much for this video. This gives me a realistic perception of how much code and time it takes to build something of this scale. It was also very informational and a HUGE guidance on how to start building these evolving massive companies. Thank you very much!!!
What I want to know is how do you go from knowing nothing about an industry to being able to build a system for that industry?
Upward inflection overload.
That's it !!! I couldn't figure out why there was a strong urge to tune him out. I guess it's hard for his colleagues to critique that. Hopefully he reads the comments. 😏
Just when you thought the Valley Girl up talk was annoying, in comes this guy adding a British accent to it.
So basically they made autonomous components as separate deployments and call it micro-services.
The combination of locking and cassandra sounds like trouble.
so brilliant. All these years later and their *still* ahead of many banks.
I don't think it is a good idea to prioritize quantity over quality in this case
If you improve one microservice with one purpose, how does that replace other microservices (decrease quantity) with different purposes?
@@TheUmnez depends, if it's modify the API schema, then it's going to be a big chore
I'm still thinking about this, are they really need that many services? I believe no
More doesn’t mean better
@Marc Green complexity does not disappear, it is shifted somewhere. You have to maintain hundreds of services with hundreds of teams which have to communicate etc. Maintaining SLA and security is much harder when number of services grows.
@Jonah Meijers security inside app management itself can't be abstracted from any service that uses any permission model
@Jonah Meijers it must use API not "imported", when you reuse code, you create coupling and it called distributed monolith
@@mg00 i get micro services as a concept but it should be a higher level abstraction, not abstract every little thing into it's own service.
Imho, if you have such a complexed architecture your domain must be quite simple.
wanna change the system? just add a service.
Open-Closed principle
I have only one word to say 'Madness'.
Amazing !! That's every developers dream to build such systems... Certainly mine too ❤️
Great speech , tnx 🔥🌞
Excellent!!!
its like addiction now...
LOL here is why this is bad idea...
what's a microservice (ms). basically think of functions but on their own servers and to call them you need to call a url.
so every function is behind a http server theoretically making it very scalable
but coding is
1. Most code is synchronous - once transaction is verified then transfer funds) any point in making them a separate ms if 2nd part is stuck 1-to-1.
2. Conditional code - if this happens, do that, if not then this, but finally do this. A logic that could fit in 10 lines of code, but if they are in ms you are really in the world of hurt....you can emulate if this then that... by having service A call service B, but what about finally..Service C needs to be called once data from both A and B have been returned. To do that you call them in reverse. Service D would call A and C then wait for them. Complexity increases and if A calls B then it has error, now you are going propagate that error all the way to D.
3. Debugging - do you like your debugger have control over entire program's state and step through it one by one.. lol. debugger can't do that if all of your code is on different server. To debug, you have to provide mock state for every possible state that your microservices upstream can give to a particular service and if you dont find an error here, keep moving. now do that for every function. Oh you want actual data, there is no stack trace.. go read over 1000000 lines of logs
4. Global state, often functions have access to global state, that is shared by many functions, there is none of that, you either do read operation on DB or pass along bloated objects.
5. Traffic / http - before unless cpu crashed you could expect abc() to always run. Now you have to worry about http request failing, or timing out due to severs starting or dying, load balancing and plain traffic congestion. So you have to implement retries, throttling, queues, events systems. before you could have done abc().
6. Code / Business requirements change - as a result now you have either 30 versions of same function purely because other code relies on it and to modify it you'd have to modify everything. It's classic problem in all code bases, but here refactoring is impossible as it'd take 10x longer. Often microservices are under different teams so good lucking opening requests tickets and telling them EXACTLY what you want, never mind that development is trial and error process, but surely you wont waste other time so tell them what you want, wait a week, and then cry if you need to change it again.
Also using microservices is basically using stringly-typed data. Atleast in monoliths a lot of errors of using the wrong API, sending only year instead of FullDateFormat would be caught by the static type checker.
@@comradepeter87 honestly I think a compiler should exist that takes CPU heavy code paths and automatically spawn that code onto new machines and then instead of using running code locally complier could make rpc calls
how tf do you even think of 1500 different microservices to make?
Having multiple teams and problems
Wow. That's impressive!!!
what's a Microservice ?
1600 microservices doing what? What bank needs so many services? Example of overuse if Microservices
Homie in the back nodding away is suuuuuper distracting
I'd be more interested in their use of Go, than their microservice architecture. 1000 lines per service is basically not possible with Java due to the enormous amount of boilerplate code that Java requires.
It feels like they are successful despite their big ball of mud architecture, because of their use of Go.
Use Kotlin, no boilerplate. Less than in Go.
Their big ball of mud won't be a problem for a few years. If they want to change things, they will have big problems.
Too much microservice .i think 20-30 microservice is enough cover business of banking.
What nonsense it is
Go? I want Javascript to handle my money! :D
Go and Cassandra. Error handling is optional. Default read/write consistency level is ONE (or at least used to be).
MICROSERVICE ORIENTED PROGRAMMING 🤣
Banking? Lol more like scamming
Those slides are worse than what an elementary school student can come up with.
micro micro micro CRAP