Hi everyone, this is GKCS! Today we are talking about how to
move from monolith to microservices. Now we know what monoliths are.
They are rather large code bases, which contain all of the logic required
for you to run your application anywhere you like. All of the relevant code in this
project is kept in a single repository. While in the micro-service
architecture, you have cell phones, which connect to different services
based on what the requirement is. So let's say you're logging into Google. Does the payment service in Google need
to know about what you're doing? No, not really. You just need to go to the authentication
service and when it gives you a response, your authentication is done. So you are seeing that the code has been
broken into pieces and converted into services themselves. As you can see, there are quite a few advantages that
microservices have over monoliths, the first one, being that if you
need to make any feature change, let's say your payments now need
to also accept PayPal payments. All you need to do is just go to this
payment service and make the change. So there's a good separation of concerns. The second one is coding in microservices
is sometimes easier because all you need to worry about when you're making
a feature change is just the code, which exists here. So your expectations are
well-defined in the payment service. Your responses are well-defined and
that's all you need to care about. Your assumption is that
the rest of the services, the engineers in those services will
respect the contracts that you are making with them. So to some
extent, coding is easier, but so is designing these services and
the interactions that they'll have. So I would say instead of
coding, maybe 'engineering', these services is actually easier. The third critical advantage here is
that you can make deployments much easier with microservices, the authentication
service, when there's a change in that, you can just deploy the
authentication service separately. There might be a service, which
is not critical. For example, you have some ranking service,
some machine learning service, which ranks your restaurants.
Now, if it stops for one second, the world won't come to a collapse.
So the deployments are easier. These are the core
advantages of microservices. Monoliths also have certain advantages. The time when you move to a microservice
architecture is not when you have a lot of scale, not when all of
your users are coming in, you move to a microservice
architecture when your team has scaled. When you have a large team and all of
them want to move about individually, you have different product teams
working on different products. You want deployments to be smooth. That's when you move from
monoliths to microservices. So for a small team monoliths
are good. For a large team, microservices are probably the way to go. The second one is that because there is
more clear communication happening in the monolith... Module A to module B, you're doing a
single function call. The parameters. That you're passing into that
function are explicit. They are clear. So when you're making that function
call, if you make a wrong function, call, the compiler is going to say
no. While in a microservice, what could happen is that ID was earlier
an int. Now you ran out of integers. So you made it a string. So all the other services who connect to
this service are going to be using the profile with the ID as an int, because they are not aware that
the ID has turned into a string, which means that all communication
to this service will break. Okay, this is called a breaking change
earlier. You had something. Now you have something else which is not
compatible. That's a breaking change. So in microservices. It's much easier to have
breaking changes, which is bad. While in monoliths because the code and
therefore the expectations are in one place, it's much harder to
have these kinds of problems. Contracts are in one place.
These are the service contracts. Now let's find out how we can actually
move from monolith to microservices. One strategy would be that you make
this microservice architecture, where you have this
cloud of things running, and then some parts of the user, maybe
10% of the users are redirected here. If they have no issues, if these services are working
perfectly along with their databases, then you can make the switch. But the problem with this. Is that the engineering challenge
is huge because you need to write down all of these microservices. Also make sure that the databases
are correctly configured. Then you have to redirect these
users. So the effort for doing. This is massive. A much better approach is not
to invest so much in the start. What you can do is when you have a new
feature in this monolith architecture, you can try to separate that out
into a single service. For example, you might have a new analytics
feature that you need. So whenever any of these
modules are producing an event, you need the analytics module to
process that event and then give you dashboards or graphs or reports instead
of actually putting it in the moonlit architecture, we separate it out.
We make this a separate service. And how do we do that? Well earlier,
when you were communicating through cord, you used to just make a function called. Now you're going to be making
this call over a network. So you'll have either HTTP or GRPC or
whatever the network called doesn't really matter. But the treatment
of this piece of code, this service is as if
it's an external thing, you cannot access any of
its functionalities through
a function called, uh, and the analytics service will
also have its own database, which may be the same as
this database. Let's say, this is my SQL that you might
end up using my SQL here also, but you might use an SQL database also
like Amazon dynamo, DB, Cassandra, anything. There is an isolation of concerns when
it comes to the analytics service. And through this small change, what we have done is we are open the
possibility for all future services, all future functionalities being
sent to their relevant services. So analytics is having
its own code repository. This might be hosted
on GitHub or wherever, and this has its own code repository, which is separate from the
analytics code repository tomorrow. You might find that there's a
functionality of sending emails, which is being used by payments. Being used by profile is
being used by analytics. There's different emails
that you need to send. So you separate that out
into separate service. By doing this, what. Happens is we need to now bring in some
infrastructure changes to make addition of these services easy. And what
are those changes? Well, firstly, you need to be able to define how
are you going to communicate to these services? So the email service is going
to be taking your network calls, but it needs to give you a contract. That for the profiles that I have, I have the ID as an integer
or as a string or whatever. But this contract has to be
maintained by the email service. And whenever an external service
wants to call a function over here, it has to read this contract,
construct an object as per requirement, and then send the request or the network. That's the important thing. So the first change that we need is that
we need to define contracts for each microservice. Okay? These
are also called clients. Whenever a service in session service
wants to call it email service. It doesn't really read the contract. Technically what happens is you have
something called a client, okay? Each service has their own client. So if I'm an engineer for the
analytics service, I say, well, you're going to be reading my contract,
constructing the object in my way. That's pretty bad. So instead I
will write some piece of code, make a library out of it. And anybody
who wants to talk to analytics, you use this library to make
these function calls. Okay? So if sessions wants to talk to analytics, all it needs to do is download the
library. And if you want to say, get report, my library has that function
and you can pass in an ID. Here. My library will figure
out how to talk to my. External service. So analytics
is here. This is my library, which is running in your
box. And you are over here. Maybe you are the session service,
which is interacting with. This library. Okay? What. Happens if my library's not
up to date too bad? I mean, the code will break most
likely, or when it reaches here, there's going to be a break. So you need to be continuously
updated in terms of libraries. If you're looking for more details
on how this library is updated across services, you can look at the description
below there's interviewready.io, which is a system design video course.
It talks about this in more detail. The second thing we need to do is
also have a mechanism for routing requests from any service
to another service. So that's point number two,
we need some sort of a router. Most likely it's going to be the load
balancer, the services, the street, which routes requests based
on service capabilities, all this happened because you took a
new feature of analytics and made it a separate service, right? Because of that, you can actually pick on each of
these functionalities separately. Point number three is
simplifying deployments. The simplest way to deploy
any service is to do a CP, which is copy of the code that
you have in your GitHub repo on to an AWS box or GCP box, then going on to that box and
running the service. Okay? So literally what you're doing is
you're copying your code from one place, keeping it in the cloud server and
then running that service by firing a command. But as the number of services
in your organization increase, that's not what you want to be doing. You want to more seamless
way of things happening, maybe on every gate push to master. You
want the deployment to be dead, okay? Because your tests have run through and
you're sure that everything is fine. So you want to simplify deployments
by using tools like Jenkins. You want to simplify deployments by
actually using containers instead of deploying it on the box that
makes your DevOps team happier. The fourth one is that communication
between services can be varied. Let's say the session service talks to
the analytics service by using a message queue. Because if the message
doesn't reach the analytics team, if this event doesn't reach the
analytics service, what's the big deal. You know, the reports will be wrong, but it's not like the user's going
to drop off while in payments, you might need a much
more immediate response. So when the profile service is
talking to the payment service, you might want to request response
architecture so that you know exactly what happened immediately after a
request has been sent to payments. So that's the communication
bit point number five, which is the thing that most
people forget is logging. Uh, this is super important. If a request is sent from the
user to the session service, then it goes to analytics which
triggered something in profiles. And then it went to payments. There's no way that you can track all
this by logging into each service and then checking the logs and saying, oh, the
ID will be over here all the time. Then you go here and it's. Not going to happen.
Instead. You want to take. All the logs in all the services and
push it into a single repository, okay. A single database. So to speak,
you can use the elastic stack, which is good at this
stuff. And for pushing logs, you can do it through a
message queue like Kafka. Kafka can take all of the logs
from all of these services, and then you can store them
in something like leucine, which is a part of this
stack to summarize, moving from monolith to microservices,
require us to look out for new features, which are being added to
our existing application. We need to then think about how we
can take those new set of features and condense them into a single service, which instead of being added
as a module to the monolith, it will be made a separate
microservice. Once this is done, you can start focusing
on these five parameters. Do these services have sensible
contracts which are being updated. Do they have some sort of
routing to the right service? Do they have any sort of deployment
help so that the engineers are not too uncomfortable adding new
services or maintaining. The services is communication between. The services well-defined. The
communication may be in different ways. You might have a request response
architecture, which is standard. You might have a messaging queue, which
takes the quest and then sends it. And you might also have some sort of a
batch processing thing where you take 10 requests and send them together
to the next service. And finally, you need to take care of logging. This is more like. Making sure that the infrastructure
on microservices is fine. If you have all of the logs of these
services being condensed and put in a single place, what happens is
if a user has an issue, okay, let's say the user ID is 123, then all relevant logs
for that user request. Let's say the request ID it's 256. All of them can be pulled out from
this single repository in one shot, which makes debugging much easier
and also root cause analysis of any bug, much, much easier.
So go ahead with this. If, and when your team is convinced that
you need to move to microservices, here's a few things to keep in mind. The first one is that every
microservice needs to encapsulate the data that it is responsible for. So if you have profiles as your
microservice, all profile related, information should be with you. So
if a person says, get a profile, it's not like they can get the
profile from the payment service. Also that's impossible. The payment service has to ask you
for profile related information. Now it might store it locally
in a cache. That is okay. It's not taking real
responsibility for the cash. The expectation is that whenever
you need to update the cash, you need to make a network call
to the profile service. Okay? So you are the source of truth.
You are a single source of truth. Every component in your architecture
has to have a single source of truth when it comes to microservices, which only happens if you have
a dedicated data store for each service. The second thing to keep in mind is that
it's very tempting to take services and break them down into simpler
and simpler components. But the important thing to remember is
that what is the responsibility of this service? And when we are breaking it down, are we also separating our
responsibilities? For example, let's say the profile service needs to
take information from various external services like. Google, Facebook, and LinkedIn. These external services, they are giving
you information in the profile service. You might feel like, Hey, it's not the profile service
job to take this information. I will create a separate service here, which is going to be condensing all this
info from the three external services and giving me a single response. So the
profile service talks to this service, which is an intermediary, uh,
which talks to external services. And then the response is sent back.
Okay. This might seem like a good idea. But the question to ask is that, is this data being used by any service
except the provide service? No. When there is a change in
profile service requirements, is there a change in the service
requirement? Most likely. Yes. And is this business functionality is the, is the business requirement of this
separate from the profile service business requirement? No. So what should ideally happen then is
that this should be a component of the profile service. You can
make a library out of this. You can put it in the uterus
package. That's a separate thing. It shouldn't be separate from
this service though. Okay. The code base should not be separate. So that's the reason why this
should just be a part of profiles. So that's the second point, condensed business
responsibilities to a single place. Okay. Don't break it down just because
your engineering will get much simpler, uh, really do consider whether you need
to separate it further and further. The third important point is that can we
afford the infrastructure requirements for building a microservice architecture? The initial infra structure cost is high. The cost of logging, the cost of building a deployment
infrastructure of documentation. All of this is really not worth
it for a small team because you're essentially sacrificing some features
that you could have added during the time you started fixing all
the infrastructure issues. Okay? So ideally this is my
own hocus-pocus formula, but for a startup really going for
a microservice architecture is fine. If the total number of services that you
are handling per person is less than or equal to two. So this is for startups. One person is handling less than
equal to two, you know, microservices, basically it depends also on the
user scale, but for startups, this number is very flexible.
As for medium organizations, I would say one person should be
handling less than or equal to one service. So ideally you would have
two people handling the session, service, two people handling the payment service. And that way you avoid a single point
of failure. If someone is absent or, or something happens, you know,
they leave the organization, you still have one person who
is taking care of that service. So you're not entirely dependent,
even as a business on them. And for the large organization, basically
two people to four people per service. And the reason I say this is
because two people is good. There's no single point of failure,
but if it's a large service, you might need multiple people
working on different things. One person might be
doing a proof of concept. Two people might be on
doing the current features, which are required by the product team. And one person might be fixing bugs or
making sure that support is being taken care of. So four people for one
service is good. More than that, what happens is there's confusion. Like who's doing what
this service is too big. Maybe you need to break it
down into simpler pieces. I know I gave a lot of talk about
the business should be running, whether this is a microservice or not. But the fact is that this
is also engineering thing. So if this is getting too big, it's probably because the business
requirements are getting too big. And therefore you need to kind of break
that service down to separate pieces. So this has been a rather detailed
approach of how to move from one. Let's do microservices. If
you're having doubts on this, do let me know in the comments below, I have a discord server in which
you can come and, you know, post any of your doubts or even
your generic doubts that you have. There's different channels for that. I also have a website with a
system design video course, which is on interviewready.io. It
speaks about these concepts in detail. You can check it out if you are
looking to improve at system design. And of course, if you liked this
content, then subscribe to the channel, hit the like button and
I'll see you the next day. What is system design? System...what? Can get to the
next question? Can I get a hint? System design is the design
of websites using systems. System design? System Design Is the process of
defining components and interfaces with their interactions based on specified requirements. Next question?