Download System Design One Shot Full Course Subtitles & Captions | Learn Architecture
System Design One Shot Full Course
Telusko
SRT - Most compatible format for video players (VLC, media players, video editors)
VTT - Web Video Text Tracks for HTML5 video and browsers
TXT - Plain text with timestamps for easy reading and editing
Scroll to view all subtitles
Welcome back aliens. My name is Vin
Reddy, and in this video we'll talk
about system design. I know you are
waiting for a long time for a system
design course on Telesco, and finally we
are here. Now, in this course we are
going to understand different aspect of
system design. Now, why it is important?
When you go for the interviews, most of
the companies will ask you for system
design knowledge, and the question will
be based on that. Now, of course they
will not be saying this is a system
design round, but they will expect from
you to understand different concepts
here, and how will you solve a complex
problem. And let me give you a statement
which highlights this, and I have it
here. Anyone can write a code that
works. A system design is what makes it
work for million people at once, and
that's the power of system design. See,
when you write a code, of course when
you learn a language, you learn a
framework, you can build application.
That framework can I mean, the entire
project will work. The moment you deploy
it, the moment it is in production, and
when you have users, not just 10 users,
of course it will work for 10 users, and
it should work for 10 users, but the
moment you have 10 million users
accessing that at the same time, will it
work? That's the question. When you talk
about all your favorite applications, it
can be WhatsApp, YouTube, Instagram, or
Amazon for that matter, there are not
few users who are accessing that at one
time. There are millions of users, but
still if you can see, they work. So, how
do we do it? And that's where system
design plays a huge role. Now, to
understand this, we have we will be
going through these concepts. So, in
this particular video, we are going to
start with the basics of system design,
what is system design, what are
different components, data versus
compute intensive, and functional and
non-functional, and all this comes under
foundation. Now, once that is done,
we'll talk about how the communication
happens between different systems. So,
we'll focus on DNS, API, and of course
REST, which you might be knowing if you
have worked with Spring Boot or Fast or
Django and any web framework. Then we'll
move towards the data. Of course, when
you have a lot of users, how will you
store data? Not just their personal
data, but their activities. Uh and in
that we have different options like SQL
databases, no SQL databases, when to use
cache, and when to use SQL and no
non-SQL. Then, let's say your users are
growing day by day. How are you are
going to manage your application? And
that's where scaling and distribution
comes into picture.
In which we'll talk about load
balancers, replication, partitioning,
and the CAP theorem. That this will be
an interesting the CAP theorem. And
then, we'll talk about operations and
reliability. And the most important part
there becomes a fault-tolerant. What if
something goes wrong? Does the
application do have something to do
that? In which we'll talk about message
queues and monitoring as well. And of
course, we'll cover different examples
here to understand different concepts.
And the entire section or this part will
be taken by an amazing trainer, Akshay,
who is very good in explaining stuff.
And I hope you will enjoy the entire
part. And do share your thoughts in the
comment section. Don't keep it blank.
You what you like, what you don't like.
If you have any questions, do point it
there. And we'll try to answer them. And
if you enjoy this type of videos from
us, let me know in the comments as well.
That is our motivation. And I hope
you're motivated. Let's get started.
Akshay is all set.
>> [music]
>> Hello everyone. Welcome back to
Teleschool. My name is Akshay Agarwal.
And today, we are going to start the
system design course. In this course, we
are covering each and every topic which
includes in system design. So, let's
start with understanding why do we need
system design at all? In systems, we
have a lot of systems around us. If we
talk about human body only, we have
digestive system. And also, we have a
system. Along with this we have a lot of
systems, but these kind of systems are
pre-built. It means we have not created
them. We just discovered them with time
and we got to know about various
components which are required for us to
breathe or to digest our food. So, in
these systems as they are not built by
us, we can't actually change anything.
Maybe through surgery we can change some
of the other component, but not much.
But the kind of system we talk about in
IT industry are the systems which are
built by human or engineers like us
only.
So, in that there is a possibility that
we can pick our systems based on our
requirement and also based on our
requirement we can pick the components
which are required in our system and we
can basically improve our system based
on the request we are getting, based on
the load our system is managing, based
on the kind of traffic which we are
getting in our system. So, in system
design if we go through the words we
have two words here, right? One is
system and one is design. What is a
system? If we go through the definition,
system basically means there are a lot
of components. There can be more than
one components in that system. So, let
me write components. And those
components are working eventually to
solve a particular use case or maybe
multiple use cases, but the common
purpose of the application remains same.
So, that means if we write system is
equal to components plus common goal,
this sums up our definition of system.
Now, when we talk about design, there
are various components which we are
going to learn and there are various
common goals based on the requirement
analysis of different applications which
we are going to cover in this particular
series. But in order to start, let's not
dig too much into the technical details
in this video. Let's start from a very
basic. Let's say we have a requirement
of creating our own application or our
own bank. Let's say we have a bank named
Alien Bank because we are in Telesco,
why not? And in this bank, we are not
dealing about each and every operation.
Currently, we have a single operation,
which is we have a cash counter, and we
have a person sitting on a cash counter.
Let's name it as cashier. Okay, so here
we are ready with our cashier, who is on
our cash counter, and the requirement or
the flow is pretty simple. For the flow,
let's understand the concept of our
bank. So, we have multiple, let's say,
customers are here, and each customer
will come to our counter, either
withdraw or deposit some amount, get the
receipt from the cashier, and then move
forward. So, let's write it down as
customer flow cycle. So, in our customer
flow cycle, there are four steps,
basically. Customer first will visit the
counter, will come to the counter, then
the customer will either withdraw or
deposit some amount, take the receipt
from the cashier, and then the
transaction is done. The purpose of our
application is done. So, these are the
core functionality of our system. It is
very basic, very easy. You might have
seen this already in some of the banks.
So, we are building the same
architecture right now. The architecture
basically looks like this. Now, in order
to understand system design, what it
really is, and how we are going to
improve the working of our Alien Bank,
let's face some issues. We are going to
face five issues, and based on the
issues and solutions, we are going to
understand how system design looks like.
So, here comes our first issue, which is
the process is really slow. By slow,
what we meant is, let's say, our cashier
takes 10 minutes per customer. So, that
means we are serving only six customers
in 1-hour span. So, this is a huge
issue, because if the number of
customers will increase to a limit, and
also we have rush hour, in those cases,
our system will break, and we will be
not able to serve the customers rightly.
So, in order to improve this, let's
first focus on our cashier. So, let's
understand our system from the cashier's
point of view. So, basically, our
cashier is taking time to understand the
requirement. By requirement, I mean
whether the customer needs to deposit
the amount or customer needs to withdraw
the amount. They have to make this
interaction, which is time-consuming,
right? Now, once the requirement is
locked, whether the customer is going to
deposit the amount or withdraw the
amount, the cashier manually have to
count the cash. And then our cashier
will prepare a receipt, which will be
again given to our customer. So, these
are the time-consuming tasks for our
cashier. How can we improve the cashier
time? So, in order to improve the
working of our cashier, we have three
major issues. First is they are not able
to understand the requirement. Next is
they are counting the cash manually,
which is taking time. And again, they
have to prepare the receipt. So, these
are the issues which our cashier is
feeling, and we are trying to solve
these issues. Maybe we can train our
cashier in order to count the cash very
rapidly. Okay. Also, our cashier is also
responsible for maintaining the receipt.
So, we will improve the typing speed of
our cashier in order to make the receipt
very fast. So, the second thing is train
to type fast. So, with this, what we are
doing, we are not adding any resources
to our cashier. Simply, we are making
our cashier super fast, right? We are
improving the skills of our cashier,
which is required for them to maintain
this job. And let's say through this
training, the cashier is really improved
now.
He is or he or she is now taking, let's
say, 5 minutes in order to fulfill one
customer's need. So, this is a huge
improvement. By this, we are able to
improve the process by 50%. So, let's
say our second issue is that the
customers which our cashier used to
attend are increasing very fast, because
this is our alien bank, and it is
working very fastly, right? Growing very
fastly. So, now the issue two is our
customers count is increasing. This is
our issue two. In this case, what we
know so far? We know that our cashier we
can't improve our cashier performance
because it is now at its peak. So we
have to basically handle some or the
other components to our cashier in order
to make the work very fluently. So maybe
the desk on which our cashier is
sitting, we will increase the size of
desk. So next thing which we can do is
we will provide the cash counting
machine to our cashier so that the
manual cash counting time will get
reduced, right?
So we'll provide cash counting machine,
right? So with this also the time will
get reduced and our cashier will be able
to attend more customers. One more thing
we can do that is instead of coming to
counter and getting the requirement at
the real time, we can give a form in
advance to all customers so that they
can fill it and our interaction time
will get reduced, right? So our cashier
will now don't have to communicate each
and every request to our customers.
Uh they can simply see the form and
based on the form they will fill out the
thing. And now our cashier have cash
counting device also, so the process
will be fast. Let's say through these
processes, through enhancing our desk or
cash counter, the timing got reduced
from 5 minutes per customer to 3 minutes
per customer. This is also a huge
impactful thing. So now our cash counter
is capable of attending more customers
in lesser time. So that means even if
the customer count is increasing, we
will be able to process more customers
and enroll more customers into our Alien
bank. So this issue is also kind of
solved. Now let's move to the third
issue. The issue three is our customers
are still waiting to get their
application resolved, right? Currently,
what do we have? We have our cashier who
is upgraded to its maximum level. So, we
can't upgrade the cashier more. Also,
the desk on which it is sitting, the
cash counter, is also upgraded to its
maximum limit. So, we can't upgrade our
cash counter more. So, these two things
are pretty solid right now. We can't
improve it now. Now, the thing is, so if
we have 10 customers in place, that
means our 10th customer will have to
wait for 27 minutes in order to process
the three-minute work. So, that is a
huge drawback of our system right now.
And why that drawback is coming? Because
we have only single cash counter in our
system. So, in order to make the process
more feasible, now we have reached that
point that we have to add more cash
counters into our system.
So, let's add them. So, now we have our
cash counter one and cash counter two.
Now, at this point, we have added one
more counter, and things are pretty
solid right now. So, our customers will
eventually have two counters to go to,
and both of those counters will be able
to solve our issues. It feels good,
right? Now, we have two counters to
process. So, our customers will not have
to wait for longer time. They can either
go to counter one, or they can go to
counter two. But, let's say if first
customer is going to counter one, and
the counter one is able to process the
information, and they are maintaining
their own data. And similarly, our
second counter is also maintaining its
own data. And they are not synced. So,
this creates two issue, right? First
issue is, if in our system, the counter
two doesn't know anything about the
customer, that will create an issue
because they have a valid account in our
bank, and they should be able to proceed
their information through it. Now, the
second issue is this only. That from the
first account, they can also withdraw
the amount, and they will not update the
second counter. So, that means they can
again withdraw the amount from cash
counter two also. This will create an
issue of data discrepancy. That means
our data is not synced. So, the fourth
issue here is we need to have a
centralized database or central data
from which the cash counter one and cash
counter two will go and validate the
data and go and retrieve the data. If
the account is there for any customer
and the amount is also there, so the
customer one will also insert the cash
into the same account. And if the
counter two is getting withdrawal
request, they will also get the amount
out of the same account. So, in order to
fix this, we need to have a centralized
data. That means our counter will look
like this. This is our counter, let's
say two. This is our counter one. And
they will eventually connect to a
centralized database. And as it was
before, our customers are standing in a
queue waiting for their turn to come in
order to get the request. Now, after
solving all these case also, we have a
new issue in hand. Which is, let's say
the gate of our bank is here. This is
our alien bank. So, since the gate is
here, most of our customers are going to
the cash counter one only, where cash
counter two is sitting idle. Or maybe
processing lesser request, far lesser
request than the cash counter one. This
will again end up adding the wait time
to our customers. And again, we will be
end up handling lesser customers than
our potential. So, let's write that
down. This is our issue five, which is
underutilized counter. Now, in order to
solve this issue, we need to have a
middleman. Which will stand apart from
our counters. Let's say this is our
counter two. Again, this is our counter
one. And here are our customers. And now
our customers will not go to the counter
directly. They will first go to this
middleman. Then the middleman will check
how much load each counter is handling.
Suppose there are 10 customers at
counter one and only five customers at
counter two, then our middleman can
decide that next customer should go to
the counter two.
And the count will increase to six,
right? And the next customer will again
go to counter two, and the next customer
is again going to counter two only.
When the limit reach, let's say we have
11 customers here and 11 customers here.
And if then any new customer arrive,
they will again ask man where to go.
Let's say on some fine day our counter
one is not working. That means our
middleman will know about this and will
eventually send all the customers to
counter two until the counter one is
getting fixed. So, let's end this
example here at this particular point
and see what have we learned. Through
this story, through this single story
and five issues, I have tried to capture
multiple concepts of system design. So,
the first concept which we discussed is
designing a system, that is for sure.
Ultimately, what design we do have here?
We have one cashier and the other
cashier. Each cashier is having their
own counter. So, this is our counter
two, maybe this is our counter one. We
have a number of customers waiting for
us. Also, we have a middleman now. With
that, we also have a common database,
okay? So, this database is nothing but
centralized database. The customers
which are coming to our bank is nothing
but requests. And if they are standing
in a queue, we can say they are creating
a traffic, okay? So, these are the
traffic which we are going to handle.
Now, all the requests or all the traffic
is coming through a load balancer, the
middleman. So, this is nothing but our
load balancer. So, from the load
balancers, all the requests are coming
to either of the cash counter. So, we
can say that our cash counter is nothing
but servers. And the person sitting
there doing the work is nothing but our
application code. Now, let's see the
system again through the system design
point of view. So, the first issue which
we have was our process is slow. So, in
order to solve that, we improved our
code quality, right? So, first thing
which we do in our systems also, we
improve our code quality. So, this is
where our LLD will come and this is
where our DSA will come. Suppose a
particular loop is taking certain time,
we can reduce that loop or we can change
that loop to some for each function or
some other way in order to process that
information fast. So, while solving the
issue two, we increase the size of our
table, we added some functionality, we
added this cash counter. That means we
upgraded our server. So, in order to
upgrade our server, this term is called
vertical scaling. In vertical scaling,
we don't add multiple servers, we
basically update our current server
only. And again, the current server
updation have a particular limit. After
that limit, you can't upgrade your
system. So, then comes the issue third,
which is our customers need to wait for
the single server to respond. So, in
this case, we added more servers. So, in
this scaling, we added more server that
is called horizontal scaling. So, after
having multiple servers, we need to
maintain the data at the common point.
So, that's why we added databases. And
in order to add a common database, we
basically can move to distributed
database architecture or can move to a
centralized approach of handling that
database. So, this is nothing but
centralized database. So, after having
centralized database, again the issue
comes where we don't know how to handle
multiple requests. That means our
requests are again going to one counter
only or one server only. Now that we
know they are going to one server only
and the other server is underutilized.
So, what we did, we added a middleman.
Our middleman is no one but our load
balancer. Our load balancer basically do
two things. They will check whether our
servers are healthy or not and based on
that, they will distribute the request
equally into multiple servers. So, these
are all the concepts which we discovered
through this particular example. So, if
we think about the applications we are
using in our day-to-day life, we are
using WhatsApp, we are using maybe
Snapchat, we are using Instagram, we are
using YouTube, we are using LinkedIn, we
are using Netflix, Amazon, maybe
Flipkart. All of the applications, if we
think about it, are showing us the data
either in the form of images or in
videos, in audios or in text. So, we can
say through a large lens, the data
consist of these four kind of
information. And all of the applications
which we are using in our day-to-day
life consist of these data's only. So,
we can say that in the core of every
system, we have data and we are then
finding ways to make it available to the
users in the way they are expecting it.
So, in the center, as we discussed, we
have data. Data can be of various form.
It can be image, video, audio or text.
Now, if we think about data, it is not
like we are seeing the data once only.
We have to see the data and also while
storing also, we need to store the large
amount of data. Now, in order to store
the data, we do have databases. So,
databases are basically our first
component of system design. What is
functionality of databases? Pretty
simple. We need to store our data and
whenever we want to retrieve some data,
we need to get the data from our
databases only. They are represented by
this cylindrical figure. Databases can
be of multiple ways. It can be
categorized into no sequel or sequel.
Now, there are various kind of databases
in both of these categories. In sequel
also, we have various databases from
which we can select which database we
are going to use. And similarly, in no
sequel also, we have various kinds of
database from which we can pick which
database we need for our application
right now. But, the core remains seems
that we are saving our data in some or
the other database. We will discuss
about sequel and no sequel databases in
the coming videos. That's why I'm not
going to deep into this at this moment.
Let's think about the scenario where you
and every user on the planet knows the
queries of database, knows how the
tables are structured if we are talking
about sequel, or how the documents or
nodes are connected if we are talking
about no sequel. If we talk about both
of these scenarios, if user, the end
user, already know the database query
languages and know how to deal with
different kind of data, in that case, we
might not need any application if you
think about it. We will simply go to our
database, or the database will be
accessible throughout every application.
Suppose we are seeing the LinkedIn, but
on LinkedIn we will see an interface on
which we will write our query, and the
data will be fetched to us. That will be
an hectic task. But, if users know about
that, and if users start exploring that,
that will be easier, right? In that
case, we don't need any application
layer in between us, and in that case,
we don't need any client-side
application also between us. We simply
will see a database, query it, and get
the results, right? In that case, what
will happen? Each query have to be
managed through the users only. And
these queries, when I talk about large
systems, let's say we are talking about
LinkedIn, there can be multiple tables
through which our data is curating and
coming to us. Every user can't do it,
right? That's why we have different
layer in front of our database, which is
our application code. So, in application
code, what we do is we hide the
complexity of dealing with databases,
different tables, different documents,
and we give the endpoints to our
application or to the world so that they
can access the kind of information they
are looking for. For that, we create
APIs or we can say we create endpoints.
There can be multiple endpoints based on
different features, based on different
operations. So, through endpoints, we
communicate to our application, which
will again communicate to our databases
to get the data we are trying to get.
There can be various operations, like we
can insert some data, we can update some
data, we can retrieve some data, we can
delete some data based on our request.
So, the thing becomes little easier to
us. Now, we don't have to deal with all
the database tables, but now we have
assigned endpoints through which we can
do the work which we want to do. And
endpoints are pretty simple.
So, in order to get some data, we have a
get endpoint. Let's say https, and here
comes our Teleschool. So, this URL or
this endpoint can be used to fetch all
the students which are there in our
Teleschool environment. But then, what
we are doing? By introducing application
code, we are moving our logic and data
separately. That means we need some kind
of connections between these two. In
which we can connect through IP
addresses, we can connect through some
HTTP protocols, or we can connect
through some TCP protocol. There are
many ways of connecting the database
from the application code and getting
the data which we want. So, in order to
show the APIs or in order to interact
with the APIs, we have to know what is
JSON and how we are going to send the
data to our APIs and how we are going to
fetch the data from our API.
In this level also, if we know how to
handle JSON, if we know how to handle
various operations through which
endpoint, it will make our life little
easier than accessing the databases,
right? So, in that case, we don't need a
front end if we know how to hit the
endpoints through which we'll get the
data. But, for our normal users, for
other users of any applications, this is
also a tedious task. So, in order to
make this easier, we have a different
layer between our system that is our
client application. Client applications
are nothing but the applications through
which we are interacting to the
database, through which we are getting
those databases. So, our client
applications, be it a mobile
application, be it any web application,
be it any ATM machine for that matter,
they are connected with the application
code, and further, the data is being
consumed by us. So, again, in order to
connect the application layer and the
client code, we again need some kind of
communication between them. We either
can go to the same HTTP or TCP or maybe
IP. Now, we have our application ready
in our hand and we can use it. So, if I
draw it like we used to draw it, this is
represented by our client, either a
desktop or a mobile device. Now, they
are sending queries to our application
code, and our application code is
further getting the data from database.
Now, for our client to communicate with
our application code, we need to put our
application code on any server. And now,
if we think about it, our application
code is already exposing the APIs to our
client. That means, it can also expose
the APIs, or any other application can
also use our application codes through
our APIs and do the work which is
needed. So, it can be connected to any
other server also, which will contain
their application code. And this will
communicate with our data through our
application code. For every query which
we are making, we are going to our
database, and from that we are getting
the data which we are trying to get. So,
if we think about it, most of the
communications will start from the
client side, and they will come to our
application code through which we will
get the data from the database. This is
pretty much the easy application or the
applications which we create on our
college projects look like. Either a
to-do application or a simple chatting
application will look like this. Now, in
the current scenario, what we are doing
with this kind of architecture is every
client is going to ask application code
for some or the other information, and
to fetch the data, our application code
needs to get the data from the database
only. We don't have any other option. In
order to make the files accessible to
our server faster, because the
database's calls are heavy, which will
take a lot of time, let's say, if a
database query is finding the columns
from 12 tables, it is going to take
time, right? Now, in order to make the
frequently used data accessible faster,
we have a different layer, which is
called cache. When we are going to put
any data into our cache, and when we are
supposed to remove the data. There are
different strategies we are going to
cover that also in the upcoming videos,
but for now, let's see, this is our
cache, and all the frequently used data
will be stored here. So, that we don't
have to call to our database, and they
can be easily accessible through our
cache only, which will make our process
slightly faster. So, this is our fourth
component of our system, which is cache.
Now, let's move forward. Let's say our
application is big, is having multiple
servers. In that case, we may have some
client or this client, either the mobile
application or the web view, and we are
getting the data from multiple servers.
Let's say this is server one or this is
server two. Now, when we have two
servers or multiple servers, our client
have to decide where to go. From where
do we fetch the information? Now, in
order to take this control, we have a
load balancer in the middle, which will
take care of each and every request and
which will take care of each and every
connections of the server. So, our load
balancers are responsible for handling
two tasks. First, they will check
whether the server is healthy or not.
And second one, they will divide the
request for each servers equally. This
is what our fifth component looks like.
Now, let's come to our next component,
which is messaging queue. So, in order
to understand message queue, let's first
understand that in order to process one
operation, there can be multiple task
into that operation, right? Let's say we
are ordering something. So, when we are
ordering, we are going to do multiple
tasks, right? We are first creating an
inventory update. Next is we are going
to process the order also. We are going
to talk to the vendor who is going to
take the delivery. So, we are going to
handle delivery. And then, we are also
trying to send you the information, the
notifications that your order is placed
successfully. Don't worry about it. So,
that means we are going to handle the
mail service or the SMS service also.
Now, in order to handle multiple
services like this, we can't wait for
every application to respond back. There
are two kind of applications basically.
First is, let's say this is an
application and this is another
application. Let's say this is SMS
application and this is our order
application or microservice for that
matter. Now, whenever an order is
placed, it is going to speak to the SMS
service or SMS application to send the
message to the user that your order is
placed successfully. Now, there can be
two ways of handling this. First way is,
whenever the SMS is sent, they will
notify the order service or the order
application back that we have sent your
message done. Or there can be different
way of handling it that from our order
service, we simply say that okay, this
is our order information. Please send
the message to this number and we are
done. We will not wait for the response.
We will move forward with our
application and with different orders.
So, the kind of requests in which we are
waiting for any confirmation or any
feedback from the other service are
called synchronous calls. And the kind
of service in which we will simply put
down the service and we are not waiting
for any confirmation, we will move
forward to do our task. Those are called
asynchronous services. Don't worry about
this if you don't understand it now. We
are going to dissect each and every
component in details in the further
coming videos. So, for asynchronous kind
of services, what we can do, we can
simply push our notification or push our
request to another service and move
forward. So, in those kinds of services,
we have a message queue or message
broker in middle. What it will do, we
are having our order service here. It
will put multiple request or can put a
request time to time into this message
queue. And then all the requests which
our order is processing through message
queue, they will not take care of it
anymore. Our message queues will take
care of it. They will connect with our
SMS service or SMS applications and send
the request one by one. And they will
take care of these all operations. So,
our message queue is like a broker who
will take the request from one
application, store inside it. They will
take care of these applications. They
will take care of the retries or if any
request is failing, they will take care
of it. Maybe they will communicate to
our order application in the end or in
the end of each day, we will send some
notification, some batch processes to
our order application in order to show
that which requests are fulfilled and
which are not fulfilled. So, in short,
our messages queues are doing two work
here. They are storing each and every
request which are coming from various
other services or various other
applications for that matter. They are
storing it and they are taking care of
those requests. They are sending those
requests finally to SMS application or
service and they are taking charge that
okay, my first service or my first
request is being processed. Nice. Now, I
will send the next request. Now, I will
send the next request and further on. If
it is failed, there are various
mechanisms how messages queues work and
how they bisect and dissect each and
every request and make sure that they
will provide the latest status of each
request. And in those kinds of
environment where we have multiple
microservices, in those cases message
queues plays a vital role in between
them. And with that, let's move to our
final component which is monitoring and
logs. In monitoring and logs, what do we
do? As we know now, we have different
components in our architecture, we have
a client system here.
We may have a mobile application again
which is connecting through an API to
our load balancer
which is again further connected to
either server one or server two.
Our servers are the area in which we
have our application code and then they
may be connected to single database or
multiple databases and those databases
can also communicate with each other in
order to maintain the data. And also,
let's say our application is also using
some third-party application for which
we are using message queues. Our message
queues are denoted by this. Now, this is
our architecture. We have so many
components.
So, it is very important for us to
monitor those components. To monitor
whether our load balancer is working
finely or not. To manage whether our
application code does have any error or
not. And if there is an error, we need
to know how to solve it. We need to know
the complete stack trace of that
particular error. We need to know how to
reproduce those errors on our local
system in order to fix them. And also,
while working with the applications, we
know that for every each and now, we
have multiple features which are being
attached to our applications. So, we
also need to monitor while adding one
more feature to our application, whether
any other feature is impacted or not, or
it is failing or not. So, in order to do
that, we have a lot of monitoring tools
and also logs to check our system. There
is a complete testing department in our
team also, who takes care of these
things. This is one of the vital role in
our application. So, these are most of
the common components which are used in
system design. Whenever we think about
any application or designing any
application, we suddenly jump to the
tools which are used in that
application. We start creating diagrams
that this is our client, this is our
database, this is how our data is going
to flow, this is how we add cache maybe.
So, these all things we start doing
without noticing a single thing, that
is, how is our application going to
work?
What is this application? What are the
limitations of this application? In
system design, there is a smart way of
doing that. First question you need to
ask yourself before diving into the
solutions is, what is this application?
What is the type of this application? Is
it a data intensive application or a
compute intensive application? With this
common differentiation, you will be able
to save a lot of cost to your system
design, as well as you will be able to
handle the task properly into your
system. Let's say, we have two
applications. In both of these
application, there are the same number
of users. With that, the network on
which both of the applications are
working are also pretty much same. Now,
let's put a scenario that our system or
the application which we are working on
is facing latency. Now, what is latency?
Latency means our system is taking time
to respond. There are various ways of
handling this issue, of fixing the
latency issue. We can add multiple
databases, we can add different caching
layers, we can update the caching
mechanism, or we can update
or the CPU powers. Now, on which vector
we are going to do this changes defines
how well we are going to solve this
issue. So, now there are two type of
applications as I discussed. One is data
intensive application and one is compute
intensive application. Let's understand
them one by one. The basic difference on
which data intensive application is
different from a compute intensive
application is that in data intensive
application our core focus is on data.
Now, for this data we need to have
multiple operations, right? We need to
store the data, plus we need to gather
the data, we need to move the data time
to time. That means we need to keep
updating the data because new data is
entering. And also, while new data is
entering we can also, right, we need to
add a lot of data.
We can take example of any application
which can be Instagram because on
Instagram we see a lot of content and we
post a lot of content. So, that is a
data intensive application where the
primary focus is on gathering the data,
is on showing the data, is on the data
you are posting. But, the focus is not
on how the data will be calculated. The
calculation part is pretty solid. We
just need to move the data from our
databases to the client applications and
we are sorted. So, in these kind of
systems the data mainly resides in the
database. So, first issue can be the
database response is low. Another is,
since we are using network calls here
and there, that means our network calls
are also bulky or we need to optimize
them. The third can be our server itself
that our server configuration is pretty
low, that's why we are not able to get
the data faster. So, all in all, in
data-intensive applications, we are not
blaming the client to upgrade their CPU,
we are blaming our circle, our database
calls, our network calls, our server
configuration in order to get the data
fast. Most of the applications in which
you work on are data-intensive
application. That's why we use terms
like cache enhancement, shredding, and
through all of those things we will be
able to solve this issue. Now, let me
also write some common examples of this.
So, the common examples here are
Instagram feed where we see a lot of
data as we discussed earlier. In
WhatsApp messages also, there is a high
amount of data because we are not only
taking care of one chat, we are taking
care of entire chat. The count of chats
or the count of messages WhatsApp deal
with is around 2 to 10 million messages
per day. So, this is also a heavy
data-intensive application. Now, there
are bank transactions, analytic
dashboard, and log process system as
well. In all these application, the
primary goal is to serve the data from
database to our client system faster.
There is not much calculation required
for them to show on the client machine.
Now, based on the data-intensive
application, what are the worries of a
data-intensive application? The first
worry is how fast can we read the data?
The second point is how safely are we
going to store the data? The third
point, as we all know, a lot of users
are using our application, so how many
users can use the same data
simultaneously? The next and one of the
most important worry of these kind of
application is what if any server dies?
What if any server breaks? What if any
network call breaks? What if any
database machine breaks down? So, in
those cases, how we are going to handle
the data? So, these are the most common
worries of the data intensive
applications. And now, in order to solve
them, we don't go to our client system.
We talk about the components on which
these processes lies. And those are our
databases, caching, replication, maybe
data sharding, or it can be solved
through data consistency. So, these are
all the components or the terms we use
in order to improve our data intensive
application. Don't worry about these
terms if you don't know them yet. We are
going to cover each and every component
in details in the coming videos. So, I
hope data intensive applications are
pretty clear up to now. But, for the
sake of example, we are also going to
take one more example. Now, think about
Instagram feed. We are not solving
Instagram feed issue through any
mathematical equations. We just have to
gather a lot of data and show you that
data. So, what we don't do here, we
don't do any complex maths. What we do
then? We normally fetch the posts. After
fetching the post, we sort them through
time or relevance. We show a lot of
images or videos. And according to those
content, we normally do some operations,
maybe like or commenting or sharing. So,
I'm writing that. So, this is all the
operations loosely we have on the
Instagram feed. Now, what is the common
challenge which Instagram is facing
daily? That is we we have a lot of
content. We have millions of users and
million of content which we have to
handle. So, let me write that down. In
other words, we can also say that
million of users are reading and writing
at the same time. So, with this
challenge, Instagram still needs to
scale, right? How does Instagram scale?
If we think about this, Instagram adds
multiple databases in order to store the
data. And also, Instagram uses
aggressive caching in order to store or
get the data fast. Now, we also know
that Instagram heavily depends on the
images and the video content form. So,
in order to handle them, we can't simply
store those kind of data into our
databases directly. For that, in order
to fetch them faster, we need to have
certain CDN in place. And in databases,
we will only store the location of that
particular file which we are going to
fetch through the CDN. Now, think about
this. In order to fix the latency issue
on Instagram or in order to help
Instagram scale, we hardly touch the CPU
or we hardly touch any GPU. We only
touch the data or the components which
are associated with them. Because the
issue here is not the CPU, but the data
movements between the components. Now,
this is all about data-intensive
applications. Let's now focus on the
compute-intensive applications. Now, the
compute-intensive application is exactly
opposite of a data-intensive
application. Here, the amount of data
which we are retrieving from databases
are pretty much low, but the
calculations we need to perform are
really heavy. So, instead of putting our
focus on database caching, replication,
sharding maybe, we move our focus from
there to CPU and GPUs. So, let me write
down the challenge now. So, we can
safely say that here our systems are
compute-bound or we can say CPU or
GPU-bound. Let me take some examples of
this. The most common example can be
image processing, video rendering. The
machine learning model training can also
be a good example of this. Also, we can
talk about simulation and cryptography.
Now, in all these examples, the data
which we are getting from the database
are in a smaller level only, but the
kind of processing we need to do in
order to show these data to user is
heavy. That's why they come under the
category of compute intensive
applications. Now, let's discuss about
the worries of a computer intensive
application. The first worry is pretty
simple, that is how fast can we do the
calculation or how fast can we compute?
The second worry can be can we do
something some processes in parallel in
order to show the data faster to the
user. You may have seen a lot of systems
in which in parallel the image is being
processed and you are able to move
further with the application. Let the
image process and the meanwhile you are
moving to the other features of the
application. The next issue can be how
can we reduce the computational cost?
And also as a system designer, we can
also think about can we use GPU instead
of CPU? So, these are the common worries
of a computer intensive application
where the data is not much, but the
processing is the king. Let me also take
a good example of a computer intensive
application. So, in order to create a
simulator machine, it is very important
for the simulator to work exactly how
the actual machine works. So, think
about a scenario that our country is
hiring a lot of pilots every year and we
can't spend too much on the actual
aircrafts when the pilot doesn't know
how to ride it or how to fly it.
In order to train them, we need to give
them simulators machines and on which
they train themself first and then sit
on the actual plane. So, now in
simulation machine, our common worries
or the task which we are going to have
is can we do anything in parallel again?
Can we use GPU instead of CPU? Again,
how can we reduce the cost of our
simulator? Also, we need to find a way
to gather a lot of good algorithms in
order to do the task frequently. Now, at
this point I think we are very clear on
how our data intensive applications are
different from computer intensive
applications and why we need to put our
focus on computation on different
algorithms on GPU or CPU in order to
make a computer intensive application
works because the data is very low and
in data intensive application if we
start focusing on GPU and CPU there will
not be any big changes because the issue
lies in the database network calls
caching algorithms or maybe server. So
in order to fix them we need to put our
effort into the right category into the
right components so that our application
works seamlessly. And why this is
important? Because if we put our efforts
into the wrong components our components
are not free they are going to cost us
money and if we put the money in the
wrong place and not getting any help in
order to solve our issue it is going to
be a bad system design for the entire
game. Now when we talk about data
intensive or computer intensive
applications we often think that these
two are very separate applications. But
in today's time we live in the
environment of multiple applications and
each application performs multiple
tasks. So that means our data
intensiveness or the computer
intensiveness of the application can
also depend on the feature we are
working in. For example we have YouTube
right? YouTube is data intensive for
serving the videos. There are a lot of
videos in YouTube environment and you
get the videos and we can say that it is
computer intensive when it comes to the
recommendation. Because in order to get
the recommendations we have to get what
you are watching right now. So I think
it is pretty sorted now that in order to
fix a particular issue you need to first
think whether the issue which we are
facing is computer intensive or data
intensive and then you get into the
components and fix that. There is a
trick to understand whether the feature
is data intensive or compute intensive.
That is, if the time is lost in data
movement, probably it is data intensive
application. Or if the time is lost in
the computation, it is probably a
compute intensive feature or the task.
This one distinctions save you a lot of
money, time, and complexity. In order to
discuss our requirements, we divide the
requirements into two categories. One is
functional requirement and the another
one is non-functional requirement. So,
let's go to our screen and let's discuss
this. Functional requirement says,
"Please define all the points which you
are building, all the features which you
are building, all the working which you
are building." That means, if we define
every feature that comes under the
functional requirement. So, let's
understand functional requirement by
taking an example of any e-commerce
application, let's say Amazon. So, what
can be the functional requirements of
Amazon application? That means, we are
defining each and every feature which we
see on Amazon. So, let's say on Amazon
application, a user can register
themself. User should also be able to
log in. So, let's write that. After
login, user should be able to see the
products. Also, user can search the
products or filter them. Let's write the
searching and filtering into two parts.
So, search the products and user
can also filter the products. After
filtering, searching, user should be
able to add any product to the cart.
After adding any product to the cart,
user should be able to get some
promotions or get some discounts, right?
So, they should be able to apply the
coupon codes to get the discount. And
once all this done, user should be able
to place the order. After placing the
order, user should be able to do the
payments, maybe. And once the item is
placed, once the order is placed, user
should be able to track that order. So,
all of these points are the functional
requirements of Amazon or any e-commerce
application for that matter. In which we
define all the functionalities, all the
actions which user can take, all the
working of the application is defined
under functional requirement. So, if we
have to write this, what is functional
requirement again? Functional
requirements means all the features
which you are going to have in your
application are the functional
requirements. Now, let's move forward to
the non-functional requirements. For
non-functional requirements also, let's
start with the example of Amazon only.
Let's say the first non-functional
requirement is that on our Amazon site,
we have
approximately 1 million users. So, that
means our system should be able to
handle 1 million daily active users.
Now, in order to give our users a good
experience, we can say that the response
time should be less. But, in
non-functional requirements, we have to
define how less.
So, let's say for Amazon application,
the response time should be less than
200 milliseconds for each request. Now,
our application is built and is running,
that means our application can't handle
failure. But, that is not possible,
right? So, we should define up to how
much is our availability of our system.
That means for how much time our system
will be available. That are defined
under SLAs and SLOs. So, we have to
define them. That for 1 year, our system
downtime should be this much amount
only. And for 99.9%
time, our system should be up. That is
defined under availability. After
availability, we don't want our data to
be flowing easily, so we want to encrypt
our data. And let's say on any sale day,
let's say Black Friday sale or Diwali
sale or Holi sale, in those times our
normal users can go up to 10x. So, our
system should be able to handle that
much traffic also. So, let's write that
down. With this, our system should be
also able to handle the faults. Because
there are going to be faults in the
system. No application is perfect so
far. Every system have their own faults,
have their own downtime. But we need to
see how can we track them and how can we
fix them as fast as possible. So, that
is we need to make our system fault
tolerant. So, with this example of
Amazon, we get to know that our
functional requirement are the features
of the system that we can say what our
system is going to do. And with
non-functional requirements, we define
how our system is going to perform. So,
these are the specific non-functional
requirements for Amazon. If we have to
write it in a generic way, there are
some generic terms which we can write.
So, we can talk about scalability. Let's
say our current configuration of server
is reaching to a point where it is not
able to handle the kind of traffic it is
getting. So, now in order to scale, will
you scale it horizontally or vertically?
That will be taken care under
non-functional requirements. Apart from
that, as we have discussed, availability
of every system will be defined under
the non-functional. As we have already
discussed, that means our system uptime
will be calculated here.
Which is defined under SLAs and SLOs.
So, in these agreements, it is already
defined that, let's say we are using
Amazon server in order to deploy our
application, then Amazon will give us
some contract that we will be down up to
this time. And apart from that, you will
not see any issues. Now, in those cases,
if we see any issues, let's say for a
day, Amazon says that we will be down
maybe for 5 minutes maximum. But then,
if Amazon fails to keep that promise or
that agreement, the companies which are
using the Amazon service can sue them.
Because the Amazon services have given
us the SLA's in writing that the
services will not be down after certain
point. So, availability plays a huge
concern there. Next, we have
reliability. In reliability, we can say
that our system should be reliable. That
means there should be no data loss in
our system. After reliability, comes the
performance. Under performance, we are
going to define how our system is going
to work, how much latency can we feel in
the system. What is our P95? What is our
P90? What is our P99? These all things
are defined under performance. So, all
the words which I have said in this
particular video, we are going to cover
each and every topic in details in the
coming videos. So, don't worry about
this if you don't get it now. After
performance, we can jump to security. In
security, we can have features like
authentication, authorization, and
encryption. With security, we are also
dealing with a lot of code. That means
we can say our code should be in perfect
modules so that each code or each chunk
of code can use different APIs or
different modules in order to work in
efficient way. After this, we have last
but not the least requirement, that is
observability. Even if our code is
pushed to production, there are a lot of
use cases which are handled after that.
Because we don't know the exact behavior
of users, that how they are going to use
it. So, we need to keep track of all the
monitoring tools, all the tools which
are going to track the user behavior on
our application. So that we can improve
our system and also we will be able to
track if there are any bugs and solve
them. So, let me write monitoring and
logging. So, this is all about
functional and non-functional
requirements. I hope you all get it. But
in order to completely get it, we all go
through a lot of applications on a
day-to-day basis, right? We may be
scrolling through Instagram, maybe
watching YouTube, maybe watching
Netflix, or Amazon Prime, or purchasing
anything from Flipkart, Amazon, or any
other application e-commerce platform,
or we may be scrolling through our
WhatsApp messages. Now, I want you,
while using your application, just sit
back for a few minutes and think about
all the functional features which you
are working, or all the functional
requirements which you are using, and
all the non-functional requirements
which the app must have configured or
thought of while creating that
applications. Also, comment down the
application on which you worked on, and
write down three to four functional and
non-functional requirements. That will
help you and me also in order to
understand that we are learning on a
similar pace.
How does our browser know which webpage
to hit? Do they know by domain name, or
do they get these things through IP
addresses?
Let's find out. So, whenever on our
browser or on our machine, whenever we
write any address, let's say
telesco.com, it is going to redirect us
to the telesco page, which is our
homepage. Maybe some banners here, maybe
some courses section here.
It is like this only. Now, how do our
browser figure out which page to show?
Because, as humans, we communicate
through names, but systems don't
communicate through names. In order to
establish the communication between one
system to another system, we need IP
addresses. So, that means there should
be some place in between or some system
in between our browser or our OS through
which we are going to get the correct IP
addresses of each and every site. So, we
will send telesco.com, and in return we
will get some IP addresses. So, this can
be the IP address of telesco. I'm not
exactly sure about the IP address, but
yeah. Like this, our DNS works.
So, DNS basically stands for domain name
system. Domain means any specific URL or
any specific domain. Domain is this
only, telesco.com. There can be multiple
domains, telesco.net, google.com,
facebook.com, whatsapp.com, .web I
think. But yeah, you get the point.
These all things are domain. And what is
subdomain? If I write any subdomain,
let's say docs.telesco.com
or any other subdomain, let's say
course. So, they both are subdomains of
telesco.com. Where telesco.com acts as
an umbrella and under which we can
create multiple subdomains if and when
required. So, these are the domain and
subdomains. But mind it, the machines,
the computers doesn't communicate with
each other through these domain names.
So, they need IP addresses. Let's figure
out ways on which our system can handle
the IP addresses. Let's say we are
building a browser. Why do we need DNS?
Why do we need another system
for maintaining the domains? We can
basically install or store all the
domain name list on our browser only.
Now, is this even possible? Let's say if
we have only two or three websites,
maybe 10 websites, we can store their
names, even 100 also. But the current
number of domains which exist in our
world is more than 350 million. And as a
browser, browser doesn't know which
sites I'm going to use, whether I'm
going to use Stack Overflow one day and
Gmail the other. So, we can't store all
the 350 plus domains into our browser.
That will crash our system. So, two
reasons because of which we can't store
the entire domain list on our browser
are first thing is it will get heavier.
And to store such amount of information,
we need a high storage browser. So, that
will also impact the performance of the
system. Now, the other point is what if
the IP changes after some time? What if,
let's say, I am running any site,
teleschool.com, I have purchased my
domain from maybe GoDaddy, and tomorrow
I decide to discontinue my service from
GoDaddy, and I'll move to Google
Domains. So, I'll purchase or renew the
domain from there. In that case, my IP
can be changed. And if it restores, I
need to reassure that in all the
browsers where teleschool.com is
running, I need to update them. I need
to send them some update. So, through
this we can estimate that it can't be
stored in one browser. And also, it
can't be stored in a single server,
also, because it will also get heavier.
There are more than 350 million domains.
That means, if we are going to store it
in a tabular manner, so the here will be
the domain name, and the corresponding
IP addresses accordingly. So, here we
will have any domain name such as
google.com, and here we will have the IP
address, 1.2.3.4,
for example.
So, by this, we will create the entire
list. This is not possible for a single
machine to handle, because if that
machine breaks, then the entire system,
the entire internet will break. Anyone
in the world will not be able to use any
internet services or any web pages for
that matter. No APIs will hit, because
it all depends on the DNS. So, one thing
is sure, we need a certain kind of
system in order to fulfill this
requirement. That's why we have one of
the most beautifully designed system,
DNS. Let's start from the high level.
So, this is our machine, which is going
to use some internet service provider,
and under this service provider, we have
something called as DNS resolver. So,
this DNS resolver is responsible for us
to getting the correct IP of any
websites or any domain which we are
trying to process. In order to
understand this clearly, let me take
this and put it in a side, so that I can
draw more things onto our screen. So,
the first call it is going to make is to
our root server. Now, there are 13 root
servers
in this entire world. That means there
are 13 companies who own 13 web servers
in this entire world. They are not
physically 13, but they are categorized
into 13. So, that means out of these 13,
we are going to hit one of them and get
the response. These root servers are
typically named from A to M like this.
Again, from this A to M, they are owned
from various companies. So, you can see
the complete list of the root servers
with the companies which own that root
servers on the screen. You don't have to
remember all of them. You just have to
see and understand that these are the
service providers of the root servers
from which we are going to get some
information in order to process our
domain. Now, let's come back to screen.
As discussed, we were searching for
telesco.com. Also, I can remove this
now. Now, when we are searching for
telesco.com, the root server doesn't
know anything about telesco.com, but it
knows about the TLDs which are top level
domains. What is top level domain? If I
talk about .com,
this is our top level domain. .com,
.net, .gov, .in, .uk, .us, .education
maybe .edu, we use them. These all
domains are the top level domains of any
website. So, that means if we need to
find out where telesco.com is, we first
need to know which server is handling
all the .coms. So, in order to do that,
our root server will give the response
that okay, you can go to one of the TLDs
which is handling the top level domain
for .com and the root server will return
the IP address of that. Maybe this is
the IP address and from now, we know
that we are going to hit any TLD,
top-level domain for a .com. Now, from
this TLD, we are again not going to get
the complete IP address of the site. We
are going to get the proper server or
the name server or the authoritative
servers which are managing the all the
IP addresses for our domains. Let's say
this is the IP address of our
authoritative name server. And from
this, we are going to make another call
which are our authoritative name
servers. And from here, we are going to
actually get where our telesco.com
resides, the IP address, which was
19283841.
And once this is captured through our
browser, the IP, then it is going to
make the call to telesco.com server and
it is going to get the web page which is
desired for. I get it this can be a
little confusing at start, so let me
reiterate it for once.
So, whenever we click on any site,
whenever we want to find any site, let
it be telesco.com, it is first going to
our service provider, internet service
provider. Also, you can see uh
it can go through router and router can
also have DNS resolver. So, from
internet service provider which have DNS
resolver, this component is going to
resolve all our queries for us and
ultimately will give us a perfectly fine
working IP address for telesco.com or
any other site for that matter. So, the
first step is it will go to the root
servers. What is root servers? There are
13 companies who own these root servers
who doesn't know the IP address of your
site directly, but knows which TLD to
follow. So, from root server, it is
going to check what is your
TLD, top-level domain. And in this case,
it is .com. Now, as it is dot com it is
going to get the IP address of the TLD
which is handling the dot com domain. So
after this first call now we are going
to call the TLD which we get from the
root server and from this also we are
not going to get the complete IP address
of telesco. We are going to get on which
name server we are going to hit to get
the complete IP address of telesco.com.
So from here we are going to get the
authoritative name servers IP and
accordingly we are going to hit our
third and final call to our
authoritative name servers. Our
authoritative name servers are mostly
can be configured in GoDaddy or
Hostinger or any other service providers
in your current application. And from
these authoritative name servers we are
going to get the IP address of
telesco.com. Now in order to click one
side we have to do these three
operations. This can be heavy, right? So
this is only done first time and the
next time when you click on anything it
basically takes the value from cache.
Now cache can be stored in three
locations here or more than three if you
think about it, but three are definite
locations. The first is the DNS resolver
can have the cache to have all the
common IP addresses which we are going
to take or the all the common domains
which we are trying to hit. It can store
it here. Also on our system we have two
things. One is OS and one is browser. In
both of these areas we can basically add
that domain and the IP address in order
to get the details fast. So browser also
maintain that cache OS level also we can
basically maintain the cache and on our
DNS resolver site also a cache is
maintained in order to get the details
fast. Now when we are at this topic let
me tell you about one more thing, that
whenever we create domain name systems
like this dogs or subdomains, these all
entirely creates a zone
in the authoritative name server. That
means telesco.com including all the
subdomains. So, one zone can contain
multiple domain list, which will include
only the domains specifically to that
particular main domain. Okay? And
through this it is easier to get to the
main domain. So, in this case, whenever
we are hitting the root server, we are
getting the IP of TLD, again hitting the
TLD, getting the IP of authoritative
name server. And in authoritative name
servers, we can have different zones
attached to different domains.
And in this zone, if it is telesco zone,
in that case, all the domains which are
associated with telesco.com will be
here. So, if instead of telesco.com, if
we are hitting courses.telesco.com,
and from this, the authoritative name
server will get that this is our telesco
zone. And in telesco zone, we will get
the courses.telesco.com
IP address also. So, yeah, this is it
for DNS for now. I hope you understand
it. If you get it, let me know in the
comments. If you have any queries also,
let me know in the comments. Have you
ever wondered, if you see Zomato, if you
see Uber, if you see Ola, if you see
Rapido, and all these applications, also
Swiggy, they all have an inbuilt map.
But, did they create their own map in
their applications, or do they use the
existing Google Maps in order to do
that? Now, that is possible only through
APIs. So, Google Maps present some APIs
to other applications which they can
use. Now, in order to understand APIs in
detail, let's dig into this video and go
to our screen. If we think about API,
the API basically stands for application
programming interface. Now, what does
this mean? Suppose this is our
application.
Any application will work. Let's say
this is a movie application.
In which we have all the movies, plus we
have all the ratings, all the reviews of
the movie. Like IMDb or something, okay?
Like Rotten Tomatoes or something. So,
we are already capturing all the details
which includes a movie like latest
movie, latest hits of 2000, 2010, 2020,
everything. Now, we already have this
amount of data which is stored in our
database and our application is already
working on that. Let's say now in any
other corner of the world, someone is
trying to create one application based
on the data which is already captured in
this app. Now, they have two options.
Either they can create their own engine
like this, their own application where
they will again curate all the ratings,
curate all the reviews, and curate all
the data. But now, where are they going
to curate this from?
For this, every application leaves some
end points which can be used by another
application. Now, if
for our application or for this
developer application, if they want to
use rating of some movie application,
they can directly call the APIs of this
application and through which they will
get the proper information which is
required for them. Now, like this, this
developer or this application don't have
to create their own application for the
task which has already been done.
So, they can use the application data
directly. But again, can't we directly
give access to our database? This can be
dangerous, right? Because then this
application again have to handle a lot
of scenarios based on the database
queries, plus they can also delete some
important data in this database which
will affect the other applications which
are using the same content. Also, there
are some added functionalities. Let's
say we are giving an option to write a
review again. So, in this we have
already handled that case through some
or the other API. So, instead of
creating a new endpoint in this
application, we can directly access the
endpoint of the other application, which
is going to take our review also.
So, in this case, this application saves
a lot of time because they are using
another application, the APIs of another
application through which they are going
to do the same work. Now, in this case,
if this application wants to add some
data into their database also, they can
easily do this. So, this is one use case
of creating an API or using APIs of
other application. Also, there can be a
case where you're creating an
application and in the backend you are
exposing the APIs which can be used by
your front end. So, front end can be a
web application or even a mobile
application. Can be both also. Let's say
we are creating some backend and from
for that application we are also
creating front end maybe using React or
something and backend using Swift or
something. In both of these cases, these
languages, the React and Swift, both are
capable of handling APIs. So, they don't
care about which language did the
backend use in order to provide them the
API. They will directly call the APIs
and use the information which they are
trying to use. So, this is another
scenario where there are no two
applications, there is only single
application which is divided into front
end and backend part and using the data
which backend is providing. Again, in
this case also, you can think that they
will use the database directly, but it
is restricted and prohibited for the
security of data which we have already
discussed in the first case. So, with
this we understand the core
functionality or usage of the APIs.
Number one is if you want to give access
to some other application, and number
two is if you want to give access of the
endpoints or the APIs to our front end.
Now, this both can also happen at the
same time because it is up to us how do
we want to expose our APIs. Some
applications or some backend basically
restrict the APIs to be used through
their front end applications only. And
if you want to make them open, you can
make them open so that other application
can also use the same API. Now, let's
move forward to the type of APIs. The
first type of API is called as REST API.
If you are a developer, you already are
using this. Also, if you are creating
projects, you might already have created
them or use them in your application.
Now, REST basically stands for
representational state transfer. REST is
one of those APIs which you will see in
most of the application nowadays because
of its easiness, its structure, and its
ability to easily maintain a large
amount of data with low volume.
So, that's why we use REST. Mostly, in
REST we use JSON,
which is JavaScript Object Notation,
which is a way or a format through which
we will send or retrieve the data. It is
a easy to use format, that's why we are
sticking with this for this today's
video, and we are going to cover this in
details in a minute. Also, we have some
other types, that is SOAP. SOAP
basically stands for Simple Object
Access Protocol. This is also one way of
handling the data across applications,
across different platforms, and SOAP
basically use XML formats in order to
transfer the data.
XMLs are replaced by JSON because XMLs
were really bulky in nature because in
order to create every object or every
array, we have to mention the attributes
again and again, which is solved by
JSON. So, that's why we prefer JSON over
XML any day in today's time. But, the
SOAP or the XML was famous back then.
So, that means there are a lot of
applications which are still using XMLs.
Why? Because there are legacy
applications. They are built way earlier
when JSON was introduced and still are
using XML. So, in legacy system, if the
APIs are created and exposed using XML,
that means
in order to make our system work, we
also need to know about XMLs so that we
can integrate those APIs into our
system. Also, you can use some
middleware application where the data
will be taken in the form of XML and
will be converted into JSON and your
application can use that data
afterwards. So, that's why if you are
working with a legacy system, it is
preferred to understand the XMLs also so
that you can convert them in JSON or you
can work them without converting them as
well. So, after SOAP, let's jump to the
third one, which is GraphQL. So, GraphQL
is also used widely across many
applications, many platforms. So, the
basic thing in GraphQL is GraphQL
basically says that I'll provide a
single endpoint, only a single endpoint,
and based on that, you can send
whichever query you want. So, in FE,
from FE side, we will not hit multiple
endpoints, but we will send a request as
a query. That's why the GraphQL stands
for graph query language. So, GraphQL
also have a query language that is
similar to SQL. In SQL also, we have
multiple queries from which we can do
our things.
In this also, only one point is exposed
as I told earlier and using that only
the front end now can send multiple
queries and access that particular
endpoint and get the data which they
want. So, this is the core concept of
GraphQL. So, as I said, GraphQL is also
present in our today's time also. So,
there can be a chance that you learning
GraphQL and working on it. The other
type of API is gRPC. Here, the RPC
stands for remote procedural calls and
for G some may say that G stands for
Google because it is created by Google,
but it is gRCP
remote procedural calls only. So,
instead of using XML and JSON, we have a
new format here which is called protocol
buffers. It is very much efficient than
JSON and XML combined. So, that means
the size of protocol buffers are usually
very small than XML or JSON. So, that
will enable the data to transfer faster.
So, because of this only Google created
this and uses this.
So, this is small in size and faster to
transfer. In today's applications where
we have microservices, right? So, in
microservices, this is our entire
application and let's say our
applications is divided into multiple
applications which is combining the data
of their endpoints through each other.
Let's say these are the connections and
through this they are going to provide
the actual API to the outer world. Now,
for this communication between these
microservices, we often use gRPC. Why?
Because internally at least the
communication should be faster to
provide the relevant information in a
low latency. This will also help us
having multiple microservices and having
various kind of communications between
them before giving the actual data to
the other application or the front end.
Now, let's jump to the last one in our
list today, which is WebSockets.
WebSockets are also used in today's time
and today's application for various
purposes. For every notifications, if we
see, WebSockets are used. In order to
maintain a chatting stream, WebSockets
are used. Wherever you need some
real-time connections, WebSockets are
used. So, its architecture is slightly
different from the other services. In
other services, front end or the other
application will place some request to
the application and then they will
provide the response. But, in
WebSockets, whenever front end creates a
request, a channel is created. Now, once
the channel is established, then the
conversation can be lead through back
end also. Whereas, in other forms, only
front end or the other application,
which is trying to access the
information, they send the request and
get the request. But, in this case,
since the back end also can initiate the
conversation, that means it can also
send some or the other information by
itself. Those information can be the
chat or the notifications, which is very
helpful for front end to get. Because,
if this channel is not there, the front
end have to constantly ask the back end
whether there are some new notifications
or not or whether the chat is there or
not. But, once the channel is maintained
through WebSockets, it is easy to
navigate message from back end to front
end and front end to back end as well.
With this also, if you have played
quizzes on our Teleschool platform only,
Teleschool channel, in which you may see
an application which Naveen sir presents
in order to share the quiz with you all,
you use that application in order to
give the responses. Now, those responses
or the marks are calculated based on the
response time and the correctness of the
answer. Now, those connections are also
maintained through WebSockets. That's
why you see many notifications or some
GIF or something something. So, this is
about web socket and with this I would
like to conclude this session because it
is going to be a long session and it is
better to understand these things in
parts. So, these are the most used five
type of APIs which we have. Now, in
order to understand them briefly in the
next video, I'm going to talk about
RESTful APIs in which we will discuss
the various aspects or the parts of the
APIs
and also see what are the
recommendations and usage of those APIs.
Now that we already know about RESTful
APIs and all the other different type of
APIs, it's time to deep dive into one of
them. And for today's video, I have
selected REST APIs to deep dive into.
Why? Because it is the most used APIs
across the world. It doesn't matter if
you are starting a career or you are
already seasoned, you have to work with
RESTful APIs for sure. So, let's move to
the screen now. RESTful APIs are also
known as REST APIs. As we know, it
stands for Representational State
Transfer. What does it mean? It means
that REST is also one format through
which we will transfer our data from one
end to another end. What are these ends?
We have discussed this already. Either
we are giving some data from front end
to back end or vice versa. It is also
possible that one application needs to
get some data from some other
application. So, in that case also, APIs
are used and REST specifically is used
to transfer some data from one end to
another end. So, basically, it is a way
of how our applications are going to
communicate with each other. Now, before
starting, let me tell you that in REST,
we normally use JSON. JSON is a standard
way of sharing the data.
In JSON, we can have array, we can have
object and with these two combinations,
we can share our data in the form of key
and value. So, let me create a simple
JSON. Let's say this is a start of an
object and here we have a key, let's say
name. For value, I'm writing my name.
With comma, we separate different
values. So, after comma, I have to write
some other key. So, let it be age. And
with age, I can write any numeric value
as well. So, as we can see, this is
string value and this is a numeric
value. There are more values who are
accepted as a form of value, which is We
have already seen string and then
number. We can also use boolean, even a
nested object, arrays, and a null. Null
can also be used because if we don't
have any value for that particular field
directly, it is easy to say it is a null
value. And the application which is
using that value can take care of it.
So, this is all about the JSON which we
need to know. We need to know that it is
in the form of key-value pair and what
are the values which we can use. Now,
let's move forward to the next part,
which is endpoint. In order to
understand endpoint, we have to get two
things. One is method and the other
thing is path. So, in order to access
any data, we have to have some URL on
which we will hit with that particular
method and based on the method selection
and the path, we are going to either get
or pass some data to our server. Let me
start this with an example. Suppose we
are using HTTP as uh any site, my site
.com. So, this is our main site and
after that, we can put a slash and use a
different URL. Let's say we are
separating all the APIs in the API
subdomain. So, APIs is there and then we
can also segregate the APIs using
version. So, this is version one and
here we are going to write resource.
Now, resource can be anything. If I talk
about any e-commerce application, it can
be a product, it can be coupon, can be
user, can be anything, basically. A
resource is an entity through which we
are navigating and getting and passing
the data to the database. So, this is
the URL. The URL is called the path
through which we are going to either get
or pass some data. And with this, we
need to have a method. So, for method,
we can have a get basically. So, get
method with this path combinedly creates
an endpoint and through which now we can
get some data. We expect this path to
retrieve some data because we are using
get. Now, there can be multiple ways of
creating this URL. So, normally, we hide
the domain part of it. We don't use them
in the explanations. We only use the
resource part. Also, we can remove the
version also. With that, API can also be
removed in order to understand the
resource part directly.
So, from now on, if I create any path,
let's say users, it is expected to have
all this domain name API versioning if
it is there beforehand. So, I'm not
writing that again and again. Cool. So,
with that, if I write users here and use
get method, now I'm expecting some
response from our server. I'm expecting
either a list or a response from our
server. We'll come back to responses in
a while, but this is how we can get some
user information from our server. Now,
let's move to the second part. In this,
we don't want all the users, we want a
specific users. So, to find a specific
user, we have to provide them an ID.
Normally, we provide them in the URL
itself. So, it is get users and here we
can include the ID. So, in real time, it
can be used as users/1.
So, if we write one, the user with the
ID one will be retrieved. Now, with
this, we can also add any user. So, the
third part is
adding a user. So, again, the URL will
be same users and now we are adding the
user, so we are using the method post
here. So, in this with post, we are
going to give some body, and in body, we
will have some JSON which will store the
user information which we are trying to
create. And based on our request, our
user will be created in our database.
Now, once we have all the user details
in our table, we may choose to update
any user information, correct? So, for
that, we use another method which is
put. Again, the URL will be same, users.
And with this users, we will send the ID
of the user of which information we are
trying to update. So, with put, we also
have another method which is patch,
which can also be used in a similar way
to update the user information. Now,
what is the difference between put and
patch? It is simply that if we use put,
our entire user object will be replaced
with the new data. So, this is going to
replace the user data. And if we don't
want to update all the fields, we want
to update a specific field or particular
field, suppose username, name, age, or
anything, so we can use patch. It can be
used to partially update the user
record. Let's understand this with an
example. Let's say we have any user
information which have ID and have a
name and have a username, maybe age.
This is all. So, these are all the
values which are
user currently have. Let's we put some
values. So, if our user table or user
entity have these all four values, if we
use put to update a particular change
only, let's say I'm going to change my
username from Akshay to AK something.
So, now this change will only be done if
we again send the entire body into the
put request. If we only send username
like this, then all the other values of
our entity will be updated with the
default value. So, if we send this kind
of data in a put request, it is going to
replace our entire entity. So, that
means the name, the age will be replaced
by the default or null value. So, it is
not recommended to use put entirely if
you want to update your entity
partially. In those cases, always try to
use patch. In patch, we're going to
again update the particular information.
So, this is perfectly valid for a patch
request. So, with this, let's move to
the next part. The next kind of method
which we use is delete. In delete also,
normally we pass the ID like this. So,
if we write users and with {slash} we
write one, so that means the user with
the ID one will be deleted. Now, this is
the usual stuff. You will get this
information anywhere. Now, let me talk
about something which is nested data.
Let's understand nested data with an
example. Suppose you're creating a blog
site. So, in blog site, we normally have
our users who are going to read our
blogs. Then, we have blog, the actual
content on the site. And on blog, the
user can comment. So, we have clearly
three entities: users, blogs, and then
comments. So, these three entities are
interrelated. So, a user is going to
give comment on a particular blog. Users
can't comment if there is no blog,
correct? So, this is the way. Now, in
order to create APIs for this, we can
create a users API for all the users'
activity. So, all the users' activity
means we can use it for get, put, push,
delete, and patch also. Now, this is
simple because a single entity is there,
users, and all the operations are on
that users only. Now, let's say we want
to create an API on which user can add a
comment. Okay? So, for that, what we can
do, we can either go from the blogs
perspective. So, every blog have a
particular comment section, right? So,
blogs, then here we can write ID. So,
this ID is basically belong to the blog,
and with blog, we can write comments.
And if we write get here, what it is
going to do, it is going to give us all
the comments which are associated with
the blogs with ID this. Correct? So,
this is a nested relationship where
we're trying to access comments, but we
are going via blogs. We can also do like
this. Suppose we are on the user's page,
and we want to see all the comments that
user have created. So, we can again
create a get query
via users, where this is the user ID
here, and we can see comments. So, we
are dealing with two different entities
by creating the relationships between
them. So, by this, we are going to get
all the comments which are created by
the user with this ID. So, we can go to
comments via blogs, as well, and via
users, as well. So, this is nested.
Again, if you want to update any
comment, delete any comment, we can use
simply the comments path
where the user can enter the ID here of
the comment.
And they can use it to update or delete
that particular comment. So, here you
can also ask me that why are we using
this kind of nesting in URL? Why are we
not sending the data in the request? So,
that is also possible. We can do like
this. We can
go to this comments, and we can pass the
request body, in which we'll pass
the post ID to get all the comments
associated with this post. This is also
possible, but this is not recommended.
As there is a direct relationship
between two entities, we don't normally
go for this body approach. We go for the
URL approach because it is easy to
understand also. So, when do we go for
the body approach? So, the body approach
is used when we are trying to filter any
data. So, we understood two concepts
here. First is the nesting data versus
filtering. So, when to use which one? If
you have a clear relationship between
two entities and it is clean, so you can
go for nesting. And also in filtering,
apart from sending the data like this in
post ID, you can also use
the URLs like this, comments, and then
in query parameter, you use post ID.
Now, this is again not recommended
because there is a direct relationship
between comments and post. So, it should
be a nested type of URL. So, if there
are clear relationship, we can use
nesting. And if the relationship is
complex, we can go for filtering. Also,
the filtering will be used whenever we
are trying to do pagination or we are
trying to filter particular records
based on multiple ways like we can go
for any e-commerce page where we are
seeing different products and we can
filter our product based on our color,
price range, and all these things. So,
those things normally go for query
parameters as a URL, right? And we don't
go for nesting there because it will be
complex to handle a long path with
nesting data. So, the crux is if the
relationship is pretty straightforward
and we will go with respect to the other
entity, we'll go for nesting kind of
URLs. And if there are complex
relationships or the filtering is used,
we'll go for the query parameters. Now,
let's move to the next part. How do we
pass the actual data to the endpoint?
So, there are three ways. Either we can
use path, so we can integrate the IDs in
the path, or we can use some query
parameter, or we can use body. I have
given you glimpse of these all three in
the previous section, but now let's talk
about this specifically. So for path, it
is very specific that we will only pass
the recommended IDs or maybe slugs or
maybe that particular unique identifier
only. So this is unique identifier. It
can be ID or slug. Slug is basically a
short form of that particular post. If
you are using any blog site, so let's
say the blog site the blog is about what
is Java and in slug you can see
something like blog /what is Java like
this. So this is our slug. Again, this
slug will be unique throughout our
blogs. So the name of the URL I have
also written blogs, it is wrong.
Normally we address the URL in the form
of plurals. So it is going to access in
multiple areas, multiple scenarios. So
normally we don't go for blog, we go for
blogs like this. Cool. Now for query
parameters, whenever we are filtering or
maybe sorting, we can go for query
parameter. Suppose we are again
scrolling through our blogs and in blogs
we can write like sort ASC or we can
assign some numbers also. So ascending
means sort ascending maybe by date. So
whichever date they are created, they
will be sorted by that. Or maybe we can
use DESC for decreasing order. So that
the latest post will be pop up first.
With this again we can use the query
parameter for filtering. So maybe we can
use blogs again here and with that we'll
pass query parameter. So this is Q for
maybe query search or search step. So
anyone with is searching for Java and it
will give us a list of blogs for Java or
which have Java in their name or their
content or their category. So, this is
all about query parameters. Now,
whenever we pass any information in
query parameter and path, those
informations are going to be exposed,
right? So, that means we can't pass any
sensitive information into query
parameters or path. So, for that we have
body. So, let's say we have a login
path, and now we can pass username and
password in the body, which is not
exposed at all.
So, it is safe. So, the rules are pretty
clear when we use path, query params,
and body. Now, with this let's see a
full request in action. The first thing
is we will have our method. So, this is
maybe a post method, and we are using
some API of version three, maybe.
For version three, we are using users,
and then we can also pass the metadata.
Suppose content type we can pass, which
is application/json
here, because we are passing the
information in the form of JSON. We can
also use XML, or if you have latest
information, we also have a new format
in town, which is
tone. So, we can also use various kind
of information, but because currently we
are using JSON, so we can pass it like
this, and with this we have our body. In
body, we can pass anything, maybe some
data we are trying to add, and then
maybe username. So, like this we can
pass the entire request or the data to
our server. So, this is what? This is
our method. This is the path. This again
is metadata, and this is our body. Now,
once we have understood the request
correctly, it is time to understand the
responses. So, in order to understand
the response, first we need to
understand the response code. So, there
are specific codes assigned to a
specific type of response, which if the
user gives will clearly understand what
they want to tell us. So, let me start
with those status codes and then we will
move forward. So, these are all the
response codes which we have to know.
200 stands for okay. So, this means
everything is working as expected. Don't
worry about it. Then we have 201. 201 is
basically used when there is a new
entity created in the database. So, this
is created. Then we have 204. 204 is
again saying that everything is working
fine, but I don't have anything to
provide to you. Let's say we are
deleting any entity, so it is
successfully deleted, but they don't
have any response body to give to us.
So, that means there is no content to
give to us, but the request is working
fine. Then we have 301. 301 is basically
used for redirects and 301 indicates
that it is a permanent redirect. And if
the redirect is not permanent, then we
use 302. That is temporary redirect.
Then we will come to the 400 series. So,
all the 400 series basically says that
there is some issue with the request we
are having. So, the 400 stands for bad
request. That means some or the other
data is not correctly mentioned in the
body. Either they have some validation
issue, either either they are missing
when they are required. Either they have
some other issues, but request which we
are getting, the body doesn't have the
correct information. So, in that case,
we normally give 400 bad request as a
response. Then we have 401. 401 is given
when someone is trying to access some
information for which they are not
basically authorized. So, 401 is
unauthorized. With that we have 403,
which is used for forbidden. Suppose on
an LMS, you have not enrolled for a
course and you want to access a
particular video or lesson part of that
course which is not publicly accessible.
So, in that case, you will receive 403
forbidden because you are not allowed to
see that particular resource. With this,
we have 404 page not found. This is
basically used whenever the URL is
incorrect or trying to access some or
the other resource which is not there
into our system. And at last, we have
500. So, 500 is the response which is
given to a front end when there is
something wrong with the back end. So,
this is related to back end. Some or the
other error is there in the back end.
Maybe some syntax error, maybe some
other error, some logic is missing, some
data is missing, something is wrong with
back end. So, this is internal server
error. There are many errors which we
don't want users to see. So, those all
are handled by 500 because we don't want
the user to understand what is the issue
we are facing with our database
connection or anything. So, we will
create logs into our system and through
which we'll resolve the 500 error
issues. So, these are all the most
commonly used response codes which we
have to understand. So, now whenever we
are creating any APIs, if the response
is completely fine, we will provide 200.
If we are creating any entity, we will
provide 201. If we are deleting or
performing some operations where we
don't have to give any content or any
data or any body in the response, we
will use 204. Then, if the permanent
redirection is there, we will use 301.
If the redirection is for temporary
basis, we will use 302. For any bad
request in the body, we will use 400.
For authorization, we will use 401.
For forbidden or the content which
requires some special access, we will
give 403. 404 we will give when they are
trying to access any resource which is
not there and 500 we will give when
there is any issue in the internal
server. So with this, let's move to the
next part which is response body. So
normally in response body, what is
allowed first we start with that. So we
can return an array, right? Also, we can
return an object. With this also we can
return data as nested objects. Now in
most of the applications whenever you
are going through any YouTube tutorial
or any course also sometimes when you
are dealing with multiple responses,
let's say the responses for this is
normally an array, right? But it is not
recommended to handle the response as
array. It should always be wrapped in
the form of an object. And if you want,
you can use any other key for this users
and in the value you will give these
responses. Now these can also be string
or an object. Normally an object only of
all the users, but it should be handled
like this. So this is the correct or I
would say recommended way. So every
response body should be an object. And
even if we're trying to give an array,
we have to wrap it up into an object and
give us in the key value form. So this
is a good practice and through this
we'll achieve a more long-lasting code.
Why? Let's say today we are passing the
user details only and tomorrow we
understand that okay, we have to add
more fields. So we don't have to change
much on the front end side or the
receiving side, but we will simply
update our response, change the object
here
and maybe add some other field user
count and pass that information maybe
29. And with this we can end our object
here. So we can pass as many
informations as we want, but if we have
used a single array
as a response, then we have to struggle
with it and we have to change the entire
architecture of our response. So, it is
always recommended to pass the response
always in the form of an object. So, let
me write returning as array not
recommended. Let me know in the comments
if you already knew about this or you
are hearing this for the first time. So,
with this, let me create a map of
request type and responses. So, let's
say here
we have request. Here are the responses
which we are going to receive. So, if
the request type is get and we are
trying to access many records, so maybe
we are trying to access users, it is
going to give an array of records,
right? So, it is normally going to give
200 as a response code and going to give
an array. Now, we understand that we
have to not give array directly, so it
will be wrapped in the form of an
object. Now, the next request is also a
get request where we want to access a
particular object. Let's say one. Now,
you can think that we will give the user
information directly, but again, it is
not recommended to give that directly.
We will use the nested object for the
same reason. So, in this object, we will
use the user as key and pass on the user
information into this object. So, this
is the actual user object, but we are
wrapping it into an another object
because it will give us flexibility to
pass some more information if we want
to. So, let me clear this up for now.
So, normally, we are going to get 200
response with this kind of nested
objects. Also, it is possible that this
ID is not there in our DB. In that case,
we can also give 404 response. Now, if
we are adding anything, we will use post
with the same URL, and normally it is
going to give 201 response, which means
the entity is created. And also, we can
use 200 response if you want. But, if we
are using 201, normally we give the ID
or the new object as response. Now, here
with post request, we are also giving
the body, so it can also have 400
issues, right? 400 bad request issue.
And also, if the format doesn't sync in,
it can also give 500 issue. If the data
is coming properly and there is some
issue in the back end, it can also give
500 easily. So, these are most common
response codes which you can have while
working with post. Now, let's talk about
delete. In delete also, we will pass
this
URL with some ID, and this can also give
200 as a response. And also, if it is
deleted correctly and we don't want to
give anybody in the response, we can go
for 204. If this entity is not present,
maybe the ID they are using is one and
we don't have any record with the ID
one, we can have 404 or we can have 500
if there are any dependencies
and which is not handled correctly by
our back end. With this, you can also
see 401 here if you are unau- prized
person to delete that particular record
or you are not allowed to delete that
particular entity, you can also get 401.
So, these are the most common request
responses, and with that we have also
discussed what can be there in the
response body. So, with this we have
covered the entire request section and
the response part of the REST APIs, and
I hope the information which you get
from this video is going to help you in
your entire development career. Whenever
you are dealing with REST APIs. In order
to build any application, we have client
on this side, right? Who is going to
interact with either a web application
or a mobile device to interact with our
application. Now, with this we will have
our server in this side. So, this is
maybe our server. And if we keep the
model like this only, that means every
time we restart our server, all the data
which user is trying to access will be
lost. Because when server restarts, it
clears all the data. But, the thing is
we need to store that data somewhere,
right? So, for that we use database in
order to store the information which the
user may require next time when they log
in or see our application. Now, one
thing is very clear that most of the
application can't live without
databases. Now, in order to understand
how do we store data, we have two
approaches. First is the SQL approach,
and the other one is no SQL approach.
So, SQL basically consists of RDBMS,
which is relational database model, in
which we will have tables, rows,
columns, and we will connect those
tables based on different joins and
everything. And in no SQL, we have other
methods. See, saying SQL and no SQL is
like saying Java and no Java. That means
there are various options in no SQL. We
can have our data as in the form of key
value. Also, we can have column. We can
also have the data in the form of nodes,
maybe. And we can store them in the form
of graphs. Also, we can store the data
in the form of document. And here, if we
talk about SQL, we have our tables in
place, who is going to hold our data in
the form of entities. And there will be
different relationships between
different tables. Also, in order to do
in SQL manner, we have various softwares
like post dress or we can go for MySQL.
Right? Like this, we can have multiple
options here. For here also, we have
multiple options like Cassandra or we
can go for MongoDB. And based on this
selection, where we are going to do it
SQL way or no SQL way, we are going to
build the entire foundation of our work.
Like how our data, our important data is
going to store in our database. So, in
today's video, let's focus on SQL. And
in next video, we will focus the ways of
no SQL. So, let's start. So, SQL
basically stands for structured query
language. And SQL comes under the
category of relational DB. Now, in
relational DB, we are going to have
multiple entities and we are going to
establish different type of
relationships between those entities, if
required. So, we are going to store our
data in the form of tables.
So, we can loosely say that every table
is loosely an entity.
It can either be a user entity or it can
be comments or it can be post, if we are
building anything like blog site or
something or it can be videos, if we are
building YouTube. So, like this, we
segregate our different entities and
then we will build the relationship
between them. Now, if I draw one of
those tables, let's say we are building
a user table. A user table can have
multiple fields. That is equivalent to a
user entity can have multiple
properties. For example, a user can have
their unique ID. A user can also have
their first name
and L name and maybe we also have their
phone number. So, this is how a table is
formed, where we have multiple
attributes of a table. These attributes
are stored in columns and when we have a
complete record, let's say in this
table, we can add a new record where I
can add any record, let's say the ID is
one, the name is Akshay, last name is
Agarwal, and phone number is, let's say,
987654
321. So, this is my number, this is a
complete record. Now, this record is
called as a row.
So, by getting any row from our table,
we can get the entire information of
that particular entity or of that
particular user. Normally, for the name
of entities, we don't go for singular
words because it will contain multiple
records. So, we will go for plural
things, users. So, this is the standard,
this is a constraint, this is not a
particular rule, but it is safer to go
into plural things. So, for comments, we
can go for comments, for post, we will
go for posts, for videos, also, we will
go for videos. So, all these things are
in plural. Why? Because a single table
will contain multiple records. It will
be easier for us to fetch the data with
that plural name because then we will
know that multiple entries are there and
it is a convention to use plural things.
So, with this, let's move to our next
topic, which is constraints. If we are
building any application, we can have
multiple users who are coming with
different backgrounds, different
geography, and everything. So, it is our
responsibility to make them enter the
data correctly. We will use validations
in form, and in database, we can handle
them with the use of constraints.
Because every wrong data and every
faulty data is of no use. So, for that,
let's dive into the constraints. So, the
first constraint is unique. Unique
basically stands for a unique value
throughout the table. For example, in
the user field, let's create the user
table again. So, this was our user
table, let's add one more column or one
more attribute, which is username. Now,
we don't want two users to share the
same username. This is a common thing
which we can see on Instagram also. If
you're trying to create a new username
and if that username is already taken,
you may get some suggestions with some
extra characters or you can change the
name entirely. Similarly, for Gmail
also, if the username is taken, they
suggest you some more usernames with the
extra characters. So, that means we can
say that the username is unique. Every
user will have their unique usernames.
So, in order to maintain that username
uniqueness, what we will do, either
while creating the table or while adding
the username field like we did, what we
do, we add the constraint unique to that
particular username. So, that when any
user comes to this entry and if they
write ABC, no other user can write ABC.
If they want to use the same username
again, they will not be added into our
databases. Why? Because this username
field is unique. The next constraint is
not null. So, not null basically
represent a value which can't be null.
Null is the default value for any
entity, right? So, whenever we want a
field to have a particular value either
given by a system or server or given by
our user, we want to have that value.
So, we can't have null in that. If we
see in users table, the first name can
easily come under the not null category.
So, we don't want our first name to be
null because we are going to address our
user with their first name. So, this is
a required field. The next constraint is
primary key. So, our primary key acts as
a unique identifier for that particular
entity. In our whole user table, there
is no record which can share that
particular value. So, if we find any
record with ID, let's say ID is equal to
three, so only one record will come out
of this. Okay? It can't give two records
because the ID cannot be shared between
two records. So, it will give a unique
record out of our users table. So, our
primary key basically helps us to track
down to that particular record. And
also, it helps us when we deal with
multiple tables because there we might
need some ID to put into some other
table as a foreign key. So, in that
concept also, primary key is used. With
this, we can have a fourth option here,
which is check. Check is basically used
in order to maintain the authenticity of
any record. Let's say we are using a
password. So, while creating a password
or while having a password, we might
want our user to use certain constraints
like the length should be greater than
eight or maybe it should have any
numeric values or it can have one or two
special characters also. So, all these
rules which we apply are applied in the
DB for that particular column through
the check constraint. Also, the other
example of this can be a mobile number
or a phone number. So, a phone number
will only contain numeric values. It
can't have any characters apart from
that. So, this is also a check which we
can apply for our phone number field.
Also, the checks can be applied to any
field. Let's say for first name, we
can't have any name whose length is less
than maybe two because A B C D, this
can't be stored as a name. The shortest
name I know is Om, right? It is also two
characters long. So, we want to have
that check. So, all the checks are
covered with the check constraint. Now,
with this,
let's move to the other constraint,
which is foreign key. So, let's
understand foreign key through an
example. Let's say we are creating a
blog site where we have users table
again. So, the users table is basically
the authors table. Or let me rename it
to author then.
So this contains the list of all the
authors who are going to publish some or
the other blogs. So there we have this
ID and then from this ID, let's say we
only have two fields, first name
and last name. We can have multiple
fields if you want. For the sake of this
example, I'm creating this smaller. So
let's say we have one and the author is
Akshat Agarwal.
Let's say I have two authors. Okay. Now
these two authors are not going to write
only single post. They are going to
write multiple posts. So we will have to
create a separate table for posts and in
that post we will have some ID. I'll
have data or maybe content is the better
word. So I'll change the name data to
content. And that content is provided by
some or the other author. So here we
will have author ID also. So now let's
say our post, first post, have some data
about HTML and who wrote that post?
Maybe Akshat. So for Akshat, I'm not
going to write the entire details about
the author again into this table. So for
that, what I will use, I'll use the
common identifier which is our ID. So
our ID is our primary key here and which
will be used as the foreign key here. So
this is our foreign key and we will
simply write one. With this particular
information, we are going to get that
okay, this author ID is one that means
it is written by Akshat. Similarly, if
we have multiple fields like this, let's
say post two is on AI maybe and it is
created by Gaurav.
So we don't have to write the entire
fields or entire information about
Gaurav. Only the primary key will do.
So from this two, we are going to again
recognize that it is written by our
second author who is Gaurav. So this is
the role of our foreign key to establish
the connections between two entities.
With this, we also have a next
constraint, which is default. So,
default basically stands for the area or
the field where we can't have null. So,
null is not an option. And we don't want
our user also to have that entry as a
mandatory field. We can fill in for
them. Let's say we are building anything
for subscription. And if user have not
paid anything to get a subscription,
they might be having free as the value
because they are currently using our
free subscription. So, this is one case.
The other case can be, let's say you are
into our learn.telesco.com, right? So,
this is our LMS and we are creating
them. So, in this, every new user or the
more number of users are going to be
students only. And only few users are
going to be managers or trainers or
maybe admin. So, those are few
categories and most of them are going to
be students. So, the default value of
role for every user here is student.
Student/learner.
So, either student or learner, we can
have as a default role. And with time,
let's say one or the other student or
learner got hired into Telesco only to
maintain the notes or maybe to teach,
then we will update their role to
trainer. This is how the system works
with default. So, these are all the
constraints which we have in our
databases. Now comes the next part of
our relational databases. One of the
most important part is join. Join is
basically used to associate two tables.
That means to manage relationships
between multiple tables. And why do we
do that? To basically maintain
relationships between different
entities. So, let's see how many joins
options do we have. The first and the
most common join option is one to many.
So, we have a users table. We have ID
here, and we have F name only.
Again, I'm going to use the same entry,
one and two. And here, I can write any
name. So, here are the two names, Akshay
and Gaurav. Two entries basically for
this users table. And again, we are
creating a blog site. So, that means
both Akshay can write multiple blogs,
and Gaurav can also write multiple
blogs. So, we will create another table
to maintain our blogs, which will have
ID, the content, and the author ID. So,
maybe the first blog, which is on HTML
again, is written by Akshay. The second
blog is on AI, which is written by
Gaurav. And then, there is third blog,
which is on system design, which is
created by Akshay. So, here we have one
to many relationships.
Because for a single record here, we
have multiple options or multiple rows
associated with that particular row. So,
this is one to many relationship. With
this, if we reverse this, we can also
have many to one relationship. So, what
we will do? Here, we were talking about
users to blogs relationship. And here,
we are talking about blogs relationship
with users. So, here we can safely say
that multiple blogs are associated with
the same user. So, here we can have
multiple blogs associated with the
single user. So, this is many to one
relationship. Now, let's move forward
for our third relationship, which is
many to many. So, in order to understand
many to many, let's again go to our LMS.
So, in LMS, we can have students.
And we have courses here, right?
Students also, we have ID maybe, and
only F name is here right now.
And in course, we have ID, and then we
can have the course name here. Now,
let's fill in some entries here. So,
here we have students as Akshaya and
Gaurav. And our courses are Master Java,
Master AI. Now, Akshaya as a student can
enroll into multiple courses. So, we can
sense that from students, we can have
multiple relationship for courses. And
also, one course can have multiple
students. And it is also possible that
in Master Java, we have both Akshaya and
Gaurav. So, that means our students
can enroll into same course. So,
whenever we see a situation like this
where we can have many students or many
records from single table associated
with the single record of another table,
and vice versa is also true, we are
going to get a many-to-many
relationship. So, in order to maintain
multiple relationships, we have to have
a
junction table in between. So, this is
our students-courses
table. And here, we will have a unique
ID of this particular record. Maybe this
is required, maybe this is not, based on
your queries and use cases. Here, we
will have students ID. And here, we will
have course ID. And now, while entering
the data, we can simply say the record
one, we have Akshaya enrolled in Master
Java.
Now, record number two, we have Akshaya
again enrolled in Master AI. Then, for
the third record, we have Gaurav
enrolled in Master Java. And the fourth
record, Gaurav enrolled in Master AI as
well. So, with this junction table, we
are going to figure out how many
students are enrolled in how many
courses, and how many courses have how
many students. I hope this makes sense.
This is a little confusing if you are
starting, but this is how we maintain
many-to-many relationships. With this,
we can have one more relationship, which
is one-to-one. Suppose we are building a
platform like YouTube or blog site which
also have podcast, which also have maybe
video section. So, we have three kind of
content, right? The first content is
text for blogs. The second content is
audio, and the third kind of content can
be video.
Now, the processing of all these
contents are different. We can handle
these multiple options by two ways.
Either create a common table
named as contents. So, in content now we
have three types. For video, we are
going to store MP4. For audio, we're
going to store MP3 maybe. And for text,
we're going to use the text which is
there in database. We can use varchar,
long text, short text, maybe text. Now,
there are three kind of content. We can
basically divide them by using a field
which is type. So, in type we will have
options like text, audio, or video. So,
here the first record can be on again
HTML, which is a blog type text type.
So, we will type one here or text
directly here. For the next content, it
can be anything. Let's say the content
is on improve focus, and in order to
make that content, we don't have a
video. So, we have something like audio
here. And for the third thing, we have
any video, let's say
system design.
And for this video, we have the type as
video. Now, if you have worked into
systems with these type of content, the
processing of each type is very
different. And if we curate all these
data into a single table, it is going to
be a really heavy one. Now, what are the
drawbacks of having a heavy table? That
is, whenever we are trying to filter, we
have to basically filter through each
and every content type and each and
every record as well. So, instead of
having all these kind of data into
single table, what we can do is we can
segregate the data already into multiple
tables and have those IDs as a foreign
key.
So, the other approach is we will create
a simple contents table where we will
have ID here again and maybe the content
name.
And then we will not have the entire
video or audio. What we will have, we
will have the ID of that particular
content. So, that means we are going to
create multiple tables, one for videos
and one for audios and one for maybe
blogs. They all will have a common ID.
With common ID, I mean their primary key
and we will use the ID from videos, from
audios and from blogs into this
particular table. So, we will not have
all the data here. Here we will only
have content ID maybe. And with this, we
can also have content type. So, this
type will determine where we need to
follow. So, this content table will only
contain all the fields which user can
search. They can search for name, they
can search for type, they can search for
maybe some keywords, some slugs. So, all
these details will be there in our
content field. And the actual data, the
actual content will not be in the
contents field but in their respective
tables. So, all the blogs will contain
all the blogs, all the audios will
contain all the audio files, all the
videos will contain all the video files.
So, now if we have one and type as
video, we know that one is going to
fetch some data
from this videos table where the ID is
equal to one.
So, this is one to one relationship.
Where we know that we are using a
different entity to our entity and the
relation between us is one to one.
Whenever we write one here,
we are not going to fetch any other data
and also we are not going to use the one
again in this table. So, this is
one-to-one relationship. So, we have
understood that in relational DB, we
have entities, right? And we join
multiple entities through relations.
That means every entity will have
particular set of properties, and then
they will be joined, and we will get the
data accordingly. Let's understand the
same thing with the example of posts and
comments. So, suppose we are building a
blog site, and in blog site, we have
some post, and then we have some
comments. The post table will have some
ID, unique identifier, then some content
associated with the post. Now, content
can be anything, right? It can be
images, it can again be text, or
sometimes it can be video, also. So,
these all are the category of post. Now,
we have different type of posts, but we
have to somehow pass those IDs and
manage three tables for image, text, and
videos. We can manage them in the same
table, as well, but that will increase
our latency, because different kind of
formats are curated into a single table.
That will increase the size, right? With
content, we can also have content type,
through which we will basically apply
some filters, if we want to. Now, if we
talk about it, we already have four
tables. One for images, one for videos,
one for text, and one for content. Now,
we will have comments, as well. So, in
order to have comments, we will have
some comment ID, and then we will have
comment. Now, comment can also be a sub
comment of a parent comment. So, that
means we can have a parent kind of
comment ID, as well. Now, in order to
handle comments, we have to handle
users, also. Now, in order to handle
user, we need one more table. We will
have ID, maybe name here. So, our number
again got increased to six. Now, in with
this PID, we will also have user ID who
is commenting on our post. So, in order
to maintain a simple post and comment
section, we will have to have
four to five to six tables, right? And
then we have to maintain the
relationships as well. So, that means
even for a small blog site, we will have
to maintain so much data. And when the
size of the blogs increase, with that I
mean this will get hard to scale. Now,
why I'm saying it is hard to scale?
First, understand how can we scale any
database? We have two options only,
right? First is by scaling them
vertically, and the second option is by
scaling them horizontally. In vertical
scaling, what do we do? We add the
capacity to a single server. So, that
means if we are using 4 GB data, we will
add more space into our server to have
more data. We can only expand this kind
of vertical scaling to a extent. After
that, we will have to use horizontal
scaling. That means having different
servers across different places. So, in
this case, we will have to maintain
relationships between the different
entities
in all of these databases.
And this will be a tedious task. So, in
order to avoid this, we can use NoSQL.
So, we can say the first advantage of
using NoSQL databases is it is easy to
scale both vertically and horizontally.
Because we will have to maintain a
single document, and we can replicate it
on different servers or even split them
into different partitions and pass it to
different servers. We will understand
about that also in a bit. Now, what is
the next issue? The next issue is
if we are maintaining a table, we can't
change the table again and again. We
have some fixed columns, right? We have
some fixed attributes or columns. We
can't add or remove different column
types in order to maintain different
kind of data. Now, let's say we are
going to handle the blog site, but this
time we are going for NoSQL database. In
this, what we can do now, we can create
again and content entity and we can
basically use any kind of content which
we want. So, we'll create the first
object and maybe we'll write something.
Let's say user ID is one, then we will
write the content. Here, the content is
an image, so let me pass some URL. https
maybe something something.jpg.
Now, when we are adding next content,
let's we can add it directly into the
same content document. So, what we'll
do, we'll again use some user ID. Maybe
this time it is two and in form of
content, now we have some textual data
and we can have some text. Also, if you
want to use it in a more refined way, if
you want to add some rows, we can use
that, right? We can use user ID as
three, then maybe heading as anything,
let's say Java, and then maybe we can
have some description. This is
description. And like this, we can have
as many fields as we want. So, that
means in a single entity content, we can
have different fields and also we can
have different number of fields in the
same document. And if we go about
relational database, we can't do that
there, right? So, in these kind of
scenarios where the document structure
is not fixed, this is basically called
schema-less, we need to go for NoSQL
options because in SQL we don't have
this option. So, that comes to our
second advantage of using NoSQL, that is
we can handle schema-less objects as
well. So, now let's discuss about third
point. So, in NoSQL up to now we have
seen it is easy to scale, then it is
schema-less and what makes NoSQL more
feasible is when we don't have to handle
a lot of linking between different
entities. That is we don't have to
maintain a lot of relationships between
different entities and also every entity
in a NoSQL database stands on its own.
Think of this as a key-value pairs.
Let's say a course ID. ID is the key
here and in the course content we can
have anything. We can have only name or
we can have entire object. Or in third
place we can have entire course with
lesson. Of course there are going to be
nested lessons in a course structure.
Again with lessons in fourth place we
can have course which will contain some
lessons as a nested object and those
lessons can also contain some comments.
Now all these things are possible in
NoSQL which were not there in SQL. If we
want to have similar structure in SQL we
have to maintain different entities and
we have to maintain different
relationships between them. Here we
don't have that struggle. So that makes
our NoSQL work easy. So this is why we
use NoSQL over SQL and with time it is
gaining popularity. For example in
Netflix we use Apache Cassandra in order
to maintain user activities. In Amazon
they use DynamoDB in order to scale
their application. In Facebook or Meta
they use HBase in order to maintain user
messaging and large-scale storage. In
Uber they use MongoDB in order to handle
flexible and real-time data. And with
that Twitter or X use Redis for caching
and timeline purposes. So the conclusion
is that NoSQL is also being used in
variety of systems nowadays. Let's
distinguish it for a bit now. So when we
should go for SQL and when we should go
for NoSQL. Whenever we are handling
payments, we don't have so much variety
there. So, payments can be easily
managed through SQL. So, with payments,
we can also think about transactions or
any other feature which needs
consistency where the data is not
changing, the schema is not changing,
and also we need to handle those
relationships perfectly. In all those
areas where we need consistency, we can
easily pick SQL. Now, when do we pick
NoSQL? When we are talking about scaling
and also we can talk about speed because
as in NoSQL, we have a single document
to search from whether in SQL, we have
different entities or tables who are
joined through one or more
relationships. So, we have to traverse
multiple tables in a SQL database and in
NoSQL, we don't have to do that. So, by
that nature, the speed of NoSQL database
is faster than the speed of SQL one. And
also, one of the core reasons to use
NoSQL is
unstructured data. So, in other words,
whenever the consistency is on more
priority than availability, we can
easily pick SQL. And when availability
and scalability is on more priority than
strict consistency, we can choose NoSQL.
With this, I hope you all get why we use
NoSQL databases also with SQL and in
what areas will we pick SQL over NoSQL
and vice versa. Now that we have
understood what NoSQL database is and
why do we use that, let's see some
examples and application areas of NoSQL
database. Now, the thing is in SQL, we
have only considered all the databases
which will have tables, similar
relationships, and in NoSQL, there can
be various ways in which we can store
data because it is like saying Java and
NoJava. In Java, we have Java and in no
Java, we can have many applications,
right? So, like that, let's start by our
first example, which is key-value pair.
Now, if you are a developer or
developing front-end, back-end, or
anything, you must have used cache. We
use the format of key and value whenever
we are trying to insert some value in
cache or maybe cookies or in data
storage. We use this kind of data. So,
if we talk about key, the only feature
which a key should have is that a key
should be unique. And for value, we can
use any kind of value. We can use
basically JSON or a string or maybe a
number. Maybe if you want to add blob,
we can use that. We can also store it as
byte array or any array for that matter.
We can also obviously have objects as
well and we can also have the
combinations of them. Like a list of
object can be stored in an array or an
object can also have nested objects. And
with that, obviously, it will be having
some strings, numbers, blob, byte array,
or any of that values. Now, the two
important points here are we don't have
to follow any structure because the
NoSQL database follows schema-less
structure. So, we don't have to follow
any structure. With that, we also don't
have to maintain any relationships.
Suppose, if you want to add post and
comments, we can simply use any key.
Let's say post is the key here, post one
maybe. And in order to have that object,
we can have any ID, post ID, or any
content. So, these all things are key
basically of this object. Post ID can be
a number. Post content can be anything.
And with that, we can have comments and
we can have array of objects in
comments. We can have multiple comments
field also.
Let's say it can have a comment ID and
the actual content of the comment. Like
this, it can have multiple objects and
this all can be done without any
relationships. So, this is a good
example of key-value pair, which we
normally use in our cache, cookies, or
any other places where we don't need to
maintain any structure. Now, let's move
to the second one, columnar DB. So, the
thing is whenever we are having any
table, let's say we have student table,
which have typical ID, a unique
identifier, the name, and then the
marks. Maybe total marks of all the
students. So, ID is one, name is Akshat,
and marks is maybe 90. With that, let's
have one more record. The ID is two,
name is Gaurav, and the marks maybe is
95. Now, what we have to do is we have
to get the average marks of class. So,
the students is basically maintaining a
class, we are assuming that, and all the
marks, if we sum them, we will get the
total marks, and if we divide them with
the total number of students, we will
get the aggregated marks. Now, in order
to do that, if we do it in a SQL manner,
the SQL manner basically reads the data
from left to right. So, even if we don't
require any name in our data, we have to
still read our table from left to right
for each and every row. This is a heavy
task, right? Because we don't need those
values. Here, we have only three
columns. What if we have 17 columns?
Then also we have to read all the rows
from left to right, and which is not
mandatory.
So, in order to fix this issue, we have
columnar DB. What columnar DB does is it
gives us the flexibility to read the
data column-wise. So, instead of reading
it row-wise, now we can read the data
column-wise. That means if you want to
deal with only marks, we can read only
marks data column-wise. And then we can
aggregate all the marks. And if we want
some other column, those can be also
read by column-wise. And how we can link
them? We can link them with the common
IDs. So, the common IDs will be there
whenever we are reading column-wise, and
then it will be easier and faster
through our unique identifier that is ID
here. Where we are reading the data, but
column-wise instead of row-wise. The
common examples of columnar DB are
Google BigQuery, Amazon Redshift, and
Snowflake.
So, all in all, if we have to read a lot
of data, we can go for columnar DB. So,
it is good for analysis. And imagine
writing the data into columnar DB, that
is going to take again a lot of time
because we have to write also
column-wise. So, that means we have to
first maintain an ID, and then the name
will be written, and then the marks will
be written, and then the other values if
we have them. Those will be also
written. So, in order to read the value,
it is useful. And when it comes to
write, it is going to take more time
than a SQL database. The third kind of
NoSQL database is graph DB. Imagine, we
have all seen those movies where
detectives basically pinpoint many
photos and join them with some thread or
something, right? So, like this only, we
have graph DB where we have different
nodes, and they are joined by the
threads which are called edge. So, every
edge basically represent a common
relationships between two nodes. Two
nodes are basically the entities, and
edge signifies the relationship between
them. Now, what is different in graph DB
is both nodes and edges can have
properties. Suppose we are creating any
node which is student, maybe, and which
contain all the student information.
Now, we have another node for course,
maybe, and we can name the relationship
anything. Maybe it is enrolled. Now, the
enrolled can also have properties in it.
It can contain year, it can contain
marks. It can contain year of passing
maybe. And all of these things the edge
or the relationship can also have. So,
this is what makes our system unique.
Graph DBs are often used by data
scientists to find patterns between
different scenarios. It works basically
in the same level which we see in any
detective movie as well. So, if you want
to work with graph DB, we can learn
Gremlin or we can go for
SparkQL. Also, we can use Cypher in
order to work with graph DB. As I said,
it is used in huge companies whenever we
are dealing with a huge amount of data
in order to face some patterns or
basically analyze the customer behavior
on our site. So, as we can see the two
entities are going to have some
properties and also the relationship
between them will also have some
properties. Also, two entities can have
different relationships. And also it can
be linked via different entities as
well. So, student basically studies in
this college. We can write all the
parameters of the studies edge also. And
college provides the course. So, in this
provide relationship also we can have
multiple properties. So, which makes our
graph DB complex. And also since we are
dealing with multiple entities with
properties and also multiple
relationship with different properties,
it is going to be a bit slow. With this,
let's move to our final and the most
famous NoSQL database which is document
DB. So, in document DB we will have some
document and in that document we can
write JSON and can store data with any
length. We don't have to follow any
structure, we don't have to follow any
schema. So, that is flexible in nature.
Also, it is schema-less. So, similarly,
document DB also don't have to follow
any relationship. At this point, if we
think about this, the graph QL is kind
of an exception on the borderline there
because we do have relationships between
them and with relationships, we also
have properties of those relationships,
which makes it entirely unique and
different from no sequel and sequel
both. But on a large level, it comes
under the category of no sequel only.
The common examples of document DB is
CouchDB and also MongoDB is widely used.
So, that is also an example of our
document DB only. Our document DB is
highly used in logging the systems
because we need flexible log structures.
So, it is highly used in logging,
logging the error, maybe logging the
warn messages, logging any kind of
stuff. Also, it can be used to handle
profile section because the profile
section can also contain different
values for different users. Suppose some
have given all the values, some have
given less values. So, that can be
easily maintained through profile. And
with that, if we talk about content like
content on any application, let's say
Instagram, we have different kind of
content. We can have image, we can have
video, or we can have some text. If we
talk about Facebook here. Now, these
different kind of posts or content don't
have to go to different tables. In
document DB, we can basically create a
single document and curate all of these
content into the same document,
obviously with different attributes and
values. So, again, as it is a no sequel
DB, it is going to be complex and the
retrieval of any information will be
faster. Easily, any no sequel databases
can be used for any kind of analysis.
So, this is all about the types of no
sequel databases. After understanding
about databases, one thing is very sure
that each and every important
information needs to be stored in
databases and will be retrieved from
there itself. That means if we have any
user here who is trying to access, let's
say telesco.com only from their mobile
application, the request eventually go
to our backend and from backend if we
are showing any information, it will be
retrieved from the database and will be
shown to our user. Now, the thing is for
every information we need to hit our
database. So,
even if we have a homepage which have,
let's say, three most popular courses
aligned like this. This is our course
one, course two, and course three. Maybe
the details of each course are visible.
One, a thumbnail is visible. Then, with
that the name is visible. Maybe the
price is also visible. And with price,
the discounted price is also visible.
Also, let's say we are showing some of
the important sections. So, yeah. These
are all the details of every course
which is visible on our homepage. Now,
this maybe is coming from any DNS
because that's where we are saving any
static files, remember? The name will be
stored in a table. Let's say the table
name is course or courses. For price, we
may have the prices in the courses table
itself, but according to area, according
to the currency, the price keeps on
changing. So, we will create a separate
tables for prices. So, the price is
coming from price. Then, the discount
price also based on the locality. So,
these both details are coming from the
same place, prices table. And then, the
important section. Important section may
have some criteria or some course
content which we need to show. So, this
maybe it is coming from courses section
only, but courses section normally have
the course main course detail and then
accordingly we can have different
sections. So this is maybe courses table
and we can create some other table which
will have all the information for
courses. We can name it as course info.
So here also the things are coming from
course info table.
So that means in order to show these
three courses we are hitting 1 2 3 and 4
resources, three tables and one DNS. And
that means that for every user who is
trying to access our site telesco.com,
it is going to hit all of these four
resources again and again. So if the
count increases to 10,000 maybe
daily active users that means we are
going to hit the database and the DNS
10,000 times for each and every user.
Also don't forget that the courses are
three.
Maybe in future we will increase the
number to six. So that means 10,000
requests multiplied by six
that is 60,000 requests. In short, for
every view we are hitting six courses
and from those six courses we are
hitting these four sections. So for
every user we are hitting 24 requests.
This is totally going to break our
system because 24 requests means it will
add latency to our home page. And in
these fast times where nobody wants to
wait for any resources, these latency
are eventually going to affect our
business.
Also the more the latency the poor the
performance. So this is clearly not a
good sign. We can't keep hitting our
databases again and again in order to
fetch the same information for each
user. We need some other mechanism. So
this is where cache comes into the
picture.
Now let's understand what cache is.
Cache is nothing but a memory storage,
which is away from databases and it can
either be in our backend or into our
front end in order to load the resources
faster. Now, how does it work? Let's
take the same example. Our user is
trying to access telesco.com and is
hitting backend
to get the information and backend
eventually is hitting database to get
the information. Now, once we understand
that these six courses are going to be
static on our home page, right? So, that
means we don't want to fetch this
information again and again from our
databases. So, what will we do?
We will eventually get that particular
information and put it onto our backend
either or we can also put the same
information on our frontend storage as
well. So, when the user again comes on
telesco.com, we don't have to hit the
entire database again and again. We have
that information handy on our backend or
frontend or in both the areas. So,
whenever we hit our home page again, we
can get those information directly
through our cache, which is stored
either on our frontend or on our
backend. Here, we are saying that our
user is accessing mobile device. Maybe
it is accessing our site through any web
application.
So, there also we can handle cache,
okay? These caches, which are on client
side, are normally referred as client
side cache. And the data, which we
stored in backend systems, are referred
as server side cache. In databases also,
there is some mechanisms where they can
also store the information ahead of
time, that is known as well. And we can
get the most requested information from
this data only. We don't need to hit our
database tables. Also, we can have cache
in DB as well, which is known as
database cache. Up to this point, we
have understand why do we need cache
from a very high level point. Now, let's
understand how can we implement the
caches in the real system. In order to
understand them, first we have to make
sure that we know some of the terms.
The first term which we need to know is
cache hit. Now, what is cache hit? Cache
hit basically means let's say we have
any request which is coming from our
front end to back end. Let's say we have
cache installed here and here is our
final DB. Now, whenever we are hitting
the request and we found the data in the
cache, that is known as a cache hit
scenario where the data is present in
the cache and we don't need to hit our
database. But, if the data which we are
trying to get is not in cache and we
have to hit our database, that is known
as cache miss. So, what is cache miss
here? Cache miss is again we are trying
to access some data
from our back end and we don't find the
data in our cache. Instead, we have to
get to our database to fetch that
particular data. So, from where we are
getting the data in cache miss? We are
getting it from database. And from where
we are getting the data in cache hit
situation? We are getting it from the
cache itself. So, whenever we hit a
cache hit kind of situation, our
responses will be faster. And similarly,
in cache miss, our responses are going
to be slower. With this, the next term
which we need to know is TTL.
TTL basically means time to live. Time
to live basically specifies for how long
the data is going to be in the cache. In
other words, we can also say after how
much time our data is going to expire
from cache. Up to now, I hope we have
understood what cache really is.
So, how do we store data in cache? We
store the data in cache in normally a
key value form. And we get these data by
using the keys, obviously, and by value,
we also have TTL with them.
In order to check whether the time is
expired for that particular key-value
pair or not. If it is expired, this
key-value pair will be eliminated from
our cache so that it makes room for
having more data. So, at this point, we
understand that the cache works faster
than our databases. Then, why don't we
get all the data from our databases and
put it in cache so that every request
which we make will be faster. If you
understand software development, you
understand that I'm asking a silly
question. But, if you are new, just hear
me out. Now, this is those kind of
question where the answer lies in the
question itself. We are saying that
cache is faster. Now, let's understand
why it is faster. Because we are only
collecting the information which is
frequently used. Okay, so that's why the
size of our cache is very smaller than
our DB. Because DB have all the
information which our site needs. So,
that means the size of cache is limited.
And we have to keep refreshing the data
in cache so that it performs well.
Why do we need to refresh? Let's say
today we have some campaign of maybe
selling our most sellable course, maybe
Java we are selling on the let's go. We
are saying mastering Java. So, you can
master Java. This is our most prominent
course today. But, tomorrow we change
our focus from Java to maybe AI. Let's
say most students are not interested to
learn Java at that time. But, are
interested to learn AI. At that time, we
have to replace the content of Java to
AI.
So that we can get this information
faster. Why it is faster? Because it is
easy to find something in a limited
space than in the entire database. That
is why cache is faster. And the second
point is if let's say somehow we managed
to create a large size of cache itself
and we managed to save our entire
database into cache, in that case, every
search query or everything which we are
trying to find is going to take a longer
time into our cache itself. So, it
defeats the whole purpose of having a
cache. That is to reduce the latency and
to get the performance better. So, with
this two points are very clear. First is
the size of our cache needs to be way
smaller than the size of our DB so that
we can get the responses very faster.
And now that we have size constraint, we
need to keep updating the cache data in
order to get the values which are
relevant to our users. Now, I think we
are very sure what cache is, why the
size is limited, why do we need to
refresh the content again and again.
Now, it's time to go a bit deeper. Let's
go into the strategies through which we
can update the cache data. The first
strategy is read through cache. As the
name suggests, read through cache
strategy is designed to handle the reads
from the cache only, not the rights. So,
let me create a diagram. Let's say this
is our server. Here we have our back end
and our cache and with this we have our
actual database here. So, read through
the query suggests that every time we
have a request of getting any
information, we are only going to read
through cache. We are not going to hit
database. We are only going to read the
information from cache. And if and only
if the data is not present in our cache,
then only we will need to hit our
database.
Again, for right, we are not going to
write any value in our cache. We are
directly going to write our data into
our database. So, in order to read, we
are going to hit our cache, and in order
to write, we are going to hit our
databases. Here, clearly, we can have
two cases. The first case is
cache hit. In case of cache hit, that
means we are trying to get some
information, the back end is going to
hit our cache, and cache have that
value, right? Cache returns that value
to our back end system. So, this is
good. This means that we are going to
have a faster retrieval. Then, we have
our case two for cache miss. What
happens here is our back end is again
going to ask our cache whether they have
the information or not. And in this
case, as this is cache miss, that means
we don't have that information into our
cache. So, here, cache itself is going
to ask to our database
and fetch that particular data. So,
database is going to give that
information to our cache, and then cache
will return the data again to BE. So,
clearly, it adds a next level step to
get the data from database, which is
going to make this request call slower.
So, that means whenever we are reading
any data, we are not going to go to
database directly. Our cache will be
connecting to database and getting the
value which is required for our back
end. And from cache, we are going to
give that value again to back end in
order to process it. So, here, if you
see what we are doing, we are not adding
any recently added data directly to our
cache. We are adding data directly to
our databases, and only the data which
is getting retrieved from our users are
going to be in our cache. Let's say,
from our back end, we are making an
order placement, and that data we are
not seeing that again. So, that means
that data is never going to come to our
cache because no one is accessing that.
Only the data which user is accessing
are going to come to our cache, which
makes our cache always ready with the
information which user wants. So, this
is all about RTC. Let's move to the
second strategy, which is WTC. WTC
stands for write through cache. As in
RTC, the strategy is only for reading,
here this strategy is only for writing.
So, that means we have again our client
application. Here we have our backend
and our cache with our database. Now,
whenever we are going to write any data,
we're going to write it into cache and
then eventually from cache, the data is
going to be there into our databases.
So, this means whenever we are writing
any data, we're going to write it into
our cache first and from cache, the data
is going to be written into databases
finally. So, by doing this, our cache
data is always going to be updated with
the latest value. Where it can be used?
It can be used if we talk about stock
values, where we always want to see the
latest data. And with this, it can be
used to any other application where we
want to see the latest data first. With
this, let's move to the third strategy,
which is WAC. WAC basically stands for
write around cache. So, up to now, we
have only talked about either read or
write. With WAC, we're going to talk
about read and write both into one
strategy. So, read around cache. So,
when it comes to write, we are going to
write the data from any query from our
client, it is going to call our backend
services and from backend, we are
directly going to write the data into
our databases. No cache is in between.
So, that means all the writes will be
directly dumped into our database. And
we haven't updated any cache here. So,
this is about write. And with read, what
we are doing, whenever we are reading
any data, we are going to read it always
from cache. If the data is there in our
cache, that is a cache hit situation,
then we're going to get this information
directly. So, this is good. If we get
any cache miss kind of situation, where
the data is not there in our cache, the
cache is going to call database and
update the value in the cache first and
then will give the value to our backend.
So, this is how WAC works. You may think
that it is a combination of RTC and WDC,
which is correct. So, in RTC and WDC, we
are only talking about read and write
respectively. But, in WAC, we are
talking about the entire flow of data.
So, it is heavily used in applications
like Twitter. Now, it is called X. So,
here the scenario is we have a lot of
users who are going to create tweets.
But, we can't directly create those
tweets and save them in our cache,
right? And whenever the users are trying
to access any tweet, at this point it is
decided to keep this tweet in cache
memory because now it can be used by
some other users as well. So, we don't
decide the importance of any tweet at
the time of its creation. We decide the
importance at the time of reading those
tweets, right? So, with WAC, we also
have one more strategy, which is WBC.
WBC basically stands for write back
cache, which basically means whenever we
are trying to write any data, it is
going to be written into our cache and
at this point our write operation is
completed. We are going to write this
data into our database, but this is an
async process. So, that means while
writing our data, we don't care about
consistency much, but we care about
speed. We want to get the update faster.
So, whenever we write any data into our
cache, it is going to give us the okay
response, maybe.
And after that, the data will be dropped
into our databases eventually. Now, as
this is async process, it is very
possible that we may get some or other
error here.
So, we have to handle this kind of
scenario or strategy very carefully. And
now, let's talk about read. While
reading the data, again, we are going to
read the entire data from our cache
itself, right? That is the whole point
of having a cache. So, as most of our
data is directly written into cache, it
is most likely to have the most updated
values. So, normally, it is going to
give cache hit. And if we get cache miss
kind of situation, so we are again going
to call our database, update our cache,
and from cache, we are again going to
read the value from our application. So,
as you can see the WAC and WBC are
pretty common, but here we are using
async to write the data. That means we
are trading off between speed and
consistency. So, even if our data is not
consistent, we are making sure that the
speed of application remains fast. Now,
WBCs are basically used where we have a
high write traffic. The most common
example of this can be any food delivery
application. Let's say Swiggy or Zomato.
So, in Zomato or Swiggy kind of
application, what normally happens is at
a particular time, we may be handling
multiple orders with multiple status.
And the status keeps on changing. So,
instead of saving all the data changes
into our database, we choose to save
them into cache. Because we know that
the status of this particular order will
change very fast. So, we use WAL here
because we need to update the
information fast and also the user who
have created the order are also going to
see the latest information through this
cache only. And in the back process or
in the backend or async manner, we are
going to keep updating our databases.
So, this way it is going to handle
million of request and status updates at
a particular time. So, up to now we have
understood that how do we handle the
data into our cache? But, we have only
added the data. We haven't deleted the
data. So, now let's understand the cache
eviction policies through which we are
going to remove the data which is not
used by our cache. Here I'm writing
policies here. We can easily use
strategies. I just wanted to sound
little different. So, that's why I added
policies.
Um just for fun, you may say. So, the
first policy basically is LRU. LRU
basically stands for least recent used.
So, as the name suggest, least recent
used.
That means the data which is not used
recently will be evicted from our cache.
Suppose Apple launches a new iPhone
which is 17 Pro
Max updated something something very
acronym synonyms of Pro Max Ultra
something. And now everyone is keep
looking for 17 Pro. No one is in today's
time looking for 11. So, that means 11
is a stale data which was used earlier
by our cache maybe. But, in today's time
we don't need to store that information
into our cache because a very few clicks
were there who were still searching for
11. Now, with this let's talk about the
second policy which is MRU, the exact
opposite of LRU.
There we were saying least here we will
say most recent used. So here we are
going to delete the data which is most
recently used. This sound a bit strange,
right? Why do we delete something which
is most recently used?
But if you think about it, let's say you
are surfing through an e-commerce
application and you already apply a
particular coupon. So in that case we
don't need that particular coupon into
our cache, right? So we will directly
remove that. Also, if you think about
it, we have streaming applications. For
example, let's say this YouTube only. So
in YouTube's the streaming normally
happens in sections. When you are
watching any video, let's say you have
watched the video till here. At this
point this data gets loaded.
And you may see a white line moving
forward which denotes that the data up
to that point is loaded right now. Let's
say currently we are at this point and
this data is already loaded. Now at this
point we don't need the previous video
information. This can easily be deleted
from our cache at least.
Because in this case the chances of me
going back into the video is very slow.
So that's where we remove the most
recently used data. So I hope you are
getting all the points. The next part,
the next eviction policy is LFU. LFU
basically stands for least frequently
used. So LFU basically means the data
which is not frequently used will be
evicted from our cache. What does that
mean? Let's say today I opened any e-com
application and search for plant. Also,
I am a gadget guy. I basically purchase
a lot of gadgets. So suppose I have a
history of seeing any secondary screen
also. With that I also purchase a lot of
clothes. So clothes section is also
there. Now, between these three, I keep
on seeing about the secondary screen and
I keep on seeing the clothes in one or
the other manner, but the plant search I
only did once. Maybe I saw some YouTube
video or liked some plant into some
Instagram story of others. Only at that
time I thought of purchasing a plant and
after that I didn't think about it
again.
So, that means the plant is the least
frequently used terms for my history of
that e-commerce applications. So, now
whenever we are going to evict any data,
it is going to be this. So, this is
another strategy where we remove the
least frequently used data from our
cache. After LFU, we have two standard
ways of handling cache data or removing
the cache data. The first strategy is
FIFO. We all know about it. FIFO
basically stands for
first in, first out. Suppose we have
assigned 180 MB to our cache and we
don't want to exceed this limit.
Now, whenever we are trying to add any
value and and if we have reached our
limit, first data which we are going to
remove is the first data which we
entered into the cache without thinking
about anything, without thinking about
frequency, without thinking about how
recently they are being used. We will
simply remove the first added data from
our cache. And with this we have the
last eviction policy which is LIFO. LIFO
basically stands for last in, first out.
You may think of a stack kind of
situation here, right? Where the last
object which is inserted will be evicted
first.
So, this is how LIFO works. So, in this
what we will do, again we have 180 MB
memory and here we I have written bytes.
Here it is bits. Don't worry about that.
It doesn't matter. Now, in that 180 MB
memory, I don't want to store any other
information. So, what information will I
remove? I'll remove the most recent
information which I added. Okay? So,
maybe this information which is added
first
will be there for the longest time, and
we will keep on removing this or this or
this information in order to have more
space for the added information. So,
this is about LIFO and FIFO. I have not
added any application areas for LIFO and
FIFO both. I want you to explore this a
bit and tell me in the comments. And
with this, we have understood about
caches, their eviction policies, and how
do we add the data into our cache. I
hope you all get it. Up to now, we have
understood how our request basically
flows through different components of
our system and ultimately provide some
information to our user. Right? We have
seen who our customer is. They're going
to interact with either some web
application or maybe some mobile
application.
From where the request will flow to a
server where our back-end code is, and
through the server, we will hit some or
the other database in order to retrieve
that information and provide it back to
the user. With this, we have also
discussed about DNS through which our
clients are going to get the address of
our server. And then, the cycle repeats.
So, this is all we know up to now. This
all looks very good, works very
efficiently up to a single point. Why?
Because here we are using only single
server, and a single server can scale
only up to certain limits.
Suppose we are already using 128 GB of
our server, and somehow our processes
are consuming this much resources. That
means we are getting more requests than
we were expecting. Maybe our app is
tracking attraction now from across the
globe. And at that time, we have no
choice but to scale our system. In order
to scale the system, this is the first
step which you can think of.
So, instead of having a single server,
we need to have multiple servers. Let's
name them server one and server two.
So, we have two servers. That means our
client need to give the call to either
server one or server two. But, how our
client is going to decide where to give
information to? This is where we need to
discuss one more component which is load
balancer. Now, let's make the diagram
again with load balancer. Now, what
happens? Our client or the user is going
to access the same information from any
mobile application or website, and they
are going to hit DNS in order to get the
IP address of server. Up to now, things
are not changing. Everything is pretty
straightforward. But, now our DNS is not
going to give the IP address of the
actual server, but it is going to give
the IP address of load balancer. And
then, the load balancer is connected to
multiple servers. Suppose this is server
one,
this is server two, this is server
three. And then, the load balancer
basically decides to which server our
request should go to, whether it should
go to S1, S2, or S3. And if it goes to
S1, S2, and S3, they are basically going
to connect to a database. Maybe they are
connected to same database, or there can
be a possibility that S3 is managing the
data in some other database, and through
migration, replication, or partitioning,
we are handling the data between those
databases as well. So, this is what the
actual picture of a microservice
applications looks like. Where the load
balancer is going to play a huge role in
order to pass those requests from client
to server. Now, if we talk about load
balancer in brief, our load balancer
mainly is going to perform two tasks.
The first task is how do it give
responses to the perfect server from
which it can get the response faster,
right? So, the first thing is choosing
the server. Also, if we are giving the
responsibility of choosing the server to
load balancer, that means load balancer
should know how our servers are
performing in the current situation. So
that no server will be overheated and no
server will be underutilized. So, the
second thing
which load balancers are going to do is
maintaining the health checks of our
server. So that whenever any new request
comes to load balancer, they are the one
who is going to decide whichever server
is working in a fine condition plus can
handle that request pretty well.
So now, let's discuss these both points
one by one. So, in order to choose a
server, we need some algorithms, right?
So, there are various algorithms and
hybrids also from which our load server
decides where the request should go. So,
let's discuss those algorithms. The
first algorithm here is round robin.
Round robin is the most simplistic
approach in order to pick the web server
for the next request. So, in round
robin, what do we do? Suppose this is
our load balancer and we have our server
one here, server two here, and server
three here. Load balancer is now going
to pick server one for the first
request. For second request, it is going
to pick server two. For third request,
it is going to pick server three. And
where will the fourth request go? It
will again go to server one. Then five
for server two and six for server three.
And this is how every request will keep
generating and going to the next server
which is in the list. So, there is no
much calculation needed here. We only
need to know that we are following the
sequence of S1, S2, and S3. And if the
current request is being processed by
S2, the next request is going to be on
S3. This is how round robin works. So,
that means round robin send request one
by one, right? Apart from this, it
doesn't check anything, which makes the
round robin very easy to implement. That
means if you are using round robin
algorithm, each server are going to
handle almost equal number of requests.
So, we can say the distribution of
requests are equal. And as in this
algorithm, we are not managing any state
of any server, basically, we'll manage
only a single counter from which we are
going to decide where the next request
is going to be. And also, we need to
manage where the current request is. So,
with simple implementation, we can
easily set up round robin into a load
balancer. But, there are some demerits
to it. What if server one, server two,
server three doesn't have equal
configurations? What if the RAM
configuration between them is different?
What if the storage is different? What
if the CPU power is different? Let's say
for S1, RAM is 4GB.
For S2, it is 8GB.
For S3, it is 16GB.
Again, the storage, let's say for server
one, we are using maybe 100GB storage.
For server two, we are using 200GB
storage. And for server three, we are
using 500GB of storage. Also, the CPU,
let's say it is 16 core, it is 32, it is
64 core. So, the configurations are
entirely different. And what we are
doing in round robin, we are not
checking any of these matrixes, but we
are simply following the next counter.
So, that means even if with uneven
configurations,
the load on server one, server two, and
server three are going to be same. And
this is unfair because the server three
may do all the task very frequently and
can sit idle. Whereas server one will
struggle to complete the task and it
will be overloaded, maybe heat up, maybe
stop working. So, this is the demerits
of using round robin. Now, let's jump to
the second algorithm, which is
geo-based, which basically states that
suppose this is our load balancer and we
have our server one again and server two
again. This is in India and this is in
US. So, if the majority of users are
from India and some users are from US,
that means they need to hit their
respective servers in order to process
the information. That way,
they will get the response faster
because if I'm sitting in India and I'm
requesting any information from the
Indian server, it will be faster to
process those information in the Indian
server as well with respect to
processing the same information through
US servers because the connections are
going to take time and which will
increase the latency of the application,
which the user doesn't want, right? So,
this is what our second algorithm
implies. It is based on geo addresses of
the particular user. So, here also we
are not maintaining any matrices for
server specifications. We are only
maintaining two matrices. The number one
matrix is where the server is and the
second matrix is from where are we
getting the request or we can say where
the user is. Now, this algorithm is used
by many applications across the world
whichever have the global appearance.
Whenever we are trying to hit google.com
or facebook.com or any other global
applications, our request basically
moves to the server whichever is closest
to us. Maybe we are residing in this
area. Here we have some server and also
here we have some server. Maybe this is
US server, this is Indian server.
So, our server needs to be situated near
us so that we get the response faster
and all the requests are maintained
through the same server. So, whenever
I'm trying to access any information,
they are going to be addressed through
the same server. So, that means our
session and other informations are also
will be in sync for this particular
user. In this algorithm, there are some
disadvantages as well, right? Because
now our load server needs to manage more
information.
Now, it needs to know from where the
requests are coming and it needs to know
where each and every server is located.
So, this is a lot of information to be
seen by load balancer. And now as our
servers are distributed across the
globe, we also need to maintain
databases accordingly. So, every region
may have their own databases for faster
retrieval. So, that will include the
computation power of replication and
partitioning, which we will be covering
in further series. Also, let's say
if we are using Indian server or this
server particularly, maybe there are two
servers in India. This is India B
server, this is India A server. For some
reason, this server breaks down.
Then we need to reroute our request to
this particular server, which is again
needs all the information which we are
accessing through this server. That
means the data or the application on
which we are working on should transfer
the data immediately to this server as
well. Even if the server A doesn't
crash, then we need all the information
which is being tracked by server A. But
this is a necessity in geo-based
location algorithm. Now, the third point
here is if any user is using VPN or
other proxy servers to change their
location, that means VPN or proxies can
mislead the traffic. With this, let's
move to our next algorithm, which is
least connection algorithm. So, in this,
what happens is we have our load
balancer in place.
And suppose we have two servers, server
one and server two. And server one and
server two at current times are managing
multiple requests, right? Suppose S1 is
maintaining
30 requests or 30 connections at this
particular time and S2 is maintaining 50
connections.
Now, whenever we get a new request, it
is going to be addressed by S1. Why?
Because S1 currently is having least
connections.
So, this is how our least connection
algorithm works. Whichever server have
the least connections, our next request
is going to that particular server. In
this algorithm also, we are not
considering any of the matrices of
server. We are also not maintaining any
of the requests or response time. We are
only maintaining the number of
connections. Let's say if these 30
requests are heavy request and these 50
are lightweight, then also the next
request is going to be taken care by S1,
which is wrong and it is going to take
time, but this is how our least
connections work. Then why do we use
this? Basically, the least connection
algos works very well when there are
sticky sessions. Now, what is sticky
session? Where we have to maintain a
proper channel for a particular
communication. Let's say we are using
web sockets for maintaining any kind of
application. Let's say we are
maintaining a chat application or a
video streaming application or maybe we
are handling some gaming kind of setup.
In all of these cases, we needs the
request and response to be faster, so we
will pass our request to those servers
who are having least connections
currently so that we can get the
response faster. Now, if we talk to
disadvantages, the first disadvantage is
this only heavy and lightweight. Maybe
these calls are for AI calls which are
going to take time and these calls are
basically chat calls or maybe some web
CTR calls or maybe some REST API calls
which are lightweighted normally. So,
they are working faster then also we
will send the next request to 30 until
the number of connections drops from 50
to maybe 29. Then only we will consider
S2. So, this is how we are going to
work. Now, if we talk about
disadvantages of least connections, the
first we already discussed. The second
disadvantage is that our load balancer
basically needs to maintain the number
of connections for each web server. So,
if S1 is maintaining 50 connections at
that time and it give response to one of
them, that means currently it is
maintaining 49 connections. It needs to
be updated to load balancer. So, our
node balancer will keep updating the
number of connections again and again
which is of course a tedious task. The
third disadvantage is we are only
considering least number of connections.
What if our server one is of very low
configuration than server two
and it is maintaining eight connections
at that time or request at that time and
this is maintaining 16.
It is easy for S2 to maintain 16
connections or maybe 100 connections and
it is hard to maintain 10 connections
for S1. Then also we will send the next
request to S1 because we are not
checking anything apart from number of
connections. So, this is how our least
connection algorithm is going to work.
After least connections come least time.
So, it is our fourth algorithm least
time algo. Suppose load balancer is
maintaining two web servers S1
and S2. The response time of S1 is
nearly about 50 ms. The average response
time, basically. It is handling some
thousand requests, and for server two,
it is currently 10 ms. So, in this
scenario, the next request is going to
be handled by server two. Because the
average response time of server two is
lesser than the average response time of
server one. Now, if we talk about
response time, if any server is having
less response time, that means the
configurations of those servers are
high. Right? That's why the response
time is low. So, this algorithm
basically takes care of the actual
matrices of the server by taking the
response time into measure. Now, the
least time algorithm is used in those
applications where we can't handle more
latency. That can be our real-time
applications, like the trading app or
even our search engines. In both of
these areas, we want the responses to be
very fast, and that's why we use least
time algorithms there. And now, if we
talk about least time algo's
disadvantage, that is our load balancer
needs to calculate the average response
time. So, with each request they are
sending to server, also the average
response time will be calculated. And
based on this, our load balancer needs
to manage where the next request is
going to be. So, calculating these
things can be really complex because if
we are calculating average time, that
means we need to know number of maybe
requests, and also the response time of
each and every response. Then only our
load balancer is going to calculate the
average response time. So, this is for
sure complex. Now, in this scenario, if
our web servers maintain any kind of
spike, it is going to affect the
calculations of our load balancer. So,
we need to be very careful there. Now,
let's talk about the fifth algorithm,
which is IP hash. Here, as the name
suggests, the IP of every request is
going to be processed by our load
balancer and will be given a unique
number.
And according to those numbers, our
servers are going to decide. Let's say
our server one is maintaining the hash
values from one to 10. So, that means
all the IPs which results between this
range are going to be addressed by S1
and maybe from 11 to 20 are addressed by
S2.
So, this is how IP hash algorithm works.
Every request is associated with some of
the other IP. They are going to process
through a hash function, and suppose the
result is five, then it is going to be
addressed by S1 because S1 is
maintaining one to 10. As we all know,
the IP of any user normally doesn't
change. That means this user for at
least one session is going to be
addressed through the same server. And
it will help. Basically, if we are
maintaining any session data, it is
going to help because we don't need to
replicate this data to other servers. We
are only handling these requests through
the same server. So, it is very easy.
Now, if the connection breaks in between
the session, then we are in problem. In
that case, this next request will go to
S2, and we need all the session data
here. And if that data is not
maintained, our user may need to address
or add the same data again into server
two, which is a loss case, which is not
recommended at all. So, for this to work
efficiently, our server basically needs
to be healthy enough to maintain a
proper session. Plus, even if the
session breaks due to any reason, due to
any server crash, it is very important
to replicate those data to other server
as well. The major disadvantage of this
is, as we are basically focused on IP
functions and hash functions, so scaling
is challenging here. Let's say we are
adding S3 here, then we again needs to
reconfigure our hash function. So, that
it consider S3 as well. And also, we
need to reassign these values also.
Maybe next time it is only handling 1 to
8, and maybe it is handling
uh
9 to 12 maybe, and this one is handling
12 to 20. So, whenever any server is
down or we are adding any new server,
basically the function will get affected
and it will reassign all the values to
the entire server. This is hard to scale
in this manner. And that's why it is not
recommended for most of the
microservices architecture we have
today. It is basically used where the
data was used in the old kind of
applications where the applications were
monolithic and mostly were legacy apps.
Like in today's scenario, if you want to
maintain a session of a particular user,
we don't only stick for that particular
session. We use many other tools like
JWT token we use, right? So, this is how
we are going to maintain an entire
connection through a server and a
client. We don't only rely on giving the
request to the same server again and
again. Even if the server changes, it is
going to recognize us through our JWT
token. And this is going to work
excellently with our distributed
systems,
microservices, and also if we use Redis.
In all these scenarios, we now don't
need IP hash functions. We don't need
our request to be handled through same
server. Even if the server changes, our
request or our session should be
consistent. Also, there is another
algorithm which is extension of round
robin, which is called weighted round
robin. So, in which the round robin, as
it was discussed, is working same, but
we added weight. So, that means
let's say this is S1, this is S2, and
this is S3. Let's say the RAM capacity
of S1 is 8 GB, for S2 it is 16, and for
S3 it is 32 GB. Now, what we are doing,
we are adding a weight to our request.
So, more the configuration,
more is going to be the weight. So, if
our load balancer basically keeps track
of this, so it knows that the S3 may
have weight three, S2 may have weight
two, and S1 may have weight one. So,
whenever a new request arrives at load
balancer, it is going to be addressed by
the one which have the most weight. So,
here the weight of S3 is maximum, so it
is going to be addressed by our S3
server. And then, based on the weight
and round robin fashion, our request are
going to be answered. So, with weighted
round robin algorithm also added in the
list, we have now covered all the
algorithms, major algorithms basically,
which we needs to know when we talk
about load balancers. Also, in real
base, no one algorithm basically works.
We always work with hybrid approach.
And load balancer basically balances
multiple algorithms. It is very possible
that we are using maybe IP hash with the
combination of round robin. And also,
other combinations are also possible.
Maybe we are combining two, maybe we are
combining all six at the same time. Like
here, we were talking about least time
algorithm and least connection
algorithm. We can combine these two
algorithms in order to get a better
algorithm. So, in order to fulfill our
requirement, we normally don't rely on a
single algorithm, we rely on multiple
hybrid algorithms. So, after discussing
all the algorithms, we know now how the
load balancer basically chooses a server
for the next request. The second thing
which load balancer does is doing the
health checks. Let's understand how load
balancer basically manages the health
checks. Here the thing is we have two
approaches how a load balancer can check
the health checks of entire servers.
Let's say we have a load balancer here
again and we have server one
and server two. The first way how we can
check any performance is by simply
seeing how server one and server two are
performing. We are not adding any new
request in server one or server two. We
are just observing how they are
responding to the actual requests. This
is the passive way of checking the
health. By this, we don't add any new
request to the servers. We don't
basically increase the load of any
server, but we simply observe. By we, I
mean load balancer. The load balancer
simply observe how the server one is
responding to request and maintain that
track. And let's say at a particular
point, if server one breaks or stops
responding, at that time the load
balancer knows about this by again
tracking the actual request. It doesn't
add any new request to server one. So,
this is what the passive way is. Now,
there is another way which is active
way. In active way, what a load balancer
does is it adds additional request to
our servers. And based on the responses
on those requests, it checks the actual
health of the server. So, these are the
two ways of checking the health of
servers. One by simply observing the
request and second by actively adding
the request to the servers. It is very
important to check the health of every
server. Why? Because it gives us the
pattern to take decisions. Like when to
scale or when to scale down. Both of
these cases are very usual by working on
any application on a day-to-day basis.
Let's suppose if we are maintaining our
application only for India region, in
that case also we know that in day time
the requests are going to be heavy.
Maybe in evening time it will be
heavier. And in night time it is going
to be little or lesser in count. So, at
that time we can maybe scale down our
server in the night time in order to
save some cost. So, let's see what are
the other parameters of health checks.
The first parameter of health check is
interval. This means how often do we
check our server? For example, it can be
maybe 5 seconds. So, if the case is
active, every 5 seconds I'll monitor all
the requests I've sent to the server and
see how the performance is going. And
also, in the passive case we'll see the
responses and calculate the matrices
every 5 seconds. The second params can
be time out. So, time out basically
means for how long do we wait to get the
response? Suppose there is any server
who normally takes from maybe 50
milliseconds
to the maximum of maybe 5 seconds
in order to process any request from a
long time. And now suddenly it is taking
10 seconds. So, this should be an
alarming case and we should immediately
check what went wrong. Okay, with that
particular web server. What is that
particular request which is taking 10
seconds? Is there any issue with the
code? Is there any issue with the
request? Does Do we change any
configuration? Or does our server is
managing some other task because of
which our this request is being
affected? We need to know the answers of
all of these questions in order to make
a better decision. We also need to know
about the threshold. Threshold can be
like healthy and unhealthy both, right?
In unhealthy, we basically take care of
the failed calls. So, we will basically
maybe set an alarm after 20 failed
calls. Okay? We can configure them based
on a particular region, based on a
particular area of our code, maybe a
route, particular subdomain of a route,
or maybe randomly. At a particular time,
if 20 calls fail, that is an alarming
situation for us. In normal scenario,
many application may give a faulty
response based on various factors. It
happens on a day-to-day basis, but after
that n threshold, after that count of
threshold, we should start investigating
the cause. And similarly, we have our
healthy threshold, where we should put
our marker maybe after every some calls.
So, maybe after every 100 calls, 100
positive calls, we need to check is
everything fine with those calls. The
response was expected, and the system is
working the way it should work. So,
these are the three health parameters of
our web servers which our load balancer
needs to check end over time in order to
make sure that our web servers are
working fine. And with this, we now
understand the two major factors of load
balancer, how it gives request to the
other server, and plus, how do it check
the health of every server. Now that we
have understood load balancer, it is
very important to know that in terms of
scaling, we also need to scale our
databases, right? So, in databases, what
normally happens is, suppose we have 100
GB of data, and we have a storage of
maybe 200 GB. This is still fine, right?
Maybe we have 1 TB of data, maybe 100 TB
of data, it doesn't matter. The thing
which matter is this data will
eventually get full.
And there will come a stage where you
can't expand your databases vertically.
You have to add more databases into our
system
whenever it comes to scaling. Also, now
that we know about load balancers, we
know that our server
can be placed into different regions of
our world, right? This can be placed
into US region, this can be placed into
India region only. And what we were
doing is we were adding both of these
data into single database. This is
effective if the user count is one, the
request we are getting are minimal. But
if the user increases, the traffic
increases, the data increases, it will
be hard to cater both of these servers
from the single database.
This is where we need to segregate this
data into multiple databases. One may be
catering Indian server and the other
might be catering the US server. Now,
this way we segregated our data into two
databases so that the requests can be
faster and also with that the data will
be segregated in such a manner that it
will be easy to maintain. Now, this can
be one of the case where we don't need
to have same data into two databases. In
this case, what we are doing, we are
assuming that the data in this data
table will be different from the data
into this database. Normally, this is
not the case, right? Normally, what can
happen is suppose we have multiple
servers for Indian region only. So, this
is also Indian region, this is also
Indian region. And we can have multiple
databases to cater the same server. Why?
Because if we have a single database and
if that fails, we don't have anywhere to
go and recover the data from. That's why
we manage multiple databases in order to
recover the data, maybe maintain the
data, and also it increase the
efficiency of our system by reducing the
latency. And also we may have some
portion of data here and some portion of
data here.
Both of these things are possible. These
things are basically
replication and partitioning. In
replication, what we do, we basically
copy the data from one database to other
database so that even if anything
happens to database one, we are able to
retrieve the data from database two.
Also, if database one is handling so
much calls, we can redirect those
requests to database two as well. And in
partitioning, what we do is we basically
divide the data into single database and
put one part here into other database
and the other part anywhere else. So
that if they are getting different
requests, it will be easier to cater
each and every request with their
specific database. We are going to cover
both of these topics, but for now let's
talk about replication. So we have
understood that replication basically
means keeping the copy of data. And why
are we doing this? Why are we making
copies? The first point is we are
avoiding or improving our single point
of failure issue. We don't want our
database to fail and our system to
collapse. We want some other database at
that time so that our system will be
working. The other reason of this is
availability. By having data into
multiple databases, our availability as
a system can increase. We can have
different data centers and it will
increase our performance. Also, as we
discussed, if we talk about different
localities or different regions of area,
we are increasing the performance by
adding particular database into that
site. So that will keep the data close
to our server and will be retrieved
faster. And also with all this, we are
eventually increasing our read
throughput. So suppose with a single
database, we were catering maybe 10,000
requests per second. Now with two
databases of same storage and data, we
can cater two times of the previous one.
So this is how the three throughput will
also increase. So after understanding
what replication is and why do we use
it, let's talk about how can we achieve
replication. So we are going to talk
about three algorithms. The first
algorithm is single leader replication.
That means there will be a database
which will be our leader and from the
leader only we will replicate the data
to other follower nodes or follower data
centers.
Suppose there is any user who is maybe
updating their profile picture. And when
they are updating their profile picture,
the request from our client basically
moves to a server and from server we are
only sending that request to our leader
only. We don't directly communicate to
our followers because it is the leader
who is going to then replicate our data
to followers. So every request will go
to our leader. To be specific, every
write request will go to our leader and
then the data will be replicated to our
followers. This is how a single leader
approach works. Let's understand this
through an another diagram. This is our
user. Maybe this is our leader and we
have our F1 follower database and
follower two. Assume this as a timeline,
okay? Now what we are going to do,
suppose at this point the user is
requesting to update the profile
picture. And this request will
eventually go to our leader node and
once the request is taken care by
leader,
they will send the same request to our
follower nodes as well.
Follower node one, maybe it is taking
longer time because it is far. So at
this point the request went to follower
one and follower two. At this point two
things can happen.
First thing is if the calls from leader
node to follower node are async, in that
case leader will do its work and update
the user that the task is done. And in
the back processes, the follower nodes
can continue updating the profile
picture and will eventually update our
leader that the task is done. This type
of request where leader updates the user
directly after updating the data without
getting the acknowledgement from these
follower nodes is called async
operation. Async basically means once
the request is catered by a leader, it
will directly update our user. And in
the back end, it will also share the
same request for follower one and
follower two node to perform the same
task and update our leader in the back
end. In this case, even if our F1 fails
to update, F2 fails to update, or
anything went wrong with these other
nodes, the leader have already given the
confirmation to our user. So, the task
is done. And eventually, when the nodes
are recovered, these operations will be
performed again on F1 and F2 to keep the
sync alive. After async, let's also talk
about sync approach, where the user
updates the profile picture.
The request basically carried by our
leader,
and it sends the update request to our
follower nodes as well,
F1 and F2. And the leader in this case
will not give any confirmation until it
get the okay response from both of our
followers. So, this gives okay,
and again, this gives okay. Once it get
confirmation from both of these follower
nodes, then only our database is going
to update our server, and eventually,
our user that the task is done. So, this
kind of approach is called sync
approach, where the leader will provide
the same operations to be performed by
F1 and F2. It will wait for the
responses, and once the response is
taken, then only it will update the
user. So, this is going to take a lot of
time, because our databases can be
placed into multiple places. There can
be two follower nodes, as we have
mentioned here, or more. So, in that
case, our time will increase, and
eventually, it will update the user
after getting the confirmation from each
and every follower. Now, let's talk
about advantages and disadvantages of
both of these approaches. If we talk
about synchronized approach, sync
approach, the advantage is all of the
followers will always have the updated
values. The other advantage of sync can
be, even if our leader fails, it will be
easier to select another leader, because
every node we know have the current
updated data. So, it will be easy to
migrate our leader to any of the
follower nodes, maybe follower one,
maybe follower two. The disadvantages
will be it is going to take a longer
time and also after getting any request,
our leader is waiting for the responses
from other follower nodes. It is going
to block that particular resource and
other operations on that particular
resource is also be blocked because of
our asset principles, right? And because
of these two disadvantages, we can say
that the sync operation here while
replication is an imprac- tical
approach. Any leader can't wait for all
the followers to update them first and
then they will update the user.
So, we always prefer async approach
here. In async approach, as we can see
clearly, no resources are blocked,
right? And the responses will also be
faster. And if we talk about
disadvantages,
we are basically trading off our
consistency. That means our data will be
mismatched. Suppose if a user is
updating any data to leader node and
leader provides the response to user,
our user will assume that the task is
done. So, even if they read from any
other follower nodes, the data should be
reflected. And in the async approach, it
is very possible that if user is trying
to access the data and it get connected
to any follower nodes, it will see the
stale data, which is eventually going to
update by our leader, but currently they
are seeing the stale data. So, this is
the issue in our async approach. Now,
before moving to the other algorithms,
let's first talk about how can we add a
new follower?
So, let's say we already have a system
where we have a leader and we have maybe
follower one and follower two already in
our system. Now, we need to add our
follower three. How can we add it? Now,
in order to add a new node into our
system, we need to perform some
operations. Our follower three will also
need to have all the data which our
leader have.
So, for that, what we do, we create
snapshot of the data from leader or
maybe we can create it from follower as
well. But, we need to make sure that if
we are picking follower two in order to
do the replication, we will again need
to use F2 only to update the data. Let's
say the current time is 12:55 p.m. and
we are taking the snapshot of F1 or F2
at this point. So, that means whatever
the state of our F2 is at this 12:55
p.m., we are only capturing the current
state of that particular database and we
are that dumping it into new node, which
is F3. Now, this process is going to
take time for sure. So, this is our
snapshot one, which is at 2:55. So, this
will contain the entire state of our F2
node. Now, what will happen again is
suppose the replication process took 2
hours or 3 hours, maybe, because the
data is huge and everything.
Now, we need to know what changes did
the F2 went through in this 2 and 3
hours. So, in that case, what we will
do, we will again take the snapshot, but
this time we don't have to capture the
entire state. We only need to capture
the difference between the snapshot and
the current time. So, we will create
another snapshot, which will include the
changes from 12:55 to current time. And
finally, we are going to dump this data
also in F3. Once we get to know that the
F3 is completely in sync with F2 and F2
is already in sync with leader, we will
make the connections of leader to our F3
also. And with this, we will have a new
follower node into our system with all
the updated data. After this, what
happens if the leader only fails? Let's
say we are having this topology again,
leader, F1, and F2.
Again, we have some databases linking.
The replication process is working fine,
then suddenly our leader fails.
In this case, we need to elect a new
leader. Now, how will we elect?
Basically, we will take care of two
factors. The first factor is which of
these F1 and F2 have the latest
information. So, we can take care of
that by seeing the timestamp of the
latest update. So, whichever we will
see, we will pick from F1 and F2, and we
will see which one is
updated recently. And the second step is
we need to update F1 to become a leader,
and our F2 to see F1 as a leader now.
So, this is the process of electing a
new leader when the leader goes down.
With this, you may have also heard these
terms like FS image or maybe added logs.
These things are highly used in the
replication process. FS image basically
con- tains the full metadata snapshot,
and added logs is used to update the
current changes. So, these both are also
used while doing the replication. And
while choosing the new leader or adding
a new follower, these two things are
also helpful. Now that we understand how
to add new leader, how to add new
follower, how to take care of things,
let's move to our second algorithm,
which is multi-leader algorithm. So, as
the name suggests, it is having multiple
leaders instead of one. So, that means
there is a possibility that every data
center, be it DS1 and DS2, will have
their bunch of leaders and followers.
So, maybe for DS1, we have this leader,
and we have follower like F1 here. Also,
here we have another leader and
follower. So, for DS2, the leader is
L2, and for DS1, the leader is L. Now,
what is going to happen? Let's say the
user is maintaining their records
through DS1. So, every record which DS1
handles will eventually first go to
their leader, and then the leader will
update their nodes. With this, now
leader also needs to update the other
leader into other data centers. And then
this leader is going to update these
nodes. This is how the process flows.
And similarly, if any request is being
made to this data center two, our leader
two is going to update their followers,
and also will send some query to other
leader to update the leader as well as
their followers. So, this is how a
multi-leader replication works, where
the leader will not communicate to each
and every nodes, but it will communicate
to leader nodes, and maybe their
follower nodes. So, this is going to
increase our performance. Also, we have
multiple leaders, that means even if a
leader node breaks, we can use the other
leaders to update the other nodes. So,
we have more tolerance to threats. Now,
since we have two leaders, we can also
perform collaborative operations, like
they can be working on the same file.
Now, we can work on the same Google
file, same Google sheet, those kind of
operation also we can perform, because
one request will not block that
resource, and the two requests can
eventually work simultaneously. Now,
when we are saying that both of these
resources are going to perform actions
on a similar table or single data, that
is going to increase our chances of
conflicts. Let me explain it through
another diagram. Let's say this is user
one, this is leader one. Here we have
leader two, and then we have another
user. Let me create the timelines again.
Let's say, user one and user two both
working on the same file, which is named
as A. Now, user one wants to rename that
file to B, and user two want to rename
that file to maybe C. Now, these both
will eventually hit their request to
their particular leaders. And based on
the async approaches we have seen, our
leaders can eventually give the okay
response to our users, right? That okay,
it is renamed. And here also, it can
give the response that okay, it is
renamed. So, these two users will see
two different data. This is not
possible, right? And also, our leader is
going to communicate with each other.
So, this will send the request to update
the data with C. And also, this leader
will also send the same request to
update it to B. Now, this is the
conflict, and how do we resolve it?
Basically, there are three ways of
resolving it. The first way of resolving
is the last right win. So, that is this
right is performed, let's say, at this
point, and this right is performed at
this point. So, as this operation is
performed later, so that means our L2
needs to update our file to C. So,
eventually, the file name will be C.
This is our first approach. The second
approach here is while working with
different leaders, we assign some IDs to
each and every leader. Suppose, leader
one have ID 10, and leader two have ID
11. Now, based on the ID, we can decide
which leader is more powerful, and which
leader we have to follow. Ultimately, if
leader two is of higher ID, that means
we have to follow leader two. And now,
it doesn't matter if the last right was
performed by L1 or L2. It is going to
update it with the value of L2 only. So,
here, instead of the last right, we are
going to focus on the ID. So, we can say
replica with higher ID wins. Replica is
nothing but a replication. Like, every
node which have the replica of content
can be called replica. So, we can write
leader also here. Okay, no issues. The
third approach basically is the approach
which we also see sometimes on Git when
we try to solve merge requests. So, the
same approach is used by the replication
process as well. So, whenever there are
conflicting situations, our leaders or
any other nodes are not going to solve
it. In this case, we will prompt our
user directly that the file name has
been changed to C and the last change
which you have made was B. So, do you
want to keep the current changes or do
you want to update it to C? It is up to
user. So, in this case, we need to add
the application logic to basically pass
our conflict to the users and eventually
user will update it.
After this, the third algorithm is
leaderless replication. So, in this
replication, we don't assign a specific
leader to any data center or to any
other node. We don't have any kind of
leader in this leaderless replication.
As the name suggests correctly, so here,
what do we do? Here, let's say we have
any client there. So, he is our user and
now we have some databases. Let's say
this is our node one, this is our node
two, this is our node three. So, these
are the three databases onto which our
data needs to be replicated. So, this
time whenever our user request for any
update, let's say again this user is
updating the profile picture, but this
time the request basically goes to all
of the nodes and eventually all will
update the data and provides a response
to the user. Here, the thing is in other
applications where we had a leader, we
can basically rely on that leader
replica and based on the response which
we get from leader, we can eventually
decide that whether the operation is
performed correctly or not. But here, we
don't have any leader. So, what can we
do? Do we wait for all the replicas to
answer us and at this point we update
our user or there is some other method?
Let's talk about that in a bit, but
before that, let's jot down some points.
So, the first point here is we don't
have any leader here. So, here we are
bound to send our queries to more than
one replicas, right? More than one
nodes. So, every query, when I say every
query, I mean both read as well as write
queries, will go to multiple nodes and
then collaboratively we'll get the
response. When I say read also, that
means let's say in this database only,
if there is some other user who is also
trying to access some values, and while
accessing some values, the user can use
this replica at this point or this
replica at this point or this replica at
this point. In all of these three
scenarios, the user is going to get
different values. So, here the user will
get updated profile, and from here they
will get the stale data. So, based on
multiple entries, we have to decide
whether to give this user updated data
or the stale data. So, this is our
struggle with this kind of replication.
But, apart from the struggles which we
see here, most of the applications in
databases use this setup. It is used by
various applications like Amazon Dynamo,
Riak, Cassandra, VM. All of these use
leaderless application. So, now the only
issue is should we wait for each and
every node to give us confirmation so
that we can proceed to tell any user any
response or is there any other way? So,
as you may have guessed, definitely we
can't wait for this long. There is a
way. That way is basically termed as
quorum. So, in quorum, what do we do?
Suppose we have total number of nodes as
three. We denote them by N, and for
reading, we have to use more than half
of the total nodes. So, it should be
more than N by 2. Again, for writing, we
should get the confirmation from more
than the half nodes. This way we
maintain the quorum and we will get the
responses which we want for. So, in the
same example, if I redraw it, suppose
the user is again going to update any
information, so updating profile picture
again maybe, and the request went like
this for first node, for second node
maybe the network is faster here, and
for the third node. Now, this is the
time each node took in order to perform
the operation. So, here we don't have to
wait for this response because we
already got the responses from more than
the half of the nodes. So, we can easily
say that profile picture is updated. So,
here we can confirm that the operation
of updating profile picture is done.
Again, if a new user appears here, and
the user is trying to access the value,
so it can basically sends a read
operation from these all nodes. Maybe at
this point, maybe at this point. Suppose
this point gives a result here, then
this point also gives a result here. So,
in these two responses, the user is
getting different values because this is
giving them stale data, and this is
giving them updated data because the
update is already done here, right? So,
in this case, there are various other
mechanisms also. You can go for
timestamp, or they can go for any other
mechanisms. But, let's say they don't go
for any other mechanism. There is one
more mechanism here where that is if the
requests are equal, and we are still
getting the different data, we will
consider the third request and response,
and then again calculate the results.
So, here we are getting updated from two
of the nodes, and we are getting stale
value from one of them. So, we will move
ahead with the updated value, and this
user will get the updated profile
picture. So, there can be various ways
of solving this conflicts, but the thing
is ultimately the user don't have to
wait for each and every response. This
is a special case where half of the
nodes are saying that things are done,
and half are saying things are not done.
We don't have three servers also. We
have more than 10 or 12 servers in a
large system. So, this case becomes a
rare case. So, yeah, this is all about
the replication which we needs to know
at this point. So, after replication,
the other way of segregating our data
into multiple nodes in order to scale
them properly is partition. Now, before
moving to partition, first see what can
be the issue with replication.
Replication basically suggests that we
will copy entire data to other node.
What if the data is so huge that we
can't have them in one node? With this,
the second concern is what if the data
is so huge that even with secondary
indexes, our time of searching any
element is getting worse and worse. So,
with these two concerns, we can't really
have all of the data in one database and
same data in other database. What can we
do then? We can easily or through some
logic break the system. We will do the
partitioning of data and maybe place
some amount of data here and other
amount of data in some other node. And
then, we can replicate this partition
data. Why? Because this data is
comparatively smaller and it will be
easier to manage. Let's say, in a
particular node, we are only saying that
we will store up to 10,000 records. And
then, once we hit this point, we will
again create a new partition and will
add the new records there. Or maybe
divide these records into 5,000. So,
these all things can be done only when
we have a new way of partitioning the
data. So, this is what partition really
is. While partitioning the data, there
is only a single rule. That is, if we
are doing the partitions
like this, then if we combine them, it
should give us the entire data set. This
is the only condition which is required
for partition. And And makes sense, too.
We don't want to lose any data, right?
So, this is our first condition and the
second condition is that let's say we
have again two partitions. Now, we want
our data to be equally distributed among
them. We don't want any nodes to get
let's say consumed by 90% of data and
here we only have 10% of data because
this basically beats the reasoning of
partitioning. We are doing partitioning
so that every node will be able to
access some data and will be able to
work frequently. So, basically we are
saying that the data should be evenly
distributed. So, these are the two major
conditions of partitioning. Apart from
this, everything works fine. So, the
first condition makes sense. It will
take care of itself and in order to
fulfill second condition, we have to
basically maintain some system where we
will protect the database to get
overloaded or to get underutilized like
this. So, now let's talk about those
solutions. So, the first thing here is
we will partition using key. Let's say
we have some table, maybe user table. We
are handling these entities and then we
have some ID here, user one or user two
and the series goes like this. So, what
we will do? We will basically in the
partitioning based on the keys will
insert the values. Let's say this user
entity can hold up to 10,000
or maybe 100,000 values. So, what we
will do? We will divide these 100,000 to
50,000 here and 50,000 here. So, that
means from user one to user 50,000,
these data will go to the node one or we
can say partition one and the users from
user ID maybe 50,000 one to user ID
100,000 will go into partition two.
So, this is how we will segregate our
data so that it will be easier to
retrieve the data afterwards as well.
This may looks fair on the surface
value, but it is quite messy. What if
these users are from different regions?
What if half of them from 1 to 50,000
are from India and half of them are from
US? Maybe here also they are distributed
like this only. So, half of them are
from India and half of them are from US.
So, in that case, both of these nodes
will be busy. This is a good scenario
because both of the nodes will be used
and will be busy in order to provide the
information. And also it is possible
that the node one is only taking care of
India request
and the US request are being taken care
by partition two or node two. So, in
this case what happens? Let's say the
application is very popular in US, but
is not that popular in India. So, maybe
P1 is getting maybe 100 requests per
second and on the other hand our
partition two is getting maybe 10,000
requests per second. Now, earlier this
was looking good on the surface level,
but now this is messy because one
partition here is clearly becoming the
hotspot. Now, what is hotspot? A hotspot
is that partition which is getting more
requests compared to other ones. So, it
is our duty to maintain this hotspot as
well. We don't want any node to become
hotspot because eventually a hotspot can
leads to the node failure. And if that
node fails, we have to basically
distribute the data into multiple nodes
then and then do the configuration again
or maybe change this node or maybe
transfer this data to other node. All
the things we have to manage, but that
thing is surely not recommended. So, we
avoid any node from becoming a hotspot.
I hope this is making sense to you. So,
one way of handling the hotspot is let's
say for every request, we also attach
timestamp and if most of these requests
are going to node one and very less are
going to node two, that means the data
distribution which we did is not good.
So, we have to rearrange our data with
some other methods. So, let's see what
the other points are. The second
approach here can be partitioning the
data with hash value of key. What we
will do here is, let's say we have user
one, user two, maybe user three as the
ID or unique identifier of the data. And
now we have to put that data into
different partitions. We will not here
choose ID, but we will use any hash
function to basically transfer the ID to
a unique number. Maybe this is one, this
is two. And user three belongs to maybe
one again because of the hash function
which we are using. So, based on this,
one and one will go to partition one and
two will go here. Or maybe we are
catering some range here, so maybe one
to 10 can go into one direction and 10
to 15 can go into other direction. So,
this is also one way of doing the
partition. The challenge here is still
same. If the request bombarded at P1, we
don't have any other way, but we have to
rearrange like we discussed in the
previous example. So, based on our
discussion so far, the hotspot is
becoming a real issue. Before solving it
for partitions, let's first see how do
we solve this issue in a local DB. Let's
say we have a table for products. And in
products, we have various attributes.
Let's say we have some name and color or
maybe price. We can have more filter
values, right? And like this, we can
have as many attributes as we want. So,
name, color, price, material. All these
attributes basically are used in order
to filter these products. Name can be
used in query parameters. Other than
that, color, price, and range can be
used in filter easily. So, what we will
do in normal scenario? We will create
indexes based on material, based on
color, maybe based on price as well. I'm
not sure about it because price normally
goes into a range, but we can easily
make a secondary index out of this and
by that, whenever any user basically
tries to search that particular product
with material, maybe material is wood.
So, what will happen? We will not go to
our table or this huge table directly.
Where we will redirect this query to, it
is going to redirect it to our second
query, which is maintained for material.
And if that data or that value is here,
we will then redirect those records
particularly to our display. So, this is
how we manage the queries to find out if
we have the data or not, and if we have
the data, where is that data
particularly. This is how we solve it in
local DB or a single instance. Now, we
are going to use the same way into
partitioning as well. So, what we are
going to do? We are going to do the
partitioning by the secondary index.
What do we mean by this is, we are going
to maintain secondary indexes in each
partition. So, that means all the
secondary indexes will be present in
each partition respectively. This way is
also used by Cassandra and also by
Elastic Search. What we are going to do
here is, let's say this is our partition
one, which have some data. Maybe this
partition have car data from ID, let's
say 200 to 400. And we have partition
two, where also we have some car data
from ID, let's say 500 to 700. Here, we
are maintaining some secondary indexes.
Maybe we are maintaining color as a
secondary index. And for color, we know
that the blue color is for car maybe
with ID 209 and 305. Similarly, for red,
we can say the ID is 350
or 359, anything, right?
For P2 also, we are maintaining it like
this only. Again, for color, we know
that the blue color cars are maybe ID
509
and 609 and red cars are 610 690. So,
these are the indexing which is done in
both of these partitions. So, whenever a
query comes for a blue car, we don't
have to scan to all the records, but we
can directly see the blue car here
belongs to 209 and 305. And here, we
have blue car for 509 and 609 only.
Let's say a new request come for silver
car. So, we don't have to basically
indulge into all the records, but by
seeing secondary indexes on color only,
we will get that this partition doesn't
have any car which is of silver color.
So, we don't scan this partition
entirely and this request can now go to
some other partition. So, this is how we
are maintaining the request so that our
data doesn't get overloaded with a lot
of request, but based on the request, if
they are present in our secondary
indexes, then only we will entertain
them and show them the records or fetch
some records, otherwise, we will
directly skip them. Now, this kind of
setup also have its challenges, right?
Because partitioning is done, but
secondary indexes are also present in
each partition. That means even if the
partition doesn't have any value, we
still have to send a request to that
particular partition. This is again a
drawback of the system which can make
the system heavy, which can send the
request to many partitions where the
data is not there and we are still
getting the request. So, this is also
wrong. So, that's why we have a fourth
and final way of solving this, which is
by having common global index. What we
will do here is instead of having
secondary indexes in each and every
partition, we will choose a partition or
any data center where we will maintain
the secondary indexes. So, if we are
saying that we want the car with color
blue, we should know that blue car
colors, according to the previous
examples, are only 209305
and here we have 509 and 609. And
basically, this belongs to our P1 and
this belongs to our P2.
So, we should know this first-handedly.
So, that whenever anyone is requesting
to get any information about blue color
car, we will directly redirect it to P1
and P2. And suppose we have some other
partitions, P3, P4, and others, we don't
send the request there. So, that these
partitions can take care of other
requests. So, this is our fourth way of
maintaining the global index. So, with
this, definitely, we are going to
improve our reading, but the writing
becomes a challenge. Why? Because even
if we are working with partition 79,
where we are adding some values, and
again have to update that, "Okay, we
have some new car, maybe 1011, which is
of blue color." So, like this, it is
handled. So, these are the ways of
handling partitioning into our system.
After understanding about partitioning,
replication, and load balancing, we now
know that we need to segregate our data
into multiple nodes in order to scale
them. We can't scale them into a single
database after an extent. So, after
understanding this, let's see what CAP
theorem basically says.
CAP theorem is one of those theorems
which we have to know whenever you think
about trade-offs between capacity and
availability. So, first see what CAP
theorem really stands for. In CAP
theorem, there are three terms
basically. C stands for consistency,
whereas A stands for availability, and P
stands for partition tolerance.
So, CAP theorem basically states that
you can only provide two of these three
variables, which means if we talk about
consistency, what does it mean?
Consistency basically means providing
latest information to every user.
So, consistency stands for latest
information. Now, if we are providing
latest information, let's see what it
really means. Let's say this is our
partition one,
this is our partition two. Some data is
updated on partition one,
and someone is reading that data
immediately after the update. So, this
update from partition one and partition
two will also take some time. And at
that time, we basically show something
like system is loading or data is
loading kind of thing to user until the
change is completed on P2. Then only we
can show the latest data. So, this means
that we will trade off our availability
of that particular information for
consistency. The second thing is
availability. Availability basically
states that we will always respond to
every request. Now, what does this mean?
In the same scenario, if it is taking
time to upload a data from B1 to B2, and
while updating someone request in
between, so they will not see loading
icon. Instead, they will see the stale
data. So, this is what availability
means. Now, the third term, which is
partitioning. Partitioning, we all know
now we need to divide our data into
multiple nodes, right? Now, with
partition, we can also see tolerance
here. What does it mean? Let's say there
are some nodes attached or linked to
each other. Now, this is partition
tolerant when the network of this node
is completely broken. So, this can't be
updated from any other method. We can
either wait to basically fix this
partition connection and update the
value or we can keep it working to
provide the information. But, then the
information we are going to provide is
going to be stale data. Why? Because the
connections between this node and the
other nodes are broken. Now, let's talk
about the combinations one by one. So,
first combination is CA,
which means we are saying that our data
will be consistent and it will be
available also. In this case, we can't
provide the partitioning part. Because
if we are saying that our data is
consistent and available, that means we
are maintaining a single database. We
can't basically have two data centers or
two nodes and think about consistency
and availability at the same time.
Suppose we have updated any data here,
it is going to take at least some
fraction of time to update the data to
other node. So, in that meantime, if
someone request about that particular
data, we can't decide basically whether
to show that data or node. Because if we
show that data, that means we are
compromising our consistency there. And
if we don't show that data and wait for
the update, that means we are
compromising with the availability. So,
this combination is only possible when
we are working with a single database or
a single node. We can't do partitioning
here. With this, let's move to our
second combination,
which is CP. CP means we are choosing
consistency over availability. So, here
we are saying consistency and
partitioning will be there, but we'll be
trade-off availability. Now, we have
understood this term, let me take the
example again. These are our two nodes
and the partition happens. Basically,
the connection between these nodes
break. Now, this doesn't have the
updated value. Now, when we are choosing
consistency, we have to let go of the
availability. So, we are saying no
request will be processed by this node.
Until when? Until it gets updated with
the latest data. So, this is what
happens when we are working in a
partitioned environment and choose
consistency over availability. That
means the requests which are calling
this node will be redirected to some
other nodes which have the latest or
consistent data. With this, let's see
the third combination as well, which is
AP. In AP, we are providing availability
to every request, right? So, we are
providing availability with
partitioning. So, what is going to
happen here? When there are two nodes
and the partition tolerance happen, that
means this node doesn't have updated no
updates. At that time also, because we
have chosen availability over
consistency, we will keep addressing the
request by showing them the stale data.
And that means we are compromising with
consistency. So, why are we learning
this CAP theorem? The CAP theorem
basically states that you have to do
some trade-offs in order to keep your
application working. Suppose we are
working on Instagram. In Instagram, the
availability matters over consistency.
Suppose you have updated a video or a
photo, it doesn't matter for your
followers to see that photo immediately.
They can wait for 1 or 2 seconds
basically. So, in Instagram, we will be
following AP. But in any application,
let's say banking application, where
each transaction matters to us, where
each change matters to us. So, if I have
sent 100 rupees to any other account,
the person will have to wait in order to
process that transaction, and after that
only they will be able to see. So, here
CP matters. And for CA, CA will be there
if we have a single data. That means for
every small application, CA can work.
But when the system scales, we don't
have an option to pick CA. That's when
we have to choose between consistency
and availability. So, this is what CAP
theorem is. I hope you all understand
it. Now, let's understand one of the
most important component of our system
design, which is message queue. Now,
before going into depth of message
queue, let's first understand the type
of request we deal with. We normally
deal with two type of request. Or we can
also say requests or maybe processes.
Some requests are sync. That means
whenever the request is received, we
have to immediately provide them some
output or response for the system to
keep working. On the other hand, we have
async calls, requests, or processes in
which we get the request, but there is
no hurry for our responses. Also, it is
also possible that we don't give any
response at all. So, so that means our
system only
takes the request and basically fulfill
the requirement in the backend
processes. So, in case of sync type of
calls, requests, or processes, we can't
do anything. Our system needs to be
concentrated on these requests and have
to provide the responses as soon as
possible, which we have discussed
throughout these courses. Now comes the
second part, which are async requests.
So, let's understand async process or
request with some example. Let's say we
are an e-commerce application. We have
some store, maybe some product is there,
and finally someone purchased this
particular product. So, at the time of
purchase, what are the operations we
need to perform? First is, we need to
send some email to the user that order
is confirmed and here are your details.
We have to also update the inventory so
that if, let's say, only one product is
left, that product should immediately be
out of stock so that there will be no
confusion for any other record. Other
than this, we also have to inform our
delivery partner, right? So, that they
will start packaging and moving the
order further. Now, out of these three
processes or request, which do you think
is the most immediate action? So, let's
see. Updating inventory is one of the
crucial task which have to be performed
immediately. We can't wait for it,
right? Otherwise, it can create
blunders. So, this is definitely a
synchronous task. But, other than that,
we can use some third-party email
service to process the email, right? We
don't have to send the emails
immediately. Even if the email goes,
let's say, 1 minute late, that is also
fine, and our system will be keep
working.
Similarly, for delivery, we can say that
delivery also is an async operation
because we are not in any hurry. Also,
our system doesn't need to take care of
delivery, as well. So, we will simply
pass this information to any delivery
service, and our current system can
basically focus on some other task. So,
this is how a distributed environment
works. Basically, we have multiple
services who communicate with each other
in order to fulfill the requirement. So,
if the services are different, and we
have to use, let's say, email, with
email, we can also use
SMS service, or maybe WhatsApp service.
We can use them, and these all are async
kind of calls. We don't have to stop our
system in order to process this request.
So, I hope up to now we have understood
about async and sync kind of request,
and in async, why we can use some other
services, and for sync, we have to wait
for the response in order to show some
immediate data, like out of service
product. Now, let's talk about some of
the examples for sync. Every financial
application can be an example here.
Wherever we are concerned about
security, we can't rely on async kind of
operation. We have to basically provide
the communication immediately. The third
area can be dependent. Wherever there is
a dependency on one or the other task to
be performed after a particular task in
a synchronous manner, we have to
complete this task in a synchronous
manner.
So that the dependent processes can also
work. For example, we can't process any
emails for order details before
processing the order. Once the order is
processed and confirmed, then only we
can put down the emails or other
notifications. So after this, let's talk
about async also. Async request
basically works wherever we need to
simply fire our request and our system
can then forget about that. So this is
the golden rule to understand what
system is async or what request is async
versus sync. Whenever we get the feeling
or we get the components where we can
simply fire a request and then our
system can forget about that, we can
easily move to async calls, which will
not only speed our systems but also free
our system in order to work on different
tasks. So some examples on free and
forget can be broadcasting. Broadcasting
can be of anything like email
broadcasting, even the matches, the live
matches which we see online on any
application, there also we can feel some
latency. The latency can be from 0
seconds to 7 or 8 or 10 seconds also
based on the network connections you
have. So broadcasting we have discussed,
email we can write here. Also we have
seen
SMS
or WhatsApp. Basically any communication
can be held asynchronously. Also the OTP
applications. In all the OTP
application, there is a timer and that
timer is mostly more than 30 seconds.
Why? Because in 30 seconds our system
can handle this request in an async
manner. So, now we have understood sync
and async, let's talk about message
queues. In order to understand message
queue, let's take the same example. So,
this is our e-commerce application and
we are using the service for emails.
Now, on our e-commerce application, we
are getting some order and based on that
order, we have to send emails.
But, in between, we will implant message
queue. In diagrams, message queue is
denoted like this because it is
basically a queue
and each of these order request or email
request can be hold in the message queue
and then through our message queues, it
can go directly to our email services.
So, what our application needs to do, it
will simply dump all the email request
to our message queue and from there, the
message queue will take care of those
requests. It is like a buffer or we can
say broker in between two apps or
services. Now, whichever party or
application is putting the request into
message queues are known as producers
and whichever service is taking the
request from message queues are called
consumers. With this, producers can also
be called publishers and consumers can
also be called subscribers because
publishers are publishing the message to
message queue and then subscribers are
the message who are subscribed to take
those request from our message queue.
So, this is how a message queue
basically works. You may think now that
why are we using message queue? Can't we
directly call the consumer or the email
service from our application? Yes, we
can call, but that will keep our system
busy. We don't want to keep our system
busy and we also want that whatever
request we are sending should be taken
care by. So, these two things can only
be done by a message queue. Now, if we
talk about qualities of message queue,
before writing the qualities, I just
want to say that if you still don't get
what message queues are, just bear with
me for some minutes and you will be
absolutely get why do we use message
queues. So, the first quality here is
that our message queues can basically
hold the request. With holding the
request, our message queues will have to
communicate those requests to our
servers. So, they can communicate to
servers or we can say services here.
With this, why do we use message queue?
The reason is it can also be used to
handle the failed calls. And with this,
one of the major reason of using message
queue is handles the load which we are
giving to the third party or the service
application here, email service. At this
point, let's talk about direct
communication again. If we again send
the request directly from our e-commerce
application to email services, that
means every time a new order is placed,
this call is going to be there. If our
email server is down or anything, that
call is going to handle the failure case
also. That will be responsibility of our
e-commerce application. But now, since
we are using message queue, these both
queries and these both troubles will be
handled by our message queue itself. So,
we don't have to care about the failed
request also. So now, what happens is
there are various ways of sending
request from message queue to the
server. Normally, our message queues
follows FIFO. We all know about FIFO.
FIFO basically means first-in,
first-out. That means whatever request
comes first will be delivered first to
our consumer. And this is how the series
will follow. So, in this case, the first
request will be taken care and then
after that second, after then third, and
so forth.
So, this is what the first-in, first-out
principle is and it is used by our
message queue in order to process the
request. So, in FIFO, we have two
approaches. First is
strict order approach, which basically
means, let's say this is our message
queue again,
and while processing the orders or
requests, let's say first process is
processed by our consumer, done.
After that, we'll come to the second
one. So, the second one is also
processed.
Then, while processing the third
request, it breaks down. So, maybe
something is wrong with the request or
maybe our consumer is down for some
time. Because of any reason,
our request was not processed. So, if we
are following strict order, even if
anything fails at this level, our queue
will not proceed. Our consumer, even if
it starts working again, can't process
the fourth request. So, this is not
recommended at all because of obvious
reasons, because we want our process to
keep continue even if one or other
request fails.
So, the second part solve this issue,
which is unordered queue. So, in
unordered queue, what we'll do, we'll
again create like this only structure of
our message queue. So, every time our
consumer or subscriber
takes back our request, so one, two, and
even if there is some issue with the
third request, our system will jump to
the other request in order to fulfill
that. So, our consumer will get the
request to perform the operations. Our
system will not break. What will happen
to the third request? Let's talk about
that in a bit. So, after unordered
queue, it is also possible that the
things which we are getting
in request in the message queues, maybe
our first request, second request, third
request, and fourth request,
between all of them, our fourth request
is like very important to us, is of high
priority, and maybe second request is
also of high priority, but not first and
third. So, in this case we can't follow
FIFO principle, right? So, our consumer
needs to get the second and the fourth
request first. This is where we used
priority queue.
What we will do, we will attest a
priority
like number or some ID to every call.
And whose priority is higher, those
calls will be picked first by the
consumers. So, in this structure if we
talk about if the priority of every call
is set, let's say the priority of first
call is 10, the priority of second call
is maybe three, the priority of third
call is eight, and priority of fourth
call is one. So, that means the first
call which our C is going to cater is
fourth one.
After fourth, it will cater the second
call. After second, it will cater the
third call, and after third, it can
cater the first call. Also, these
numbers are in ascending order. I have
created uh my system in that way that
one will be the most important priority
request, but you can reverse the order
as well. So, this is how our priority
queue is going to take request. After
understanding priority queue, there are
two more concepts here.
So, the one concept is pull request. So,
in pull request or pull-based request,
what happens is whenever we have some
data in our queue, let's again put 1 2 3
or some random values. Now, these
requests are in queue, which means that
the queue message queue will take care
of them.
But, the consumer here will decide when
to pick the request. Maybe our consumer
is working with some other task, and the
moment it gets free, it can pull the
request. So, message queue will not send
the request to consumers. Our consumer
will pull the request accordingly.
Again, the reverse of this is push-based
request. In push-based request, what
happens is the opposite of pull-based
request, which means if we have some
request in our queue, our message queue
is going to start the communication with
consumer and going to push our request
to the consumers. So, here the
communication starts from message queue,
and in the previous case of pull-based,
it will start with consumer. Also, I can
change the
uh direction of our request.
So, because it is pulling, so request
will come from here. So, I hope up to
now the things are clear.
Now, let's talk about pub/sub models.
So, in pub/sub kind of architecture,
what normally happens is we have
publishers here who are like sending the
message to our message queue.
We have message queue in between,
and here we can have multiple
subscribers as well. So, what we are
going to do, these publishers are going
to send some or the other message to our
message queue, which will be taken care
by our message queue by providing them
to the subscribers. Maybe this is using
push, and this is using pull. So, this
is how the system works in pub/sub
model. Pub/sub is nothing but the
understanding of our message queues
only. So, in this model, we include
subscribers
and publishers as well. Now, as
discussed in the previous example, our
message queue needs to perform some
operations in pub/sub model as well.
First thing is it will hold the request.
It will send these requests one by one
to the subscribers. And also, in case of
any failed response, message queue needs
to take care of that. With this, our
message queue is also responsible in a
way to take care of subscribers as well.
By taking care, I mean our message queue
needs to check subscriber is working or
not. If it is not working, our message
queue will not send the request to that
particular subscriber, and it will
redirect the request to maybe some other
subscriber. This is how the things work.
So, our message queue basically
maintains or the whole state of the
request as well.
Send the request to subscribers. Take
care of the failed request by using DLQ.
We will see that in a minute. And also
take care of the subscribers health.
Also keep checking whether the
subscriber is it still alive to work or
not. We can also say that it's still
alive or not. We can also say that our
message queue takes care of request and
takes the response from subscribers as
well. So, that means our message queue
know which subscriber is working fine or
fast and which is not working that
delicately. So, every time we get a
priority queue or a priority task, it
will be sent to the subscriber who is
working efficiently. So, this is what
Pub/Sub basically is. Let's talk about
some of the factors which can affect
Pub/Sub. The first thing which you can
talk about is message order. Let's talk
about message order. So, we are saying
that all the calls which are going to
message queue are async calls. Then why
do we need to maintain order? Okay.
First thing is that even if we want to
maintain some order, we know that we can
use priority queue.
And this is the only way of maintaining
any kind of order in message queue.
There is no other way. Maybe it is
handled by our application or maybe we
can add some additional information of
order in the request itself. This is how
we can handle message orders. Other than
that, it is for async calls where the
order doesn't matter. The second thing
we can talk about is how our messages
are going to be consumed. So, we know
that publishers publish the message and
they will store in message queue and
consumers are going to consume this. But
how they are going to consume this? We
are not maintaining any order. That
means these consumptions are random.
Maybe out of 100 request, the consumer
can pick up the 100 requests first. Even
if we are using priority queue, we can
make the priority of 100 requests first.
So, there is no particular order in
which the requests are going to be
fulfilled.
Consumers can pick any of the request
anytime. Also, message queue can send
any of the request anytime based on the
priority either or it is completely
random. Let's talk about the third
factor, which is poison message. So, all
the poison messages means all the
messages that subscribers are not able
to process. Maybe because they are bad
requests or maybe invalid. It is also
possible that they are failing like
after multiple returns as well. Also, if
we think about it, let's say a request
failed at the consumer side. And then,
if we send those requests again and
again, those are going to use or consume
the consumers energy and will do
nothing. Those requests are basically
our poison request who are taking time
and resource from our consumer as well
as message queue but are not able to
fulfill. Now, at this point, let's talk
about DLQ. So, this is our message
queue. This is our publisher or
producer, we can say. And here, we have
our consumer or subscriber. Now, let's
say we have a request which has not been
processed by our subscriber due to any
of the reasons. So, in this case, our
message queue can't stop. It will send
the next request. But, this first
request will go to a different queue for
retry or to maintain that this request
was failed. This queue basically, which
is maintained by our message queue only,
is called DLQ. DLQ stands for dead queue
or dead letter queue. So, our message
queue maintains this DLQ in order to
keep track of the failed request as
well.
So, that even if the publisher have put
the async operations, eventually
they will have to know that these cases
are failed. So, we will see the failed
logs or failed requests through any
logs, from which we will see, "Okay,
this request was failed."
Or other than that, we can also send
some or the other information to our
publisher in a async manner or in a
report kind of manner, where we will
give the stats of these many requests
are passed, these many requests are
failed. And here are the reasons of the
failed request. So, this DLQ is the
mechanisms through which our message
queue will take care of the failed
requests as well. I hope you get it now.
Also, poison. Poison means any request
which can't be processed, which is using
or consuming the resources, but can't be
processed.
So, with this, let's move to our four
factor. Fourth factor basically is
duplicacy. So, if, let's say, our
message queue have processed this
request when it is already processed by
subscriber one, then it should not
travel to subscriber two by any other
way.
Because the request is already
processed, it should not be processed
again. What if this request contains
some important information which can't
be done twice? So, in order to maintain
duplicacy, our message queue only takes
care of this thing.
So, with taking care of each request and
dead request, it is also duty of message
queue that whenever a process is done,
it should be deleted from our message
queue, so that we don't perform any
operation on that particular request. It
should be deleted. And if configured,
our message queue keeps end track of
this, that there was some request which
was obtained from P1 producer
and was handled by our S1 subscriber.
So, this is how our message queue will
take care of the duplicacy of the
request as well. After discussing all
these things, let's talk about some of
the use cases. Like where we can use
message Q easily and where we should
avoid using message Q. Let's say if we
are working on any async kind of
environment, any async operations, any
async request, we can easily go for
message Q. There is no doubt about that.
Similarly, if we talk about any
decoupling activity, which can be like
taking care of user analytics we want to
see and capture, maybe we want to
capture where our user lands, if our
order is failing, why they are failing,
and all the log systems. We can easily
do this with our message Q as well.
There is no doubt about this.
The third area can be our load balancing
acts. So, if we think about it, our
message Q does everything what a load
balancer does, right? So, our message Qs
can be used as load balancers as well.
Where it will take care of all the
request, it will keep them in a Q, and
it will provide those requests to
servers respectively.
Also, we can use the message Q with this
with the deferred system. Where we have
some operations, but we can basically do
them later, like generating reports and
everything. After every day, we can
generate some reports. Or maybe there
can be any schedule processes for doing
anything. Let's say we are adding
products into our catalogs like whole
day, and in the evening we want them to
be live. So, we will schedule a process
in order to work with them. So, the
message Qs can be used with load
balancer as well as they can be used by
our deferred system. Now, message Qs are
a costly service. So, if we don't have a
lot of request, we should not use
message Qs, right? Because it is a
costly service, and why waste our cost
when we can use them in a synchronous
manner? Or maybe if the request count is
low, we will directly call the
subscriber from producers. Like for
emailing, we will directly send the
request for our email service. With
this, if we are using any real-time
application, we can't use message queues
basically. Why? Because we need the
response to be in a synchronous manner.
We need the response to be immediate.
And if we are using message queue,
our request can take some time
to basically respond from any email
service or any other services which we
are using. So, in these cases, we should
avoid using message queues. And also, we
should avoid using message queues
whenever we need some acknowledgement.
Because if we need some acknowledgement,
that means our server or our system is
waiting for the some response to get.
But message queue normally doesn't do
it. In this example, where we were
sending some reports, this will be also
done by some or the other intervention
of our code only, so that we can see the
processes. But if we want response from
every request, it can't be done by
message queue. So, whenever we need
acknowledgement, we don't use message
queues here. And with this, we have
covered about message queues. Now, let's
talk about faults. Whenever we think
about faults or error, we basically,
while building any system or while
building any software as well, we have
to take care of each and every fault and
error. Now, while studying system
design, we have encountered very
components and we know what the
complexity our software also holds. So,
let's talk about faults and error. So,
our faults or errors can be called as in
any condition, if our system is not
responding in a way it should respond,
that means we have some issue or some
fault or some error with our system. We
can easily categorize them into three
categories. The first category is
hardware. So, hardware faults are
basically belongs to our server. Maybe
we are using databases, so DB can also
crash.
We are using message queues, we are
using each and every components, and
every component can fail our system if
they stops working. So, this hardware
issue or hardware fault is our first
type, and the nature of our hardware
failures is it can be random, right?
Like our system can fail entirely
anytime. There can be various reasons of
its failure. We can have like a disk is
full or something out of memory issue,
or let's say our server is down. We also
use network cables, so maybe they are
damaged. Maybe there is an issue with
the power supply. Maybe one or the other
node is not configured correctly, or
maybe it is experiencing some spike in
request, so it is down because of
overheating. Also, we are using
databases, so database can also be
compromised, right? These all things are
basically the fault of our hardware. We
do have some control over it, like we
can pass some alerts whenever we are
sensing any risk out of them, but they
are like inevitable. Whenever a hardware
fails, it mostly fails abruptly. That's
why we use multiple systems in databases
as well, and in terms of servers as
well, so that if any server crashes or
any databases goes down,
we can use our system by using the other
database or other server, maybe. So,
this is what the hardware issue is. Now,
let's talk about the second category of
our issues, which is software issue.
Now, our software issue can be caused
through anything. Maybe the code which
we are working on is written badly.
Maybe we have forgot to handle any
exception or anything. Maybe while
testing our application, we tested all
of the cases, but there are some edge
cases which comes to our picture when
the user actually uses the application.
So, there can be some edge cases. Also,
while coding in microservices or using
APIs, we also configure them into our
configurations. Maybe there can be some
issue with the configuration itself that
our system stops responding or maybe not
responding in a way which it should be
responding. Other than that, we can have
some deployment issues as well. There
can be some issues with the development
environment and the production
environment mismatch. So, something is
working on production but not working on
our development or vice versa. These
things come on a day-to-day basis in the
life of software developers. So, don't
worry about this but we have to take
care of this and this is our software
issue or software fault we can say. With
this, if I have to write any other
thing, uh one of the major pain points
can be merge requests. So, let's say two
developers working on similar feature or
same file parallelly and when the code
compiles of both of them, we need to
thoroughly test both of the
functionalities so that it doesn't break
down each other on the production or on
staging or on any environment. So, this
is one of the most pain point thing of
any developer. Other than that, our
software fault or software issue can be,
let's say, our requests are taking too
much time. So, the performance is also
something which software should take
care of. But the good and the bad thing
about software issues is that it is not
random. There has to be something in the
configuration or code file which we can
find out and solve that issue. Also,
this is not random, this is a good thing
so that we can find out the issue. But
with not random, it is also
deterministic which means by following
the same steps, we can get that proper
error again and again. And if that error
is not fixed sooner, that can basically
break our system or give a bad
experience to our users.
So, we need to fix software issues very
carefully and ASAP. Now, the third fault
is not really a fault but it comes into
the category of fault and is considered
the most important faults in our system
which is human fault. We know that every
human is unpredictable and we don't have
any control over ourselves. We can do
basically anything. So, this kind of
issue or error can cause unpredictably.
Why? Because humans are considered to be
most unreliable components of software
development among all.
Every component, whenever they are
failing or not working, give us an alert
beforehand. But with humans, it is
sometimes possible, sometimes not
possible based on the value of that
particular developer or anyone attached
to the software development cycle. But
with saying these all things about
developers or humans, we also need to
know that it is one of the most powerful
component or person in the software
development life cycle. If human stops
working, nothing is going to work. Even
if the code is written by AI agents or
AI anything, Claude, OpenAI, or any
other open source, it is still needs to
be rectified by human only. Because we
need some accountability over that code
because that code is going to build a
product which is going to be used by
humans only. So, we need human in
between all these processes. So, this is
one of the most powerful thing. That
means that makes us responsible for
handling the code even more. So, these
are the three categories in which we
divide our faults normally into. The
software issue, the hardware issue, and
the human fault or human error. Human
issues can be solved by having good
behavior or not doing the band-aid fixes
or quick fixes in the wrong manner, but
going deep into the system and fixing
the thing entirely for each and every
area. Also, by software issues, we
should not write bad code, handle
exceptions properly, see the edge cases,
maybe do testing thoroughly of each and
every component every time you make a
build. It can be solved, right? Also,
deployment issues can be solved if you
configure each and every environment
variable carefully. There can be other
configurations for databases or for
other APIs which can be configured on
development environment as well in order
to replicate that issue and eventually
solve it. Now, if we talk about
hardwares, hardwares are something which
we don't have any control on. So, if any
hardware is going down, it is mostly
unpredictable. So, this is also a danger
point. That's why we have to scale our
system in order to handle the system
perfectly or in a better manner. So,
this is all about faults and errors.
Now, let's understand about the last
topic of system design, which is most
important but many playlists skip this
one. This is our monitoring and
observability. We all know that in our
product life cycle, our product is once
developed will be deployed to any of
these servers and then will be
maintained. Now, creating a product is
entirely different from maintaining that
product. Here, we don't have to maybe
change a lot of code and add lot of
features, but we have to keep monitoring
whether our product is working fine or
not. So, we have to take care of these
following things. Are there any errors
in our system or not? Is every component
basically is working fine or not? How's
the health of each and every server,
every component, every database? If
there are coming edge cases or any
errors in our system, are we recording
them correctly? Do we have logs in place
so that each and every customer request
can be tracked and can be seen whether
they are working fine or not. And if
there is any error, can we like go to
the RCA of that particular error so that
our developer can debug and perform the
required operation. And also, if any
other component is going down or
basically down at this particular
moment, do we have other systems in
place who will take care of the system?
And also, do we have proper alert
systems so that we can rectify or get
these messages beforehand so that we can
take care of the situation in a better
way. So we need to take care of all of
these things plus more in the
maintenance phase or while maintaining
our application. For example, let's talk
about microservices. So one microservice
can do two operations, right? Either it
can handle a request and work on it or
the other thing it can do is it can even
redirect the request to any other
microservices. So in this case, we have
to monitor two things. The first thing
is how our APIs are performing and while
handling any request or whenever a
microservice or a server is working on
anything, we need to also check
how it is affecting our machine. Like
how much memory it is consuming, what
are the consequences of this particular
request if it gets overloaded or
something. So we have to take care of
the machine as well as the APIs at the
same time. Now let's talk about both of
them one by one. So if we talk about API
monitoring, the first thing we need to
check is our throughput. Now what is
throughput? Throughput basically means
how many requests can our server handle.
Let's say our server can handle 10k
requests per second. So that means if
our server is already hitting 9k or
maybe 8k responses, we have to configure
some alerts in order to know whether we
are going to hit our throughput or not
and maybe we'll migrate the data or the
request to some other servers at the
particular time because we need this
server to perform or to be alive. The
other thing which we can monitor while
using the APIs can be our error codes.
Like we all know about 500 issues and
400 issues and maybe we are using some
redirects also so 300 issues as well. We
need to know how many 500s are we
getting, how many 400 requests are we
getting, how many 300 requests are we
getting. So the first thing is when we
are getting too many error things, we
need to know the RCA of it. So, that
means our logging should be in places so
that our developer can work. One thing
is that. Also, we need to put some alert
whenever the count increases after a
particular point so that we can get to
know about the 500 issues or 400 issues
or 300 issues and fix them accordingly.
Third thing is our health check. So, in
order to check health of any components,
we have already seen that we can do it
by two ways, passive and active. So, we
have to constantly monitor the 200
responses as well and see if our
component is in a working condition or
not and is giving the positive replies
or not. The fourth thing is to check our
latency. Latency is a very good metrics
in order to check the performance of any
system. How can we check the latency?
Suppose we have some 10 requests and
suppose these values are the response
time of those APIs. Now, we need to know
the response time of our particular
server, of our particular API system.
So, how do we calculate them? If we use,
let's say, average, the average gives
the wrong value because, let's say, our
average value for this will come to 6.8
seconds, right? But, if we see most of
our requests are being handled in a much
lower rate. So, this average value
basically gives a wrong impression of
our services. So, apart from average, we
check P values. What is P? P basically
stands for percentile. So, what is a
percentile? Percentile basically says if
we are writing P90, we are saying that
our 90% of the request can be handled in
a particular seconds or maybe
milliseconds, whatever the time is. In
our current example, if we arrange them
in an ascending order, something like
this, we can see that we have 10
requests and P90 will be calculated here
and all of the requests like 90% of the
requests will take lesser time than this
time. So, this is our 12 seconds maybe.
So, let me also remove this milliseconds
for a bit. 12 seconds should not be idle
time for any API response. This is just
for the example, okay? Similarly, if we
talk about let's say P50 here, P50 will
be 4 seconds, right? So, that means 50%
of our request are currently covered
under 4 seconds. So, we can see that P50
is 4 second and somehow P90 is 12
second, that means something should be
off between these two. We have to check
all the APIs which are giving us the
response of near 12 seconds. And we have
to basically optimize them and improve
the performance of our entire system.
Again, these P90, P50, P70, P maybe
99.9,
when we have a large system and a lot of
calls, so all these matrices and values
percentiles help us in jot down how our
system is working in a majority portion.
And also, we can optimize the
performance of our system by checking
the differences of different P values.
So, it is very useful in case of
optimizing our code as well and also, we
need to know how our system is
eventually working. So, this is what
percentile is used for and we use it to
calculate the latency of our project.
Again, here also, we can provide some
alert system. Let's say our P90 here is
12 second and if our responses are
taking 50 second or something, we should
get an additional alert because this is
an unusual behavior for us now. So, this
is how we take care of latency of our
system as well. So, after APIs, let's
talk about machine monitoring. By
machine, I mean hardware, right? The
factors of measuring how our hardwares
are working, the first factor if we talk
about it can be our CPU usage, like how
much power is being consumed by that
particular operation or that particular
hardware while doing some particular
operation. And if that usage basically
exceeds any limit, let's say I'm taking
example of 75, maybe you can take 70, 90
accordingly. We should get an alert that
your CPU usage is already attained a
75%. So you need to take care of the
systems. Again, the other thing can be
memory usage. Let's say already we have
consumed 90% of the memory.
So we know now that our database will
not be able to hold more values. So we
need to immediately either scale our
system or we need to see whether we are
getting some error or not. Similarly, we
have a lot of input-output operations as
well. So we have to take care of disk IO
operations as well as network also. In
both of these cases, we can set the
limit and once the limit is exceed, we
can send alerts accordingly. So this is
all about monitoring our APIs and
machine. Now, let me give you a quick
recap of all the things which we have
discussed so far. We have discussed
about system design, what is system
design, what are the different
components of system design. Then we
have discussed about data intensive and
compute intensive applications, then
functionality and non-functionality
requirements, what is DNS, APIs. We have
also understood REST APIs in details.
After that we move on to DB, our SQL and
no SQL DB with detail. Also, cache and
their strategies of eviction as well as
how do we store the data in cache. We
have completed all the cache part very
extensively so that we don't get any
issues afterwards.
We have also covered load balancing and
load balancer in which we have talked
about how a load balancer acts as a
mediator between the coming request and
the request which goes to server. Also,
it works as an orchestration between
different servers and take care of each
and everyone's health. With that, we
have covered various forms of
replication, partitioning. Ultimately,
one of the most important theorems which
we're going to cover in each and every
interview, that is CAP theorem. Whether
you'll choose availability over
consistency or vice versa. After CAP
theorem, we have covered message queues,
fault tolerance, and then we had a brief
discussion about monitoring and
observability also.
So, with all these topics, now we are
ready to give any interview or to design
any system design component which we
want to. We have a solid foundation now.
Now, we can design any system. So,
congratulations, you have unlocked a new
trick, a new component, a new system in
your resume, in your abilities. Also, if
you feel like I have missed any point or
any topic, please mention that in the
comment. I may make a video of it in the
coming days.
With this, let's move to the last part
of our video, which is designing a
system. So, whenever you appear in an
interview of system design or maybe you
will design a system by yourself, it is
very important to think out loud. So,
you have to take your decisions very
specifically. No one is looking for the
perfect solution, but everyone here is
looking for what are the trade-offs you
make, what are the components you use.
Also, when I'm talking about components,
whenever you are using a component, it
is very important that you use it for
the right reasons. Just because you know
about all the components, it is not
recommended to add all the components
into your system. Because remember,
every component you add will add the
costing of your system also. So, we have
to use the component and design the
system very efficiently so that it can
be cost-efficient as well as work
efficiently to solve our purpose. So,
for now, let's design a video streaming
application.
So, see, we already have a lot of
applications. We have YouTube for
streaming. We also have, let's say,
Hotstar, Netflix, Prime. Also, if we
talk about streaming applications, we
can also say G Meet is also a streaming
application because we can do the live
streaming.
Uh we can call it a Zoom call or a G
Meet also. So, Zoom can also come into
this category where we stream our video
live to other members. So, a call is
basically also an example of a streaming
application. Now, with this, we can also
use LMS or any other software for
streaming our data. We can have more
applications. I'm just jotting this down
so that you get the idea of the
applications which use streaming. Now,
before starting, it is very important to
jot down the requirement. So, for our
video, we doesn't care about user login.
We don't care about their reviews and
maybe rating also. We don't care about
any other operation, but we only need to
know how a video basically process from
one system to finally our client system.
This is what we need to know in this
particular example. Now, whenever you
appear on an interview also, it is very
important to jot down the requirement
because let's say they give you an
example of designing any software like
Netflix, you need to know what are the
features the interviewer is interested
in. With that, while creating your
systems also, you need to know
specifically what you are designing
because you may be designing an entire
LMS, but for that moment, you need to
pick feature by feature and design each
component and at the end, maybe collect
all the findings and create a system.
This is how every system is built. Now,
here, we only are talking about this
process
of getting a video to our client system
from any server or from any other
source. Okay, so let's start from very
basic.
What is a video? A video is nothing but
a collection of different images we can
say and with this we also have some
audio here.
So different images are combined with
audio to create a video, okay? So in
order to calculate different images we
can see FPS or frame per second. We can
have 30 or 60.
These two things are available. Also, we
can use 120 or 240 if they're available.
I'm not that sure about it. But yeah,
these two frame rates are quite common
in our day-to-day life.
So what does it mean to have 30 and 60
FPS? Basically, in 1 second, if we are
using 30 FPS, our video will be divided
into 30 images.
And if we are using 60, for 1 second, it
will be divided into 60 images.
So that means the size of 60 FPS will be
more than that of a 30 FPS video. But if
we talk about the video smoothness, also
the 60 FPS video will be more smoother
than a 30 FPS video. Now with this,
let's stick to 30 FPS thing. Let's say a
size of a normal video, let I'm like I
am recording a video in 30 FPS right
now.
My recording, let's say went for 1 hour
and for the 1 hour recording video, the
size of my recording is basically
around 2GB.
So if, let's say you are watching this
video and if you want to download the
entire video in the start before playing
and then you play,
what will happen? It will add latency to
our system because downloading 2GB will
take time for sure. Also, you have to
see buffer and let's say you downloaded
all the 2GBs of content into your system
just to see a particular section or
maybe you see the first 10 seconds of
the video and didn't like it. So, you
wasted your internet and storage. So,
this is not a good option to download
2GB entirely first hand and then see a
video. It is completely waste of time.
So, we have to think about something
else. So, the thing is here we have to
use some network which is suitable for
our system. So, in order to process
information in video or images form, we
normally go for TCP. Because TCP
maintains a sequence of things. Why do
we need sequence? Let's see in a bit.
So, in TCP we have two protocols. One is
RTMP which is Real Time Messaging
Protocol and the other one is RTSP which
is Real Time Streaming Protocols. Both
of these protocols basically help us in
order to stream a particular video to
our device. Now, what this protocol does
is let's say we have a complete video
here. It is going to divide our video
into different chunks called as
segments. And our client machine or the
server from which we are watching is
going to pull these segments one by one.
Now, in message queues we have talked
about pull and push. This time I'm
saying pull. So, just connect the dots.
Keep connecting the dots while I'm
saying things, okay? So, this is going
to pull our segments one by one based on
the network. Now, we'll come to this
part in a bit. So, this will solve our
issues.
This will give us a low latency because
we don't have to download the entire
video. We can download some segments
also. With this we'll now be able to
stream in a much better way and it will
be more efficient than downloading the
entire video which was consuming our
resources and network bandwidth. Now,
this time we have to only download some
segments which is going to be more
efficient because this time we are
downloading in parts. So, suppose we are
watching one video, first 10 seconds is
over and now we don't want to watch the
entire video. So maybe some or the other
sections will be pre-downloaded for us
so that if you go ahead we don't see
buffer, but we don't have to download
the entire video which will save us a
lot of space and lot of network
bandwidth as well. Now with FPS we also
have one more factor which changed the
game entirely which is resolution. With
videos we have different resolutions,
right? We can use 4K, we can use HD, we
can use maybe 720p,
we can use 480 or 240 or even 144p. Even
64p was an option. I'm not sure whether
our video will be able to render in that
quality or not. I have like way before
when I was in school, maybe I saw that.
After that I didn't. So yeah, these are
all the resolutions on which we can see
our video. 4K will obviously have better
quality and 144p
is going to have bad quality. But why
are we talking about resolutions is even
if let's say we are streaming a 4K
video,
which I already said for 1 hour video we
need to store it in 2GB space. Suppose
we divide this into multiple segments
for each second, then 1 second will be
0.57
MB. Now this looks small but is a huge
size if we talk about network. What if
we have a poor network? What if we are
traveling? So our network is keep on
fluctuating on a different level. Also
if we sit by working on our office or on
system, our networks keep on fluctuating
as well. So that means we are not going
to have a common bandwidth throughout
our video viewing experience. So our
network will keep on increasing and
decreasing. So we have to take care of
that also. Let's say I record videos in
HD only and if I start recording in 4K,
that means the size of 2GB can become
big, right? The 2GB can go to 4GB. Maybe
I use multi-cam setups. At that time,
the 4GB can also go up to 8GB, maybe.
Also, in my videos, I'm not doing much
activity. The frames are pretty still.
Only my hand movements can be shown once
in a while. I'm sitting still. I'm just
facing the camera or the screen. I'm not
doing much activities. Also, the screen
you are seeing is black on which I'm
writing in white. So, there are no
colors, also. So, this is pretty easy
video to see. But, if I start recording
outside or maybe I start recording any
action sequence, so in that case, the
size can also get to 16GB for the same
4K video of 1 hour. So, this size can
also be increased to four times. So,
that will be around 4MB. So, the issue
here is for even 1-second video, we are
using 4MB. And if our network is not
that good, we are still going to see
buffer or face loading issues, which is
going to basically ruin the experience
of our viewer, and they will leave the
application. This is not what we want
entirely, right? So, we have to do
something about it. Also, if you think
about it, there are different screens on
which you work on. We maybe watching
something on TV. We maybe using our
laptop screen. Uh also, we can use our
mobile screen, maybe our watch as well.
Maybe we are seeing it on iPad. We don't
want 4K qualities in all of them, right?
Let's say we are watching on watch, we
don't want 4K.
Maybe on watch, 480 works fine. And
also, on iPad, also, I don't think 4K is
required. Maybe we can show them in SD,
and it will be enough. On TV, we
basically require 4K. Like, we don't
have to compromise here. But, on laptop,
also, we can switch between HD and 4K.
We can choose. We can pick based on the
requirement or based on the
configuration, based on the network
also. On mobile also, we can work pretty
well with SD. We don't need 4K here as
well. So, that means not only network,
but based on our screen size, we can
change the resolution of our video. So,
why are we changing?
Because it is going to reduce the size
of our segment. And the lesser the size,
the faster it will be to show. So, in
order to maintain streaming, we have one
mechanisms, which is adaptive bitrate
streaming. What it basically conveys is,
let's say you start watching a video on
300 Mbps. And your networks keep on
fluctuating. Maybe it went down till 10
Mbps. So, when the network fluctuates,
we can't download with the same
consistency. And if we are not able to
download with the same consistency,
there's high chance of seeing the buffer
icon. And we don't want that.
So, in order to achieve this, what can
we do? We have a source video
of 4K, right?
We have to divide this video into
different segments, that we know. Also,
we have to divide those segments into
different qualities. So, for example,
this 4K video is divided into 10
segments of 4K quality. But now, also we
have to divide these segments into more
configurations, the lower
configurations. Now, our basic
resolutions and segments are ready. Now,
let's see in real time how our function
really works. So, let's say here we have
our client who is watching something on
our desktop screen. In starting, the
network connection was 300 Mbps. So, we
start showing them the 4K video. So, it
sees segment one, maybe segment two also
he watches. And then, the network drops
to 10 Mbps. So, at this point, maybe
this is already loaded into their system
in the form of cache. So, they can still
see this section into 4K. But after
that, we need to load the data again.
And the network is now at 10 Mbps. So,
we can't load the 4K data. What we will
do, we will load the lower configuration
data. Maybe according to this we will
pick 480p.
So, we will start downloading this data.
And once the network restores to maybe
300 or 150 Mbps, we will start switching
our configurations accordingly. So, we
can go to 1080p as well. And if it then
drops to 50 Mbps, we can still give them
720p. And at the end, if network
basically restores to 300 Mbps,
we can show them the last segment in 4K
again. So, this is how an YouTube or any
other stream basically works.
They will keep switching our quality
based on our network bandwidth because
we are mostly seeing that entire video
on a single screen.
And based on our network, they will keep
switching the qualities. And we see the
entire video into one go
without seeing the much difference there
because normally the network doesn't
drop so drastically. We just keep these
segments in order to show them into
different devices. If you pay attention
in most of the streaming applications
where you are seeing the video, in the
side corner, you also see a segment
where you can switch your configurations
again. You can choose between auto,
maybe HD, or maybe they will directly
use the configuration that is 720p or
480p,
something like this.
So, you can choose between them. And if
you choose auto,
they are going to perform this
orchestration or this game while you
watch the entire video. So, what did we
see here? If the network throughput,
that means our network speed, is greater
than the bitrate of the downloaded
segment, that means we have downloaded
in a lower quality and now network is
greater than that. So we can now switch
to a better quality. Similarly, if the
network throughput is less than
the bitrate of
downloaded segment, so in this case what
we will do, we will switch down the
quality of our video. So after getting
all this knowledge, after discussing all
these things with your interviewer or
with your team,
then you start deciding what components
do you use in your system design. Now
the path is very clear, right? We need
to store the current data or the actual
data somewhere. Maybe this is our CDN
where the actual data or the actual
video is uploaded and it is uploaded
from where? From any server. Now from
here we need to create the segments, so
that means we need to give this data to
a service which can basically transform
our video. So we can name that we can
say it is a transformation service. Now
after this we have to send the segments
to our queue. We can use priority queue
here, right? So we can create a queue.
And why we are using priority queue? You
need to answer yourself. Now
from this message queue, our system is
going to use the services of downgrading
each and every quality. So we use worker
term here. Worker is basically used in
order to denote another service. So we
may be using worker one for downgrading
it to HD. Also we can use worker two for
maybe downgrading it to 720p and so
forth. So after working with these
resolutions, again we need a message
queue to store the results into segments
and again we need a priority queue here.
Okay, with this we will send this
request to a distributed CDN kind of
services from where it can go into
different part of our servers. So, if
someone is watching from India, they can
access the data from this server and
they can watch it from US server and the
other servers are for other regions.
Now, by doing this, we have completed
the entire system design of our video
streaming application. And from this
server,
eventually, we are going to access it on
our client machine on which our user is
going to watch their video. So, now
after creating this diagram, let's also
do some maths.
Let's say our source video is of 50 GB
and it is of 20 minutes. So, it is a
high-quality video, maybe 4K, and it is
having 60 FPS. So, that's why the size
is too big. So, this is we are taking as
an average size of the video which we
are going to stream. Maybe we are
streaming an entire match. So, this is
the size which we are going for our
20-minute video. Now, let's decide how
many segments can we divide it to. So,
I'm doing an easy maths. So, 20 minutes
multiplied by
60, that will convert it into seconds.
So, it will be 1 2 0 0 seconds. And
also, I am making the segments also
equal, so that means 1 2 0 0
segments as well. Also, with this, let's
talk about different resolutions. So,
let's say 4K is of 50 GB, which will be
divided by our segment. So, here the
size of our segment is too large, right?
Because it is a 4K video. Maybe we can
divide it into more segments. So, but
for this example, let's stick to it.
Let's say our 1080 pixel video,
let it be for 20 GB and again, we are
going to divide it by 1200. It is going
to be again 16.6 MB.
With this, let me write all the
resolutions.
Now, this is what the calculation looks
like if we divide it for each segment
for each resolution. For 720, it will be
8.3 MB. For 480, it will be 4.17. And
for 250, it will be 2.08 MB. That means
if we combine them all, it is going to
be 72.65
MB, approximately. So, that means the
size of one segment of our video is
going to be 72 MB, which is too huge, I
feel. So, maybe we can divide it into
further segments. But for now, this is
going to be the size of our one segment.
And accordingly, we need to load the
data into our stream.
Also, while calculating the size, we
should also take care of our user. That
means we should know how many users are
going to see the stream. So, if the user
count is, let's say, 100, we can use the
same server or a single server only,
right? For 100 number. If we count this,
it will comes down to 87.5 GB.
So, we can store 87.5
GB
into a single server, and from which
these 100 users can view our streaming
easily. What if the user changes from
100 users to 100,000 users? Now, this
will change our picture. Now, this is
where we will know that our one server
is maybe not enough to cater so much
requests. So, we will divide our servers
into two, maybe. And based on the number
of users, we have to keep increasing the
count of servers. Maybe we'll use
message queues. Maybe we'll add some
caching algorithms. And all of this will
be managed through our diagram. Here, I
have not used any caching. But we can
use the caching on CDN level.
Or we can use the cache on our browser
level,
which is going to hold the segments of
the coming part. So, this is what the
design look like. This is what the
calculation is. And this is what is the
logic behind the system design of my
system, which will stream our video to a
10,000 or a 100,000 user. Now, this
diagram can be different in your case
also. It is very possible that you will
design a system better than me, and it
is also possible that you will see some
other YouTube video who have designed
the video better than me or maybe worse
than me. So, these designs are basically
your practice.
The more you practice, the more you see
other designs, the more you read
different papers, your designs are going
to improve. And more your design
improves, the quality of your system or
your workflow increases with time. So,
with this, I end the discussion of
system design.
And I really hope you all enjoyed this
series so far. This was a long video,
and we covered a lot of topic. I hope
you all enjoyed it. Now, you can like
this video or comment the most
interesting section you found out in
this video. Also, you can comment out
any topic which you want to see in
future on Telescop. With this, my name
is Akshat Agarwal, signing off. Thank
you.
Full transcript without timestamps
Welcome back aliens. My name is Vin Reddy, and in this video we'll talk about system design. I know you are waiting for a long time for a system design course on Telesco, and finally we are here. Now, in this course we are going to understand different aspect of system design. Now, why it is important? When you go for the interviews, most of the companies will ask you for system design knowledge, and the question will be based on that. Now, of course they will not be saying this is a system design round, but they will expect from you to understand different concepts here, and how will you solve a complex problem. And let me give you a statement which highlights this, and I have it here. Anyone can write a code that works. A system design is what makes it work for million people at once, and that's the power of system design. See, when you write a code, of course when you learn a language, you learn a framework, you can build application. That framework can I mean, the entire project will work. The moment you deploy it, the moment it is in production, and when you have users, not just 10 users, of course it will work for 10 users, and it should work for 10 users, but the moment you have 10 million users accessing that at the same time, will it work? That's the question. When you talk about all your favorite applications, it can be WhatsApp, YouTube, Instagram, or Amazon for that matter, there are not few users who are accessing that at one time. There are millions of users, but still if you can see, they work. So, how do we do it? And that's where system design plays a huge role. Now, to understand this, we have we will be going through these concepts. So, in this particular video, we are going to start with the basics of system design, what is system design, what are different components, data versus compute intensive, and functional and non-functional, and all this comes under foundation. Now, once that is done, we'll talk about how the communication happens between different systems. So, we'll focus on DNS, API, and of course REST, which you might be knowing if you have worked with Spring Boot or Fast or Django and any web framework. Then we'll move towards the data. Of course, when you have a lot of users, how will you store data? Not just their personal data, but their activities. Uh and in that we have different options like SQL databases, no SQL databases, when to use cache, and when to use SQL and no non-SQL. Then, let's say your users are growing day by day. How are you are going to manage your application? And that's where scaling and distribution comes into picture. In which we'll talk about load balancers, replication, partitioning, and the CAP theorem. That this will be an interesting the CAP theorem. And then, we'll talk about operations and reliability. And the most important part there becomes a fault-tolerant. What if something goes wrong? Does the application do have something to do that? In which we'll talk about message queues and monitoring as well. And of course, we'll cover different examples here to understand different concepts. And the entire section or this part will be taken by an amazing trainer, Akshay, who is very good in explaining stuff. And I hope you will enjoy the entire part. And do share your thoughts in the comment section. Don't keep it blank. You what you like, what you don't like. If you have any questions, do point it there. And we'll try to answer them. And if you enjoy this type of videos from us, let me know in the comments as well. That is our motivation. And I hope you're motivated. Let's get started. Akshay is all set. >> [music] >> Hello everyone. Welcome back to Teleschool. My name is Akshay Agarwal. And today, we are going to start the system design course. In this course, we are covering each and every topic which includes in system design. So, let's start with understanding why do we need system design at all? In systems, we have a lot of systems around us. If we talk about human body only, we have digestive system. And also, we have a system. Along with this we have a lot of systems, but these kind of systems are pre-built. It means we have not created them. We just discovered them with time and we got to know about various components which are required for us to breathe or to digest our food. So, in these systems as they are not built by us, we can't actually change anything. Maybe through surgery we can change some of the other component, but not much. But the kind of system we talk about in IT industry are the systems which are built by human or engineers like us only. So, in that there is a possibility that we can pick our systems based on our requirement and also based on our requirement we can pick the components which are required in our system and we can basically improve our system based on the request we are getting, based on the load our system is managing, based on the kind of traffic which we are getting in our system. So, in system design if we go through the words we have two words here, right? One is system and one is design. What is a system? If we go through the definition, system basically means there are a lot of components. There can be more than one components in that system. So, let me write components. And those components are working eventually to solve a particular use case or maybe multiple use cases, but the common purpose of the application remains same. So, that means if we write system is equal to components plus common goal, this sums up our definition of system. Now, when we talk about design, there are various components which we are going to learn and there are various common goals based on the requirement analysis of different applications which we are going to cover in this particular series. But in order to start, let's not dig too much into the technical details in this video. Let's start from a very basic. Let's say we have a requirement of creating our own application or our own bank. Let's say we have a bank named Alien Bank because we are in Telesco, why not? And in this bank, we are not dealing about each and every operation. Currently, we have a single operation, which is we have a cash counter, and we have a person sitting on a cash counter. Let's name it as cashier. Okay, so here we are ready with our cashier, who is on our cash counter, and the requirement or the flow is pretty simple. For the flow, let's understand the concept of our bank. So, we have multiple, let's say, customers are here, and each customer will come to our counter, either withdraw or deposit some amount, get the receipt from the cashier, and then move forward. So, let's write it down as customer flow cycle. So, in our customer flow cycle, there are four steps, basically. Customer first will visit the counter, will come to the counter, then the customer will either withdraw or deposit some amount, take the receipt from the cashier, and then the transaction is done. The purpose of our application is done. So, these are the core functionality of our system. It is very basic, very easy. You might have seen this already in some of the banks. So, we are building the same architecture right now. The architecture basically looks like this. Now, in order to understand system design, what it really is, and how we are going to improve the working of our Alien Bank, let's face some issues. We are going to face five issues, and based on the issues and solutions, we are going to understand how system design looks like. So, here comes our first issue, which is the process is really slow. By slow, what we meant is, let's say, our cashier takes 10 minutes per customer. So, that means we are serving only six customers in 1-hour span. So, this is a huge issue, because if the number of customers will increase to a limit, and also we have rush hour, in those cases, our system will break, and we will be not able to serve the customers rightly. So, in order to improve this, let's first focus on our cashier. So, let's understand our system from the cashier's point of view. So, basically, our cashier is taking time to understand the requirement. By requirement, I mean whether the customer needs to deposit the amount or customer needs to withdraw the amount. They have to make this interaction, which is time-consuming, right? Now, once the requirement is locked, whether the customer is going to deposit the amount or withdraw the amount, the cashier manually have to count the cash. And then our cashier will prepare a receipt, which will be again given to our customer. So, these are the time-consuming tasks for our cashier. How can we improve the cashier time? So, in order to improve the working of our cashier, we have three major issues. First is they are not able to understand the requirement. Next is they are counting the cash manually, which is taking time. And again, they have to prepare the receipt. So, these are the issues which our cashier is feeling, and we are trying to solve these issues. Maybe we can train our cashier in order to count the cash very rapidly. Okay. Also, our cashier is also responsible for maintaining the receipt. So, we will improve the typing speed of our cashier in order to make the receipt very fast. So, the second thing is train to type fast. So, with this, what we are doing, we are not adding any resources to our cashier. Simply, we are making our cashier super fast, right? We are improving the skills of our cashier, which is required for them to maintain this job. And let's say through this training, the cashier is really improved now. He is or he or she is now taking, let's say, 5 minutes in order to fulfill one customer's need. So, this is a huge improvement. By this, we are able to improve the process by 50%. So, let's say our second issue is that the customers which our cashier used to attend are increasing very fast, because this is our alien bank, and it is working very fastly, right? Growing very fastly. So, now the issue two is our customers count is increasing. This is our issue two. In this case, what we know so far? We know that our cashier we can't improve our cashier performance because it is now at its peak. So we have to basically handle some or the other components to our cashier in order to make the work very fluently. So maybe the desk on which our cashier is sitting, we will increase the size of desk. So next thing which we can do is we will provide the cash counting machine to our cashier so that the manual cash counting time will get reduced, right? So we'll provide cash counting machine, right? So with this also the time will get reduced and our cashier will be able to attend more customers. One more thing we can do that is instead of coming to counter and getting the requirement at the real time, we can give a form in advance to all customers so that they can fill it and our interaction time will get reduced, right? So our cashier will now don't have to communicate each and every request to our customers. Uh they can simply see the form and based on the form they will fill out the thing. And now our cashier have cash counting device also, so the process will be fast. Let's say through these processes, through enhancing our desk or cash counter, the timing got reduced from 5 minutes per customer to 3 minutes per customer. This is also a huge impactful thing. So now our cash counter is capable of attending more customers in lesser time. So that means even if the customer count is increasing, we will be able to process more customers and enroll more customers into our Alien bank. So this issue is also kind of solved. Now let's move to the third issue. The issue three is our customers are still waiting to get their application resolved, right? Currently, what do we have? We have our cashier who is upgraded to its maximum level. So, we can't upgrade the cashier more. Also, the desk on which it is sitting, the cash counter, is also upgraded to its maximum limit. So, we can't upgrade our cash counter more. So, these two things are pretty solid right now. We can't improve it now. Now, the thing is, so if we have 10 customers in place, that means our 10th customer will have to wait for 27 minutes in order to process the three-minute work. So, that is a huge drawback of our system right now. And why that drawback is coming? Because we have only single cash counter in our system. So, in order to make the process more feasible, now we have reached that point that we have to add more cash counters into our system. So, let's add them. So, now we have our cash counter one and cash counter two. Now, at this point, we have added one more counter, and things are pretty solid right now. So, our customers will eventually have two counters to go to, and both of those counters will be able to solve our issues. It feels good, right? Now, we have two counters to process. So, our customers will not have to wait for longer time. They can either go to counter one, or they can go to counter two. But, let's say if first customer is going to counter one, and the counter one is able to process the information, and they are maintaining their own data. And similarly, our second counter is also maintaining its own data. And they are not synced. So, this creates two issue, right? First issue is, if in our system, the counter two doesn't know anything about the customer, that will create an issue because they have a valid account in our bank, and they should be able to proceed their information through it. Now, the second issue is this only. That from the first account, they can also withdraw the amount, and they will not update the second counter. So, that means they can again withdraw the amount from cash counter two also. This will create an issue of data discrepancy. That means our data is not synced. So, the fourth issue here is we need to have a centralized database or central data from which the cash counter one and cash counter two will go and validate the data and go and retrieve the data. If the account is there for any customer and the amount is also there, so the customer one will also insert the cash into the same account. And if the counter two is getting withdrawal request, they will also get the amount out of the same account. So, in order to fix this, we need to have a centralized data. That means our counter will look like this. This is our counter, let's say two. This is our counter one. And they will eventually connect to a centralized database. And as it was before, our customers are standing in a queue waiting for their turn to come in order to get the request. Now, after solving all these case also, we have a new issue in hand. Which is, let's say the gate of our bank is here. This is our alien bank. So, since the gate is here, most of our customers are going to the cash counter one only, where cash counter two is sitting idle. Or maybe processing lesser request, far lesser request than the cash counter one. This will again end up adding the wait time to our customers. And again, we will be end up handling lesser customers than our potential. So, let's write that down. This is our issue five, which is underutilized counter. Now, in order to solve this issue, we need to have a middleman. Which will stand apart from our counters. Let's say this is our counter two. Again, this is our counter one. And here are our customers. And now our customers will not go to the counter directly. They will first go to this middleman. Then the middleman will check how much load each counter is handling. Suppose there are 10 customers at counter one and only five customers at counter two, then our middleman can decide that next customer should go to the counter two. And the count will increase to six, right? And the next customer will again go to counter two, and the next customer is again going to counter two only. When the limit reach, let's say we have 11 customers here and 11 customers here. And if then any new customer arrive, they will again ask man where to go. Let's say on some fine day our counter one is not working. That means our middleman will know about this and will eventually send all the customers to counter two until the counter one is getting fixed. So, let's end this example here at this particular point and see what have we learned. Through this story, through this single story and five issues, I have tried to capture multiple concepts of system design. So, the first concept which we discussed is designing a system, that is for sure. Ultimately, what design we do have here? We have one cashier and the other cashier. Each cashier is having their own counter. So, this is our counter two, maybe this is our counter one. We have a number of customers waiting for us. Also, we have a middleman now. With that, we also have a common database, okay? So, this database is nothing but centralized database. The customers which are coming to our bank is nothing but requests. And if they are standing in a queue, we can say they are creating a traffic, okay? So, these are the traffic which we are going to handle. Now, all the requests or all the traffic is coming through a load balancer, the middleman. So, this is nothing but our load balancer. So, from the load balancers, all the requests are coming to either of the cash counter. So, we can say that our cash counter is nothing but servers. And the person sitting there doing the work is nothing but our application code. Now, let's see the system again through the system design point of view. So, the first issue which we have was our process is slow. So, in order to solve that, we improved our code quality, right? So, first thing which we do in our systems also, we improve our code quality. So, this is where our LLD will come and this is where our DSA will come. Suppose a particular loop is taking certain time, we can reduce that loop or we can change that loop to some for each function or some other way in order to process that information fast. So, while solving the issue two, we increase the size of our table, we added some functionality, we added this cash counter. That means we upgraded our server. So, in order to upgrade our server, this term is called vertical scaling. In vertical scaling, we don't add multiple servers, we basically update our current server only. And again, the current server updation have a particular limit. After that limit, you can't upgrade your system. So, then comes the issue third, which is our customers need to wait for the single server to respond. So, in this case, we added more servers. So, in this scaling, we added more server that is called horizontal scaling. So, after having multiple servers, we need to maintain the data at the common point. So, that's why we added databases. And in order to add a common database, we basically can move to distributed database architecture or can move to a centralized approach of handling that database. So, this is nothing but centralized database. So, after having centralized database, again the issue comes where we don't know how to handle multiple requests. That means our requests are again going to one counter only or one server only. Now that we know they are going to one server only and the other server is underutilized. So, what we did, we added a middleman. Our middleman is no one but our load balancer. Our load balancer basically do two things. They will check whether our servers are healthy or not and based on that, they will distribute the request equally into multiple servers. So, these are all the concepts which we discovered through this particular example. So, if we think about the applications we are using in our day-to-day life, we are using WhatsApp, we are using maybe Snapchat, we are using Instagram, we are using YouTube, we are using LinkedIn, we are using Netflix, Amazon, maybe Flipkart. All of the applications, if we think about it, are showing us the data either in the form of images or in videos, in audios or in text. So, we can say through a large lens, the data consist of these four kind of information. And all of the applications which we are using in our day-to-day life consist of these data's only. So, we can say that in the core of every system, we have data and we are then finding ways to make it available to the users in the way they are expecting it. So, in the center, as we discussed, we have data. Data can be of various form. It can be image, video, audio or text. Now, if we think about data, it is not like we are seeing the data once only. We have to see the data and also while storing also, we need to store the large amount of data. Now, in order to store the data, we do have databases. So, databases are basically our first component of system design. What is functionality of databases? Pretty simple. We need to store our data and whenever we want to retrieve some data, we need to get the data from our databases only. They are represented by this cylindrical figure. Databases can be of multiple ways. It can be categorized into no sequel or sequel. Now, there are various kind of databases in both of these categories. In sequel also, we have various databases from which we can select which database we are going to use. And similarly, in no sequel also, we have various kinds of database from which we can pick which database we need for our application right now. But, the core remains seems that we are saving our data in some or the other database. We will discuss about sequel and no sequel databases in the coming videos. That's why I'm not going to deep into this at this moment. Let's think about the scenario where you and every user on the planet knows the queries of database, knows how the tables are structured if we are talking about sequel, or how the documents or nodes are connected if we are talking about no sequel. If we talk about both of these scenarios, if user, the end user, already know the database query languages and know how to deal with different kind of data, in that case, we might not need any application if you think about it. We will simply go to our database, or the database will be accessible throughout every application. Suppose we are seeing the LinkedIn, but on LinkedIn we will see an interface on which we will write our query, and the data will be fetched to us. That will be an hectic task. But, if users know about that, and if users start exploring that, that will be easier, right? In that case, we don't need any application layer in between us, and in that case, we don't need any client-side application also between us. We simply will see a database, query it, and get the results, right? In that case, what will happen? Each query have to be managed through the users only. And these queries, when I talk about large systems, let's say we are talking about LinkedIn, there can be multiple tables through which our data is curating and coming to us. Every user can't do it, right? That's why we have different layer in front of our database, which is our application code. So, in application code, what we do is we hide the complexity of dealing with databases, different tables, different documents, and we give the endpoints to our application or to the world so that they can access the kind of information they are looking for. For that, we create APIs or we can say we create endpoints. There can be multiple endpoints based on different features, based on different operations. So, through endpoints, we communicate to our application, which will again communicate to our databases to get the data we are trying to get. There can be various operations, like we can insert some data, we can update some data, we can retrieve some data, we can delete some data based on our request. So, the thing becomes little easier to us. Now, we don't have to deal with all the database tables, but now we have assigned endpoints through which we can do the work which we want to do. And endpoints are pretty simple. So, in order to get some data, we have a get endpoint. Let's say https, and here comes our Teleschool. So, this URL or this endpoint can be used to fetch all the students which are there in our Teleschool environment. But then, what we are doing? By introducing application code, we are moving our logic and data separately. That means we need some kind of connections between these two. In which we can connect through IP addresses, we can connect through some HTTP protocols, or we can connect through some TCP protocol. There are many ways of connecting the database from the application code and getting the data which we want. So, in order to show the APIs or in order to interact with the APIs, we have to know what is JSON and how we are going to send the data to our APIs and how we are going to fetch the data from our API. In this level also, if we know how to handle JSON, if we know how to handle various operations through which endpoint, it will make our life little easier than accessing the databases, right? So, in that case, we don't need a front end if we know how to hit the endpoints through which we'll get the data. But, for our normal users, for other users of any applications, this is also a tedious task. So, in order to make this easier, we have a different layer between our system that is our client application. Client applications are nothing but the applications through which we are interacting to the database, through which we are getting those databases. So, our client applications, be it a mobile application, be it any web application, be it any ATM machine for that matter, they are connected with the application code, and further, the data is being consumed by us. So, again, in order to connect the application layer and the client code, we again need some kind of communication between them. We either can go to the same HTTP or TCP or maybe IP. Now, we have our application ready in our hand and we can use it. So, if I draw it like we used to draw it, this is represented by our client, either a desktop or a mobile device. Now, they are sending queries to our application code, and our application code is further getting the data from database. Now, for our client to communicate with our application code, we need to put our application code on any server. And now, if we think about it, our application code is already exposing the APIs to our client. That means, it can also expose the APIs, or any other application can also use our application codes through our APIs and do the work which is needed. So, it can be connected to any other server also, which will contain their application code. And this will communicate with our data through our application code. For every query which we are making, we are going to our database, and from that we are getting the data which we are trying to get. So, if we think about it, most of the communications will start from the client side, and they will come to our application code through which we will get the data from the database. This is pretty much the easy application or the applications which we create on our college projects look like. Either a to-do application or a simple chatting application will look like this. Now, in the current scenario, what we are doing with this kind of architecture is every client is going to ask application code for some or the other information, and to fetch the data, our application code needs to get the data from the database only. We don't have any other option. In order to make the files accessible to our server faster, because the database's calls are heavy, which will take a lot of time, let's say, if a database query is finding the columns from 12 tables, it is going to take time, right? Now, in order to make the frequently used data accessible faster, we have a different layer, which is called cache. When we are going to put any data into our cache, and when we are supposed to remove the data. There are different strategies we are going to cover that also in the upcoming videos, but for now, let's see, this is our cache, and all the frequently used data will be stored here. So, that we don't have to call to our database, and they can be easily accessible through our cache only, which will make our process slightly faster. So, this is our fourth component of our system, which is cache. Now, let's move forward. Let's say our application is big, is having multiple servers. In that case, we may have some client or this client, either the mobile application or the web view, and we are getting the data from multiple servers. Let's say this is server one or this is server two. Now, when we have two servers or multiple servers, our client have to decide where to go. From where do we fetch the information? Now, in order to take this control, we have a load balancer in the middle, which will take care of each and every request and which will take care of each and every connections of the server. So, our load balancers are responsible for handling two tasks. First, they will check whether the server is healthy or not. And second one, they will divide the request for each servers equally. This is what our fifth component looks like. Now, let's come to our next component, which is messaging queue. So, in order to understand message queue, let's first understand that in order to process one operation, there can be multiple task into that operation, right? Let's say we are ordering something. So, when we are ordering, we are going to do multiple tasks, right? We are first creating an inventory update. Next is we are going to process the order also. We are going to talk to the vendor who is going to take the delivery. So, we are going to handle delivery. And then, we are also trying to send you the information, the notifications that your order is placed successfully. Don't worry about it. So, that means we are going to handle the mail service or the SMS service also. Now, in order to handle multiple services like this, we can't wait for every application to respond back. There are two kind of applications basically. First is, let's say this is an application and this is another application. Let's say this is SMS application and this is our order application or microservice for that matter. Now, whenever an order is placed, it is going to speak to the SMS service or SMS application to send the message to the user that your order is placed successfully. Now, there can be two ways of handling this. First way is, whenever the SMS is sent, they will notify the order service or the order application back that we have sent your message done. Or there can be different way of handling it that from our order service, we simply say that okay, this is our order information. Please send the message to this number and we are done. We will not wait for the response. We will move forward with our application and with different orders. So, the kind of requests in which we are waiting for any confirmation or any feedback from the other service are called synchronous calls. And the kind of service in which we will simply put down the service and we are not waiting for any confirmation, we will move forward to do our task. Those are called asynchronous services. Don't worry about this if you don't understand it now. We are going to dissect each and every component in details in the further coming videos. So, for asynchronous kind of services, what we can do, we can simply push our notification or push our request to another service and move forward. So, in those kinds of services, we have a message queue or message broker in middle. What it will do, we are having our order service here. It will put multiple request or can put a request time to time into this message queue. And then all the requests which our order is processing through message queue, they will not take care of it anymore. Our message queues will take care of it. They will connect with our SMS service or SMS applications and send the request one by one. And they will take care of these all operations. So, our message queue is like a broker who will take the request from one application, store inside it. They will take care of these applications. They will take care of the retries or if any request is failing, they will take care of it. Maybe they will communicate to our order application in the end or in the end of each day, we will send some notification, some batch processes to our order application in order to show that which requests are fulfilled and which are not fulfilled. So, in short, our messages queues are doing two work here. They are storing each and every request which are coming from various other services or various other applications for that matter. They are storing it and they are taking care of those requests. They are sending those requests finally to SMS application or service and they are taking charge that okay, my first service or my first request is being processed. Nice. Now, I will send the next request. Now, I will send the next request and further on. If it is failed, there are various mechanisms how messages queues work and how they bisect and dissect each and every request and make sure that they will provide the latest status of each request. And in those kinds of environment where we have multiple microservices, in those cases message queues plays a vital role in between them. And with that, let's move to our final component which is monitoring and logs. In monitoring and logs, what do we do? As we know now, we have different components in our architecture, we have a client system here. We may have a mobile application again which is connecting through an API to our load balancer which is again further connected to either server one or server two. Our servers are the area in which we have our application code and then they may be connected to single database or multiple databases and those databases can also communicate with each other in order to maintain the data. And also, let's say our application is also using some third-party application for which we are using message queues. Our message queues are denoted by this. Now, this is our architecture. We have so many components. So, it is very important for us to monitor those components. To monitor whether our load balancer is working finely or not. To manage whether our application code does have any error or not. And if there is an error, we need to know how to solve it. We need to know the complete stack trace of that particular error. We need to know how to reproduce those errors on our local system in order to fix them. And also, while working with the applications, we know that for every each and now, we have multiple features which are being attached to our applications. So, we also need to monitor while adding one more feature to our application, whether any other feature is impacted or not, or it is failing or not. So, in order to do that, we have a lot of monitoring tools and also logs to check our system. There is a complete testing department in our team also, who takes care of these things. This is one of the vital role in our application. So, these are most of the common components which are used in system design. Whenever we think about any application or designing any application, we suddenly jump to the tools which are used in that application. We start creating diagrams that this is our client, this is our database, this is how our data is going to flow, this is how we add cache maybe. So, these all things we start doing without noticing a single thing, that is, how is our application going to work? What is this application? What are the limitations of this application? In system design, there is a smart way of doing that. First question you need to ask yourself before diving into the solutions is, what is this application? What is the type of this application? Is it a data intensive application or a compute intensive application? With this common differentiation, you will be able to save a lot of cost to your system design, as well as you will be able to handle the task properly into your system. Let's say, we have two applications. In both of these application, there are the same number of users. With that, the network on which both of the applications are working are also pretty much same. Now, let's put a scenario that our system or the application which we are working on is facing latency. Now, what is latency? Latency means our system is taking time to respond. There are various ways of handling this issue, of fixing the latency issue. We can add multiple databases, we can add different caching layers, we can update the caching mechanism, or we can update or the CPU powers. Now, on which vector we are going to do this changes defines how well we are going to solve this issue. So, now there are two type of applications as I discussed. One is data intensive application and one is compute intensive application. Let's understand them one by one. The basic difference on which data intensive application is different from a compute intensive application is that in data intensive application our core focus is on data. Now, for this data we need to have multiple operations, right? We need to store the data, plus we need to gather the data, we need to move the data time to time. That means we need to keep updating the data because new data is entering. And also, while new data is entering we can also, right, we need to add a lot of data. We can take example of any application which can be Instagram because on Instagram we see a lot of content and we post a lot of content. So, that is a data intensive application where the primary focus is on gathering the data, is on showing the data, is on the data you are posting. But, the focus is not on how the data will be calculated. The calculation part is pretty solid. We just need to move the data from our databases to the client applications and we are sorted. So, in these kind of systems the data mainly resides in the database. So, first issue can be the database response is low. Another is, since we are using network calls here and there, that means our network calls are also bulky or we need to optimize them. The third can be our server itself that our server configuration is pretty low, that's why we are not able to get the data faster. So, all in all, in data-intensive applications, we are not blaming the client to upgrade their CPU, we are blaming our circle, our database calls, our network calls, our server configuration in order to get the data fast. Most of the applications in which you work on are data-intensive application. That's why we use terms like cache enhancement, shredding, and through all of those things we will be able to solve this issue. Now, let me also write some common examples of this. So, the common examples here are Instagram feed where we see a lot of data as we discussed earlier. In WhatsApp messages also, there is a high amount of data because we are not only taking care of one chat, we are taking care of entire chat. The count of chats or the count of messages WhatsApp deal with is around 2 to 10 million messages per day. So, this is also a heavy data-intensive application. Now, there are bank transactions, analytic dashboard, and log process system as well. In all these application, the primary goal is to serve the data from database to our client system faster. There is not much calculation required for them to show on the client machine. Now, based on the data-intensive application, what are the worries of a data-intensive application? The first worry is how fast can we read the data? The second point is how safely are we going to store the data? The third point, as we all know, a lot of users are using our application, so how many users can use the same data simultaneously? The next and one of the most important worry of these kind of application is what if any server dies? What if any server breaks? What if any network call breaks? What if any database machine breaks down? So, in those cases, how we are going to handle the data? So, these are the most common worries of the data intensive applications. And now, in order to solve them, we don't go to our client system. We talk about the components on which these processes lies. And those are our databases, caching, replication, maybe data sharding, or it can be solved through data consistency. So, these are all the components or the terms we use in order to improve our data intensive application. Don't worry about these terms if you don't know them yet. We are going to cover each and every component in details in the coming videos. So, I hope data intensive applications are pretty clear up to now. But, for the sake of example, we are also going to take one more example. Now, think about Instagram feed. We are not solving Instagram feed issue through any mathematical equations. We just have to gather a lot of data and show you that data. So, what we don't do here, we don't do any complex maths. What we do then? We normally fetch the posts. After fetching the post, we sort them through time or relevance. We show a lot of images or videos. And according to those content, we normally do some operations, maybe like or commenting or sharing. So, I'm writing that. So, this is all the operations loosely we have on the Instagram feed. Now, what is the common challenge which Instagram is facing daily? That is we we have a lot of content. We have millions of users and million of content which we have to handle. So, let me write that down. In other words, we can also say that million of users are reading and writing at the same time. So, with this challenge, Instagram still needs to scale, right? How does Instagram scale? If we think about this, Instagram adds multiple databases in order to store the data. And also, Instagram uses aggressive caching in order to store or get the data fast. Now, we also know that Instagram heavily depends on the images and the video content form. So, in order to handle them, we can't simply store those kind of data into our databases directly. For that, in order to fetch them faster, we need to have certain CDN in place. And in databases, we will only store the location of that particular file which we are going to fetch through the CDN. Now, think about this. In order to fix the latency issue on Instagram or in order to help Instagram scale, we hardly touch the CPU or we hardly touch any GPU. We only touch the data or the components which are associated with them. Because the issue here is not the CPU, but the data movements between the components. Now, this is all about data-intensive applications. Let's now focus on the compute-intensive applications. Now, the compute-intensive application is exactly opposite of a data-intensive application. Here, the amount of data which we are retrieving from databases are pretty much low, but the calculations we need to perform are really heavy. So, instead of putting our focus on database caching, replication, sharding maybe, we move our focus from there to CPU and GPUs. So, let me write down the challenge now. So, we can safely say that here our systems are compute-bound or we can say CPU or GPU-bound. Let me take some examples of this. The most common example can be image processing, video rendering. The machine learning model training can also be a good example of this. Also, we can talk about simulation and cryptography. Now, in all these examples, the data which we are getting from the database are in a smaller level only, but the kind of processing we need to do in order to show these data to user is heavy. That's why they come under the category of compute intensive applications. Now, let's discuss about the worries of a computer intensive application. The first worry is pretty simple, that is how fast can we do the calculation or how fast can we compute? The second worry can be can we do something some processes in parallel in order to show the data faster to the user. You may have seen a lot of systems in which in parallel the image is being processed and you are able to move further with the application. Let the image process and the meanwhile you are moving to the other features of the application. The next issue can be how can we reduce the computational cost? And also as a system designer, we can also think about can we use GPU instead of CPU? So, these are the common worries of a computer intensive application where the data is not much, but the processing is the king. Let me also take a good example of a computer intensive application. So, in order to create a simulator machine, it is very important for the simulator to work exactly how the actual machine works. So, think about a scenario that our country is hiring a lot of pilots every year and we can't spend too much on the actual aircrafts when the pilot doesn't know how to ride it or how to fly it. In order to train them, we need to give them simulators machines and on which they train themself first and then sit on the actual plane. So, now in simulation machine, our common worries or the task which we are going to have is can we do anything in parallel again? Can we use GPU instead of CPU? Again, how can we reduce the cost of our simulator? Also, we need to find a way to gather a lot of good algorithms in order to do the task frequently. Now, at this point I think we are very clear on how our data intensive applications are different from computer intensive applications and why we need to put our focus on computation on different algorithms on GPU or CPU in order to make a computer intensive application works because the data is very low and in data intensive application if we start focusing on GPU and CPU there will not be any big changes because the issue lies in the database network calls caching algorithms or maybe server. So in order to fix them we need to put our effort into the right category into the right components so that our application works seamlessly. And why this is important? Because if we put our efforts into the wrong components our components are not free they are going to cost us money and if we put the money in the wrong place and not getting any help in order to solve our issue it is going to be a bad system design for the entire game. Now when we talk about data intensive or computer intensive applications we often think that these two are very separate applications. But in today's time we live in the environment of multiple applications and each application performs multiple tasks. So that means our data intensiveness or the computer intensiveness of the application can also depend on the feature we are working in. For example we have YouTube right? YouTube is data intensive for serving the videos. There are a lot of videos in YouTube environment and you get the videos and we can say that it is computer intensive when it comes to the recommendation. Because in order to get the recommendations we have to get what you are watching right now. So I think it is pretty sorted now that in order to fix a particular issue you need to first think whether the issue which we are facing is computer intensive or data intensive and then you get into the components and fix that. There is a trick to understand whether the feature is data intensive or compute intensive. That is, if the time is lost in data movement, probably it is data intensive application. Or if the time is lost in the computation, it is probably a compute intensive feature or the task. This one distinctions save you a lot of money, time, and complexity. In order to discuss our requirements, we divide the requirements into two categories. One is functional requirement and the another one is non-functional requirement. So, let's go to our screen and let's discuss this. Functional requirement says, "Please define all the points which you are building, all the features which you are building, all the working which you are building." That means, if we define every feature that comes under the functional requirement. So, let's understand functional requirement by taking an example of any e-commerce application, let's say Amazon. So, what can be the functional requirements of Amazon application? That means, we are defining each and every feature which we see on Amazon. So, let's say on Amazon application, a user can register themself. User should also be able to log in. So, let's write that. After login, user should be able to see the products. Also, user can search the products or filter them. Let's write the searching and filtering into two parts. So, search the products and user can also filter the products. After filtering, searching, user should be able to add any product to the cart. After adding any product to the cart, user should be able to get some promotions or get some discounts, right? So, they should be able to apply the coupon codes to get the discount. And once all this done, user should be able to place the order. After placing the order, user should be able to do the payments, maybe. And once the item is placed, once the order is placed, user should be able to track that order. So, all of these points are the functional requirements of Amazon or any e-commerce application for that matter. In which we define all the functionalities, all the actions which user can take, all the working of the application is defined under functional requirement. So, if we have to write this, what is functional requirement again? Functional requirements means all the features which you are going to have in your application are the functional requirements. Now, let's move forward to the non-functional requirements. For non-functional requirements also, let's start with the example of Amazon only. Let's say the first non-functional requirement is that on our Amazon site, we have approximately 1 million users. So, that means our system should be able to handle 1 million daily active users. Now, in order to give our users a good experience, we can say that the response time should be less. But, in non-functional requirements, we have to define how less. So, let's say for Amazon application, the response time should be less than 200 milliseconds for each request. Now, our application is built and is running, that means our application can't handle failure. But, that is not possible, right? So, we should define up to how much is our availability of our system. That means for how much time our system will be available. That are defined under SLAs and SLOs. So, we have to define them. That for 1 year, our system downtime should be this much amount only. And for 99.9% time, our system should be up. That is defined under availability. After availability, we don't want our data to be flowing easily, so we want to encrypt our data. And let's say on any sale day, let's say Black Friday sale or Diwali sale or Holi sale, in those times our normal users can go up to 10x. So, our system should be able to handle that much traffic also. So, let's write that down. With this, our system should be also able to handle the faults. Because there are going to be faults in the system. No application is perfect so far. Every system have their own faults, have their own downtime. But we need to see how can we track them and how can we fix them as fast as possible. So, that is we need to make our system fault tolerant. So, with this example of Amazon, we get to know that our functional requirement are the features of the system that we can say what our system is going to do. And with non-functional requirements, we define how our system is going to perform. So, these are the specific non-functional requirements for Amazon. If we have to write it in a generic way, there are some generic terms which we can write. So, we can talk about scalability. Let's say our current configuration of server is reaching to a point where it is not able to handle the kind of traffic it is getting. So, now in order to scale, will you scale it horizontally or vertically? That will be taken care under non-functional requirements. Apart from that, as we have discussed, availability of every system will be defined under the non-functional. As we have already discussed, that means our system uptime will be calculated here. Which is defined under SLAs and SLOs. So, in these agreements, it is already defined that, let's say we are using Amazon server in order to deploy our application, then Amazon will give us some contract that we will be down up to this time. And apart from that, you will not see any issues. Now, in those cases, if we see any issues, let's say for a day, Amazon says that we will be down maybe for 5 minutes maximum. But then, if Amazon fails to keep that promise or that agreement, the companies which are using the Amazon service can sue them. Because the Amazon services have given us the SLA's in writing that the services will not be down after certain point. So, availability plays a huge concern there. Next, we have reliability. In reliability, we can say that our system should be reliable. That means there should be no data loss in our system. After reliability, comes the performance. Under performance, we are going to define how our system is going to work, how much latency can we feel in the system. What is our P95? What is our P90? What is our P99? These all things are defined under performance. So, all the words which I have said in this particular video, we are going to cover each and every topic in details in the coming videos. So, don't worry about this if you don't get it now. After performance, we can jump to security. In security, we can have features like authentication, authorization, and encryption. With security, we are also dealing with a lot of code. That means we can say our code should be in perfect modules so that each code or each chunk of code can use different APIs or different modules in order to work in efficient way. After this, we have last but not the least requirement, that is observability. Even if our code is pushed to production, there are a lot of use cases which are handled after that. Because we don't know the exact behavior of users, that how they are going to use it. So, we need to keep track of all the monitoring tools, all the tools which are going to track the user behavior on our application. So that we can improve our system and also we will be able to track if there are any bugs and solve them. So, let me write monitoring and logging. So, this is all about functional and non-functional requirements. I hope you all get it. But in order to completely get it, we all go through a lot of applications on a day-to-day basis, right? We may be scrolling through Instagram, maybe watching YouTube, maybe watching Netflix, or Amazon Prime, or purchasing anything from Flipkart, Amazon, or any other application e-commerce platform, or we may be scrolling through our WhatsApp messages. Now, I want you, while using your application, just sit back for a few minutes and think about all the functional features which you are working, or all the functional requirements which you are using, and all the non-functional requirements which the app must have configured or thought of while creating that applications. Also, comment down the application on which you worked on, and write down three to four functional and non-functional requirements. That will help you and me also in order to understand that we are learning on a similar pace. How does our browser know which webpage to hit? Do they know by domain name, or do they get these things through IP addresses? Let's find out. So, whenever on our browser or on our machine, whenever we write any address, let's say telesco.com, it is going to redirect us to the telesco page, which is our homepage. Maybe some banners here, maybe some courses section here. It is like this only. Now, how do our browser figure out which page to show? Because, as humans, we communicate through names, but systems don't communicate through names. In order to establish the communication between one system to another system, we need IP addresses. So, that means there should be some place in between or some system in between our browser or our OS through which we are going to get the correct IP addresses of each and every site. So, we will send telesco.com, and in return we will get some IP addresses. So, this can be the IP address of telesco. I'm not exactly sure about the IP address, but yeah. Like this, our DNS works. So, DNS basically stands for domain name system. Domain means any specific URL or any specific domain. Domain is this only, telesco.com. There can be multiple domains, telesco.net, google.com, facebook.com, whatsapp.com, .web I think. But yeah, you get the point. These all things are domain. And what is subdomain? If I write any subdomain, let's say docs.telesco.com or any other subdomain, let's say course. So, they both are subdomains of telesco.com. Where telesco.com acts as an umbrella and under which we can create multiple subdomains if and when required. So, these are the domain and subdomains. But mind it, the machines, the computers doesn't communicate with each other through these domain names. So, they need IP addresses. Let's figure out ways on which our system can handle the IP addresses. Let's say we are building a browser. Why do we need DNS? Why do we need another system for maintaining the domains? We can basically install or store all the domain name list on our browser only. Now, is this even possible? Let's say if we have only two or three websites, maybe 10 websites, we can store their names, even 100 also. But the current number of domains which exist in our world is more than 350 million. And as a browser, browser doesn't know which sites I'm going to use, whether I'm going to use Stack Overflow one day and Gmail the other. So, we can't store all the 350 plus domains into our browser. That will crash our system. So, two reasons because of which we can't store the entire domain list on our browser are first thing is it will get heavier. And to store such amount of information, we need a high storage browser. So, that will also impact the performance of the system. Now, the other point is what if the IP changes after some time? What if, let's say, I am running any site, teleschool.com, I have purchased my domain from maybe GoDaddy, and tomorrow I decide to discontinue my service from GoDaddy, and I'll move to Google Domains. So, I'll purchase or renew the domain from there. In that case, my IP can be changed. And if it restores, I need to reassure that in all the browsers where teleschool.com is running, I need to update them. I need to send them some update. So, through this we can estimate that it can't be stored in one browser. And also, it can't be stored in a single server, also, because it will also get heavier. There are more than 350 million domains. That means, if we are going to store it in a tabular manner, so the here will be the domain name, and the corresponding IP addresses accordingly. So, here we will have any domain name such as google.com, and here we will have the IP address, 1.2.3.4, for example. So, by this, we will create the entire list. This is not possible for a single machine to handle, because if that machine breaks, then the entire system, the entire internet will break. Anyone in the world will not be able to use any internet services or any web pages for that matter. No APIs will hit, because it all depends on the DNS. So, one thing is sure, we need a certain kind of system in order to fulfill this requirement. That's why we have one of the most beautifully designed system, DNS. Let's start from the high level. So, this is our machine, which is going to use some internet service provider, and under this service provider, we have something called as DNS resolver. So, this DNS resolver is responsible for us to getting the correct IP of any websites or any domain which we are trying to process. In order to understand this clearly, let me take this and put it in a side, so that I can draw more things onto our screen. So, the first call it is going to make is to our root server. Now, there are 13 root servers in this entire world. That means there are 13 companies who own 13 web servers in this entire world. They are not physically 13, but they are categorized into 13. So, that means out of these 13, we are going to hit one of them and get the response. These root servers are typically named from A to M like this. Again, from this A to M, they are owned from various companies. So, you can see the complete list of the root servers with the companies which own that root servers on the screen. You don't have to remember all of them. You just have to see and understand that these are the service providers of the root servers from which we are going to get some information in order to process our domain. Now, let's come back to screen. As discussed, we were searching for telesco.com. Also, I can remove this now. Now, when we are searching for telesco.com, the root server doesn't know anything about telesco.com, but it knows about the TLDs which are top level domains. What is top level domain? If I talk about .com, this is our top level domain. .com, .net, .gov, .in, .uk, .us, .education maybe .edu, we use them. These all domains are the top level domains of any website. So, that means if we need to find out where telesco.com is, we first need to know which server is handling all the .coms. So, in order to do that, our root server will give the response that okay, you can go to one of the TLDs which is handling the top level domain for .com and the root server will return the IP address of that. Maybe this is the IP address and from now, we know that we are going to hit any TLD, top-level domain for a .com. Now, from this TLD, we are again not going to get the complete IP address of the site. We are going to get the proper server or the name server or the authoritative servers which are managing the all the IP addresses for our domains. Let's say this is the IP address of our authoritative name server. And from this, we are going to make another call which are our authoritative name servers. And from here, we are going to actually get where our telesco.com resides, the IP address, which was 19283841. And once this is captured through our browser, the IP, then it is going to make the call to telesco.com server and it is going to get the web page which is desired for. I get it this can be a little confusing at start, so let me reiterate it for once. So, whenever we click on any site, whenever we want to find any site, let it be telesco.com, it is first going to our service provider, internet service provider. Also, you can see uh it can go through router and router can also have DNS resolver. So, from internet service provider which have DNS resolver, this component is going to resolve all our queries for us and ultimately will give us a perfectly fine working IP address for telesco.com or any other site for that matter. So, the first step is it will go to the root servers. What is root servers? There are 13 companies who own these root servers who doesn't know the IP address of your site directly, but knows which TLD to follow. So, from root server, it is going to check what is your TLD, top-level domain. And in this case, it is .com. Now, as it is dot com it is going to get the IP address of the TLD which is handling the dot com domain. So after this first call now we are going to call the TLD which we get from the root server and from this also we are not going to get the complete IP address of telesco. We are going to get on which name server we are going to hit to get the complete IP address of telesco.com. So from here we are going to get the authoritative name servers IP and accordingly we are going to hit our third and final call to our authoritative name servers. Our authoritative name servers are mostly can be configured in GoDaddy or Hostinger or any other service providers in your current application. And from these authoritative name servers we are going to get the IP address of telesco.com. Now in order to click one side we have to do these three operations. This can be heavy, right? So this is only done first time and the next time when you click on anything it basically takes the value from cache. Now cache can be stored in three locations here or more than three if you think about it, but three are definite locations. The first is the DNS resolver can have the cache to have all the common IP addresses which we are going to take or the all the common domains which we are trying to hit. It can store it here. Also on our system we have two things. One is OS and one is browser. In both of these areas we can basically add that domain and the IP address in order to get the details fast. So browser also maintain that cache OS level also we can basically maintain the cache and on our DNS resolver site also a cache is maintained in order to get the details fast. Now when we are at this topic let me tell you about one more thing, that whenever we create domain name systems like this dogs or subdomains, these all entirely creates a zone in the authoritative name server. That means telesco.com including all the subdomains. So, one zone can contain multiple domain list, which will include only the domains specifically to that particular main domain. Okay? And through this it is easier to get to the main domain. So, in this case, whenever we are hitting the root server, we are getting the IP of TLD, again hitting the TLD, getting the IP of authoritative name server. And in authoritative name servers, we can have different zones attached to different domains. And in this zone, if it is telesco zone, in that case, all the domains which are associated with telesco.com will be here. So, if instead of telesco.com, if we are hitting courses.telesco.com, and from this, the authoritative name server will get that this is our telesco zone. And in telesco zone, we will get the courses.telesco.com IP address also. So, yeah, this is it for DNS for now. I hope you understand it. If you get it, let me know in the comments. If you have any queries also, let me know in the comments. Have you ever wondered, if you see Zomato, if you see Uber, if you see Ola, if you see Rapido, and all these applications, also Swiggy, they all have an inbuilt map. But, did they create their own map in their applications, or do they use the existing Google Maps in order to do that? Now, that is possible only through APIs. So, Google Maps present some APIs to other applications which they can use. Now, in order to understand APIs in detail, let's dig into this video and go to our screen. If we think about API, the API basically stands for application programming interface. Now, what does this mean? Suppose this is our application. Any application will work. Let's say this is a movie application. In which we have all the movies, plus we have all the ratings, all the reviews of the movie. Like IMDb or something, okay? Like Rotten Tomatoes or something. So, we are already capturing all the details which includes a movie like latest movie, latest hits of 2000, 2010, 2020, everything. Now, we already have this amount of data which is stored in our database and our application is already working on that. Let's say now in any other corner of the world, someone is trying to create one application based on the data which is already captured in this app. Now, they have two options. Either they can create their own engine like this, their own application where they will again curate all the ratings, curate all the reviews, and curate all the data. But now, where are they going to curate this from? For this, every application leaves some end points which can be used by another application. Now, if for our application or for this developer application, if they want to use rating of some movie application, they can directly call the APIs of this application and through which they will get the proper information which is required for them. Now, like this, this developer or this application don't have to create their own application for the task which has already been done. So, they can use the application data directly. But again, can't we directly give access to our database? This can be dangerous, right? Because then this application again have to handle a lot of scenarios based on the database queries, plus they can also delete some important data in this database which will affect the other applications which are using the same content. Also, there are some added functionalities. Let's say we are giving an option to write a review again. So, in this we have already handled that case through some or the other API. So, instead of creating a new endpoint in this application, we can directly access the endpoint of the other application, which is going to take our review also. So, in this case, this application saves a lot of time because they are using another application, the APIs of another application through which they are going to do the same work. Now, in this case, if this application wants to add some data into their database also, they can easily do this. So, this is one use case of creating an API or using APIs of other application. Also, there can be a case where you're creating an application and in the backend you are exposing the APIs which can be used by your front end. So, front end can be a web application or even a mobile application. Can be both also. Let's say we are creating some backend and from for that application we are also creating front end maybe using React or something and backend using Swift or something. In both of these cases, these languages, the React and Swift, both are capable of handling APIs. So, they don't care about which language did the backend use in order to provide them the API. They will directly call the APIs and use the information which they are trying to use. So, this is another scenario where there are no two applications, there is only single application which is divided into front end and backend part and using the data which backend is providing. Again, in this case also, you can think that they will use the database directly, but it is restricted and prohibited for the security of data which we have already discussed in the first case. So, with this we understand the core functionality or usage of the APIs. Number one is if you want to give access to some other application, and number two is if you want to give access of the endpoints or the APIs to our front end. Now, this both can also happen at the same time because it is up to us how do we want to expose our APIs. Some applications or some backend basically restrict the APIs to be used through their front end applications only. And if you want to make them open, you can make them open so that other application can also use the same API. Now, let's move forward to the type of APIs. The first type of API is called as REST API. If you are a developer, you already are using this. Also, if you are creating projects, you might already have created them or use them in your application. Now, REST basically stands for representational state transfer. REST is one of those APIs which you will see in most of the application nowadays because of its easiness, its structure, and its ability to easily maintain a large amount of data with low volume. So, that's why we use REST. Mostly, in REST we use JSON, which is JavaScript Object Notation, which is a way or a format through which we will send or retrieve the data. It is a easy to use format, that's why we are sticking with this for this today's video, and we are going to cover this in details in a minute. Also, we have some other types, that is SOAP. SOAP basically stands for Simple Object Access Protocol. This is also one way of handling the data across applications, across different platforms, and SOAP basically use XML formats in order to transfer the data. XMLs are replaced by JSON because XMLs were really bulky in nature because in order to create every object or every array, we have to mention the attributes again and again, which is solved by JSON. So, that's why we prefer JSON over XML any day in today's time. But, the SOAP or the XML was famous back then. So, that means there are a lot of applications which are still using XMLs. Why? Because there are legacy applications. They are built way earlier when JSON was introduced and still are using XML. So, in legacy system, if the APIs are created and exposed using XML, that means in order to make our system work, we also need to know about XMLs so that we can integrate those APIs into our system. Also, you can use some middleware application where the data will be taken in the form of XML and will be converted into JSON and your application can use that data afterwards. So, that's why if you are working with a legacy system, it is preferred to understand the XMLs also so that you can convert them in JSON or you can work them without converting them as well. So, after SOAP, let's jump to the third one, which is GraphQL. So, GraphQL is also used widely across many applications, many platforms. So, the basic thing in GraphQL is GraphQL basically says that I'll provide a single endpoint, only a single endpoint, and based on that, you can send whichever query you want. So, in FE, from FE side, we will not hit multiple endpoints, but we will send a request as a query. That's why the GraphQL stands for graph query language. So, GraphQL also have a query language that is similar to SQL. In SQL also, we have multiple queries from which we can do our things. In this also, only one point is exposed as I told earlier and using that only the front end now can send multiple queries and access that particular endpoint and get the data which they want. So, this is the core concept of GraphQL. So, as I said, GraphQL is also present in our today's time also. So, there can be a chance that you learning GraphQL and working on it. The other type of API is gRPC. Here, the RPC stands for remote procedural calls and for G some may say that G stands for Google because it is created by Google, but it is gRCP remote procedural calls only. So, instead of using XML and JSON, we have a new format here which is called protocol buffers. It is very much efficient than JSON and XML combined. So, that means the size of protocol buffers are usually very small than XML or JSON. So, that will enable the data to transfer faster. So, because of this only Google created this and uses this. So, this is small in size and faster to transfer. In today's applications where we have microservices, right? So, in microservices, this is our entire application and let's say our applications is divided into multiple applications which is combining the data of their endpoints through each other. Let's say these are the connections and through this they are going to provide the actual API to the outer world. Now, for this communication between these microservices, we often use gRPC. Why? Because internally at least the communication should be faster to provide the relevant information in a low latency. This will also help us having multiple microservices and having various kind of communications between them before giving the actual data to the other application or the front end. Now, let's jump to the last one in our list today, which is WebSockets. WebSockets are also used in today's time and today's application for various purposes. For every notifications, if we see, WebSockets are used. In order to maintain a chatting stream, WebSockets are used. Wherever you need some real-time connections, WebSockets are used. So, its architecture is slightly different from the other services. In other services, front end or the other application will place some request to the application and then they will provide the response. But, in WebSockets, whenever front end creates a request, a channel is created. Now, once the channel is established, then the conversation can be lead through back end also. Whereas, in other forms, only front end or the other application, which is trying to access the information, they send the request and get the request. But, in this case, since the back end also can initiate the conversation, that means it can also send some or the other information by itself. Those information can be the chat or the notifications, which is very helpful for front end to get. Because, if this channel is not there, the front end have to constantly ask the back end whether there are some new notifications or not or whether the chat is there or not. But, once the channel is maintained through WebSockets, it is easy to navigate message from back end to front end and front end to back end as well. With this also, if you have played quizzes on our Teleschool platform only, Teleschool channel, in which you may see an application which Naveen sir presents in order to share the quiz with you all, you use that application in order to give the responses. Now, those responses or the marks are calculated based on the response time and the correctness of the answer. Now, those connections are also maintained through WebSockets. That's why you see many notifications or some GIF or something something. So, this is about web socket and with this I would like to conclude this session because it is going to be a long session and it is better to understand these things in parts. So, these are the most used five type of APIs which we have. Now, in order to understand them briefly in the next video, I'm going to talk about RESTful APIs in which we will discuss the various aspects or the parts of the APIs and also see what are the recommendations and usage of those APIs. Now that we already know about RESTful APIs and all the other different type of APIs, it's time to deep dive into one of them. And for today's video, I have selected REST APIs to deep dive into. Why? Because it is the most used APIs across the world. It doesn't matter if you are starting a career or you are already seasoned, you have to work with RESTful APIs for sure. So, let's move to the screen now. RESTful APIs are also known as REST APIs. As we know, it stands for Representational State Transfer. What does it mean? It means that REST is also one format through which we will transfer our data from one end to another end. What are these ends? We have discussed this already. Either we are giving some data from front end to back end or vice versa. It is also possible that one application needs to get some data from some other application. So, in that case also, APIs are used and REST specifically is used to transfer some data from one end to another end. So, basically, it is a way of how our applications are going to communicate with each other. Now, before starting, let me tell you that in REST, we normally use JSON. JSON is a standard way of sharing the data. In JSON, we can have array, we can have object and with these two combinations, we can share our data in the form of key and value. So, let me create a simple JSON. Let's say this is a start of an object and here we have a key, let's say name. For value, I'm writing my name. With comma, we separate different values. So, after comma, I have to write some other key. So, let it be age. And with age, I can write any numeric value as well. So, as we can see, this is string value and this is a numeric value. There are more values who are accepted as a form of value, which is We have already seen string and then number. We can also use boolean, even a nested object, arrays, and a null. Null can also be used because if we don't have any value for that particular field directly, it is easy to say it is a null value. And the application which is using that value can take care of it. So, this is all about the JSON which we need to know. We need to know that it is in the form of key-value pair and what are the values which we can use. Now, let's move forward to the next part, which is endpoint. In order to understand endpoint, we have to get two things. One is method and the other thing is path. So, in order to access any data, we have to have some URL on which we will hit with that particular method and based on the method selection and the path, we are going to either get or pass some data to our server. Let me start this with an example. Suppose we are using HTTP as uh any site, my site .com. So, this is our main site and after that, we can put a slash and use a different URL. Let's say we are separating all the APIs in the API subdomain. So, APIs is there and then we can also segregate the APIs using version. So, this is version one and here we are going to write resource. Now, resource can be anything. If I talk about any e-commerce application, it can be a product, it can be coupon, can be user, can be anything, basically. A resource is an entity through which we are navigating and getting and passing the data to the database. So, this is the URL. The URL is called the path through which we are going to either get or pass some data. And with this, we need to have a method. So, for method, we can have a get basically. So, get method with this path combinedly creates an endpoint and through which now we can get some data. We expect this path to retrieve some data because we are using get. Now, there can be multiple ways of creating this URL. So, normally, we hide the domain part of it. We don't use them in the explanations. We only use the resource part. Also, we can remove the version also. With that, API can also be removed in order to understand the resource part directly. So, from now on, if I create any path, let's say users, it is expected to have all this domain name API versioning if it is there beforehand. So, I'm not writing that again and again. Cool. So, with that, if I write users here and use get method, now I'm expecting some response from our server. I'm expecting either a list or a response from our server. We'll come back to responses in a while, but this is how we can get some user information from our server. Now, let's move to the second part. In this, we don't want all the users, we want a specific users. So, to find a specific user, we have to provide them an ID. Normally, we provide them in the URL itself. So, it is get users and here we can include the ID. So, in real time, it can be used as users/1. So, if we write one, the user with the ID one will be retrieved. Now, with this, we can also add any user. So, the third part is adding a user. So, again, the URL will be same users and now we are adding the user, so we are using the method post here. So, in this with post, we are going to give some body, and in body, we will have some JSON which will store the user information which we are trying to create. And based on our request, our user will be created in our database. Now, once we have all the user details in our table, we may choose to update any user information, correct? So, for that, we use another method which is put. Again, the URL will be same, users. And with this users, we will send the ID of the user of which information we are trying to update. So, with put, we also have another method which is patch, which can also be used in a similar way to update the user information. Now, what is the difference between put and patch? It is simply that if we use put, our entire user object will be replaced with the new data. So, this is going to replace the user data. And if we don't want to update all the fields, we want to update a specific field or particular field, suppose username, name, age, or anything, so we can use patch. It can be used to partially update the user record. Let's understand this with an example. Let's say we have any user information which have ID and have a name and have a username, maybe age. This is all. So, these are all the values which are user currently have. Let's we put some values. So, if our user table or user entity have these all four values, if we use put to update a particular change only, let's say I'm going to change my username from Akshay to AK something. So, now this change will only be done if we again send the entire body into the put request. If we only send username like this, then all the other values of our entity will be updated with the default value. So, if we send this kind of data in a put request, it is going to replace our entire entity. So, that means the name, the age will be replaced by the default or null value. So, it is not recommended to use put entirely if you want to update your entity partially. In those cases, always try to use patch. In patch, we're going to again update the particular information. So, this is perfectly valid for a patch request. So, with this, let's move to the next part. The next kind of method which we use is delete. In delete also, normally we pass the ID like this. So, if we write users and with {slash} we write one, so that means the user with the ID one will be deleted. Now, this is the usual stuff. You will get this information anywhere. Now, let me talk about something which is nested data. Let's understand nested data with an example. Suppose you're creating a blog site. So, in blog site, we normally have our users who are going to read our blogs. Then, we have blog, the actual content on the site. And on blog, the user can comment. So, we have clearly three entities: users, blogs, and then comments. So, these three entities are interrelated. So, a user is going to give comment on a particular blog. Users can't comment if there is no blog, correct? So, this is the way. Now, in order to create APIs for this, we can create a users API for all the users' activity. So, all the users' activity means we can use it for get, put, push, delete, and patch also. Now, this is simple because a single entity is there, users, and all the operations are on that users only. Now, let's say we want to create an API on which user can add a comment. Okay? So, for that, what we can do, we can either go from the blogs perspective. So, every blog have a particular comment section, right? So, blogs, then here we can write ID. So, this ID is basically belong to the blog, and with blog, we can write comments. And if we write get here, what it is going to do, it is going to give us all the comments which are associated with the blogs with ID this. Correct? So, this is a nested relationship where we're trying to access comments, but we are going via blogs. We can also do like this. Suppose we are on the user's page, and we want to see all the comments that user have created. So, we can again create a get query via users, where this is the user ID here, and we can see comments. So, we are dealing with two different entities by creating the relationships between them. So, by this, we are going to get all the comments which are created by the user with this ID. So, we can go to comments via blogs, as well, and via users, as well. So, this is nested. Again, if you want to update any comment, delete any comment, we can use simply the comments path where the user can enter the ID here of the comment. And they can use it to update or delete that particular comment. So, here you can also ask me that why are we using this kind of nesting in URL? Why are we not sending the data in the request? So, that is also possible. We can do like this. We can go to this comments, and we can pass the request body, in which we'll pass the post ID to get all the comments associated with this post. This is also possible, but this is not recommended. As there is a direct relationship between two entities, we don't normally go for this body approach. We go for the URL approach because it is easy to understand also. So, when do we go for the body approach? So, the body approach is used when we are trying to filter any data. So, we understood two concepts here. First is the nesting data versus filtering. So, when to use which one? If you have a clear relationship between two entities and it is clean, so you can go for nesting. And also in filtering, apart from sending the data like this in post ID, you can also use the URLs like this, comments, and then in query parameter, you use post ID. Now, this is again not recommended because there is a direct relationship between comments and post. So, it should be a nested type of URL. So, if there are clear relationship, we can use nesting. And if the relationship is complex, we can go for filtering. Also, the filtering will be used whenever we are trying to do pagination or we are trying to filter particular records based on multiple ways like we can go for any e-commerce page where we are seeing different products and we can filter our product based on our color, price range, and all these things. So, those things normally go for query parameters as a URL, right? And we don't go for nesting there because it will be complex to handle a long path with nesting data. So, the crux is if the relationship is pretty straightforward and we will go with respect to the other entity, we'll go for nesting kind of URLs. And if there are complex relationships or the filtering is used, we'll go for the query parameters. Now, let's move to the next part. How do we pass the actual data to the endpoint? So, there are three ways. Either we can use path, so we can integrate the IDs in the path, or we can use some query parameter, or we can use body. I have given you glimpse of these all three in the previous section, but now let's talk about this specifically. So for path, it is very specific that we will only pass the recommended IDs or maybe slugs or maybe that particular unique identifier only. So this is unique identifier. It can be ID or slug. Slug is basically a short form of that particular post. If you are using any blog site, so let's say the blog site the blog is about what is Java and in slug you can see something like blog /what is Java like this. So this is our slug. Again, this slug will be unique throughout our blogs. So the name of the URL I have also written blogs, it is wrong. Normally we address the URL in the form of plurals. So it is going to access in multiple areas, multiple scenarios. So normally we don't go for blog, we go for blogs like this. Cool. Now for query parameters, whenever we are filtering or maybe sorting, we can go for query parameter. Suppose we are again scrolling through our blogs and in blogs we can write like sort ASC or we can assign some numbers also. So ascending means sort ascending maybe by date. So whichever date they are created, they will be sorted by that. Or maybe we can use DESC for decreasing order. So that the latest post will be pop up first. With this again we can use the query parameter for filtering. So maybe we can use blogs again here and with that we'll pass query parameter. So this is Q for maybe query search or search step. So anyone with is searching for Java and it will give us a list of blogs for Java or which have Java in their name or their content or their category. So, this is all about query parameters. Now, whenever we pass any information in query parameter and path, those informations are going to be exposed, right? So, that means we can't pass any sensitive information into query parameters or path. So, for that we have body. So, let's say we have a login path, and now we can pass username and password in the body, which is not exposed at all. So, it is safe. So, the rules are pretty clear when we use path, query params, and body. Now, with this let's see a full request in action. The first thing is we will have our method. So, this is maybe a post method, and we are using some API of version three, maybe. For version three, we are using users, and then we can also pass the metadata. Suppose content type we can pass, which is application/json here, because we are passing the information in the form of JSON. We can also use XML, or if you have latest information, we also have a new format in town, which is tone. So, we can also use various kind of information, but because currently we are using JSON, so we can pass it like this, and with this we have our body. In body, we can pass anything, maybe some data we are trying to add, and then maybe username. So, like this we can pass the entire request or the data to our server. So, this is what? This is our method. This is the path. This again is metadata, and this is our body. Now, once we have understood the request correctly, it is time to understand the responses. So, in order to understand the response, first we need to understand the response code. So, there are specific codes assigned to a specific type of response, which if the user gives will clearly understand what they want to tell us. So, let me start with those status codes and then we will move forward. So, these are all the response codes which we have to know. 200 stands for okay. So, this means everything is working as expected. Don't worry about it. Then we have 201. 201 is basically used when there is a new entity created in the database. So, this is created. Then we have 204. 204 is again saying that everything is working fine, but I don't have anything to provide to you. Let's say we are deleting any entity, so it is successfully deleted, but they don't have any response body to give to us. So, that means there is no content to give to us, but the request is working fine. Then we have 301. 301 is basically used for redirects and 301 indicates that it is a permanent redirect. And if the redirect is not permanent, then we use 302. That is temporary redirect. Then we will come to the 400 series. So, all the 400 series basically says that there is some issue with the request we are having. So, the 400 stands for bad request. That means some or the other data is not correctly mentioned in the body. Either they have some validation issue, either either they are missing when they are required. Either they have some other issues, but request which we are getting, the body doesn't have the correct information. So, in that case, we normally give 400 bad request as a response. Then we have 401. 401 is given when someone is trying to access some information for which they are not basically authorized. So, 401 is unauthorized. With that we have 403, which is used for forbidden. Suppose on an LMS, you have not enrolled for a course and you want to access a particular video or lesson part of that course which is not publicly accessible. So, in that case, you will receive 403 forbidden because you are not allowed to see that particular resource. With this, we have 404 page not found. This is basically used whenever the URL is incorrect or trying to access some or the other resource which is not there into our system. And at last, we have 500. So, 500 is the response which is given to a front end when there is something wrong with the back end. So, this is related to back end. Some or the other error is there in the back end. Maybe some syntax error, maybe some other error, some logic is missing, some data is missing, something is wrong with back end. So, this is internal server error. There are many errors which we don't want users to see. So, those all are handled by 500 because we don't want the user to understand what is the issue we are facing with our database connection or anything. So, we will create logs into our system and through which we'll resolve the 500 error issues. So, these are all the most commonly used response codes which we have to understand. So, now whenever we are creating any APIs, if the response is completely fine, we will provide 200. If we are creating any entity, we will provide 201. If we are deleting or performing some operations where we don't have to give any content or any data or any body in the response, we will use 204. Then, if the permanent redirection is there, we will use 301. If the redirection is for temporary basis, we will use 302. For any bad request in the body, we will use 400. For authorization, we will use 401. For forbidden or the content which requires some special access, we will give 403. 404 we will give when they are trying to access any resource which is not there and 500 we will give when there is any issue in the internal server. So with this, let's move to the next part which is response body. So normally in response body, what is allowed first we start with that. So we can return an array, right? Also, we can return an object. With this also we can return data as nested objects. Now in most of the applications whenever you are going through any YouTube tutorial or any course also sometimes when you are dealing with multiple responses, let's say the responses for this is normally an array, right? But it is not recommended to handle the response as array. It should always be wrapped in the form of an object. And if you want, you can use any other key for this users and in the value you will give these responses. Now these can also be string or an object. Normally an object only of all the users, but it should be handled like this. So this is the correct or I would say recommended way. So every response body should be an object. And even if we're trying to give an array, we have to wrap it up into an object and give us in the key value form. So this is a good practice and through this we'll achieve a more long-lasting code. Why? Let's say today we are passing the user details only and tomorrow we understand that okay, we have to add more fields. So we don't have to change much on the front end side or the receiving side, but we will simply update our response, change the object here and maybe add some other field user count and pass that information maybe 29. And with this we can end our object here. So we can pass as many informations as we want, but if we have used a single array as a response, then we have to struggle with it and we have to change the entire architecture of our response. So, it is always recommended to pass the response always in the form of an object. So, let me write returning as array not recommended. Let me know in the comments if you already knew about this or you are hearing this for the first time. So, with this, let me create a map of request type and responses. So, let's say here we have request. Here are the responses which we are going to receive. So, if the request type is get and we are trying to access many records, so maybe we are trying to access users, it is going to give an array of records, right? So, it is normally going to give 200 as a response code and going to give an array. Now, we understand that we have to not give array directly, so it will be wrapped in the form of an object. Now, the next request is also a get request where we want to access a particular object. Let's say one. Now, you can think that we will give the user information directly, but again, it is not recommended to give that directly. We will use the nested object for the same reason. So, in this object, we will use the user as key and pass on the user information into this object. So, this is the actual user object, but we are wrapping it into an another object because it will give us flexibility to pass some more information if we want to. So, let me clear this up for now. So, normally, we are going to get 200 response with this kind of nested objects. Also, it is possible that this ID is not there in our DB. In that case, we can also give 404 response. Now, if we are adding anything, we will use post with the same URL, and normally it is going to give 201 response, which means the entity is created. And also, we can use 200 response if you want. But, if we are using 201, normally we give the ID or the new object as response. Now, here with post request, we are also giving the body, so it can also have 400 issues, right? 400 bad request issue. And also, if the format doesn't sync in, it can also give 500 issue. If the data is coming properly and there is some issue in the back end, it can also give 500 easily. So, these are most common response codes which you can have while working with post. Now, let's talk about delete. In delete also, we will pass this URL with some ID, and this can also give 200 as a response. And also, if it is deleted correctly and we don't want to give anybody in the response, we can go for 204. If this entity is not present, maybe the ID they are using is one and we don't have any record with the ID one, we can have 404 or we can have 500 if there are any dependencies and which is not handled correctly by our back end. With this, you can also see 401 here if you are unau- prized person to delete that particular record or you are not allowed to delete that particular entity, you can also get 401. So, these are the most common request responses, and with that we have also discussed what can be there in the response body. So, with this we have covered the entire request section and the response part of the REST APIs, and I hope the information which you get from this video is going to help you in your entire development career. Whenever you are dealing with REST APIs. In order to build any application, we have client on this side, right? Who is going to interact with either a web application or a mobile device to interact with our application. Now, with this we will have our server in this side. So, this is maybe our server. And if we keep the model like this only, that means every time we restart our server, all the data which user is trying to access will be lost. Because when server restarts, it clears all the data. But, the thing is we need to store that data somewhere, right? So, for that we use database in order to store the information which the user may require next time when they log in or see our application. Now, one thing is very clear that most of the application can't live without databases. Now, in order to understand how do we store data, we have two approaches. First is the SQL approach, and the other one is no SQL approach. So, SQL basically consists of RDBMS, which is relational database model, in which we will have tables, rows, columns, and we will connect those tables based on different joins and everything. And in no SQL, we have other methods. See, saying SQL and no SQL is like saying Java and no Java. That means there are various options in no SQL. We can have our data as in the form of key value. Also, we can have column. We can also have the data in the form of nodes, maybe. And we can store them in the form of graphs. Also, we can store the data in the form of document. And here, if we talk about SQL, we have our tables in place, who is going to hold our data in the form of entities. And there will be different relationships between different tables. Also, in order to do in SQL manner, we have various softwares like post dress or we can go for MySQL. Right? Like this, we can have multiple options here. For here also, we have multiple options like Cassandra or we can go for MongoDB. And based on this selection, where we are going to do it SQL way or no SQL way, we are going to build the entire foundation of our work. Like how our data, our important data is going to store in our database. So, in today's video, let's focus on SQL. And in next video, we will focus the ways of no SQL. So, let's start. So, SQL basically stands for structured query language. And SQL comes under the category of relational DB. Now, in relational DB, we are going to have multiple entities and we are going to establish different type of relationships between those entities, if required. So, we are going to store our data in the form of tables. So, we can loosely say that every table is loosely an entity. It can either be a user entity or it can be comments or it can be post, if we are building anything like blog site or something or it can be videos, if we are building YouTube. So, like this, we segregate our different entities and then we will build the relationship between them. Now, if I draw one of those tables, let's say we are building a user table. A user table can have multiple fields. That is equivalent to a user entity can have multiple properties. For example, a user can have their unique ID. A user can also have their first name and L name and maybe we also have their phone number. So, this is how a table is formed, where we have multiple attributes of a table. These attributes are stored in columns and when we have a complete record, let's say in this table, we can add a new record where I can add any record, let's say the ID is one, the name is Akshay, last name is Agarwal, and phone number is, let's say, 987654 321. So, this is my number, this is a complete record. Now, this record is called as a row. So, by getting any row from our table, we can get the entire information of that particular entity or of that particular user. Normally, for the name of entities, we don't go for singular words because it will contain multiple records. So, we will go for plural things, users. So, this is the standard, this is a constraint, this is not a particular rule, but it is safer to go into plural things. So, for comments, we can go for comments, for post, we will go for posts, for videos, also, we will go for videos. So, all these things are in plural. Why? Because a single table will contain multiple records. It will be easier for us to fetch the data with that plural name because then we will know that multiple entries are there and it is a convention to use plural things. So, with this, let's move to our next topic, which is constraints. If we are building any application, we can have multiple users who are coming with different backgrounds, different geography, and everything. So, it is our responsibility to make them enter the data correctly. We will use validations in form, and in database, we can handle them with the use of constraints. Because every wrong data and every faulty data is of no use. So, for that, let's dive into the constraints. So, the first constraint is unique. Unique basically stands for a unique value throughout the table. For example, in the user field, let's create the user table again. So, this was our user table, let's add one more column or one more attribute, which is username. Now, we don't want two users to share the same username. This is a common thing which we can see on Instagram also. If you're trying to create a new username and if that username is already taken, you may get some suggestions with some extra characters or you can change the name entirely. Similarly, for Gmail also, if the username is taken, they suggest you some more usernames with the extra characters. So, that means we can say that the username is unique. Every user will have their unique usernames. So, in order to maintain that username uniqueness, what we will do, either while creating the table or while adding the username field like we did, what we do, we add the constraint unique to that particular username. So, that when any user comes to this entry and if they write ABC, no other user can write ABC. If they want to use the same username again, they will not be added into our databases. Why? Because this username field is unique. The next constraint is not null. So, not null basically represent a value which can't be null. Null is the default value for any entity, right? So, whenever we want a field to have a particular value either given by a system or server or given by our user, we want to have that value. So, we can't have null in that. If we see in users table, the first name can easily come under the not null category. So, we don't want our first name to be null because we are going to address our user with their first name. So, this is a required field. The next constraint is primary key. So, our primary key acts as a unique identifier for that particular entity. In our whole user table, there is no record which can share that particular value. So, if we find any record with ID, let's say ID is equal to three, so only one record will come out of this. Okay? It can't give two records because the ID cannot be shared between two records. So, it will give a unique record out of our users table. So, our primary key basically helps us to track down to that particular record. And also, it helps us when we deal with multiple tables because there we might need some ID to put into some other table as a foreign key. So, in that concept also, primary key is used. With this, we can have a fourth option here, which is check. Check is basically used in order to maintain the authenticity of any record. Let's say we are using a password. So, while creating a password or while having a password, we might want our user to use certain constraints like the length should be greater than eight or maybe it should have any numeric values or it can have one or two special characters also. So, all these rules which we apply are applied in the DB for that particular column through the check constraint. Also, the other example of this can be a mobile number or a phone number. So, a phone number will only contain numeric values. It can't have any characters apart from that. So, this is also a check which we can apply for our phone number field. Also, the checks can be applied to any field. Let's say for first name, we can't have any name whose length is less than maybe two because A B C D, this can't be stored as a name. The shortest name I know is Om, right? It is also two characters long. So, we want to have that check. So, all the checks are covered with the check constraint. Now, with this, let's move to the other constraint, which is foreign key. So, let's understand foreign key through an example. Let's say we are creating a blog site where we have users table again. So, the users table is basically the authors table. Or let me rename it to author then. So this contains the list of all the authors who are going to publish some or the other blogs. So there we have this ID and then from this ID, let's say we only have two fields, first name and last name. We can have multiple fields if you want. For the sake of this example, I'm creating this smaller. So let's say we have one and the author is Akshat Agarwal. Let's say I have two authors. Okay. Now these two authors are not going to write only single post. They are going to write multiple posts. So we will have to create a separate table for posts and in that post we will have some ID. I'll have data or maybe content is the better word. So I'll change the name data to content. And that content is provided by some or the other author. So here we will have author ID also. So now let's say our post, first post, have some data about HTML and who wrote that post? Maybe Akshat. So for Akshat, I'm not going to write the entire details about the author again into this table. So for that, what I will use, I'll use the common identifier which is our ID. So our ID is our primary key here and which will be used as the foreign key here. So this is our foreign key and we will simply write one. With this particular information, we are going to get that okay, this author ID is one that means it is written by Akshat. Similarly, if we have multiple fields like this, let's say post two is on AI maybe and it is created by Gaurav. So we don't have to write the entire fields or entire information about Gaurav. Only the primary key will do. So from this two, we are going to again recognize that it is written by our second author who is Gaurav. So this is the role of our foreign key to establish the connections between two entities. With this, we also have a next constraint, which is default. So, default basically stands for the area or the field where we can't have null. So, null is not an option. And we don't want our user also to have that entry as a mandatory field. We can fill in for them. Let's say we are building anything for subscription. And if user have not paid anything to get a subscription, they might be having free as the value because they are currently using our free subscription. So, this is one case. The other case can be, let's say you are into our learn.telesco.com, right? So, this is our LMS and we are creating them. So, in this, every new user or the more number of users are going to be students only. And only few users are going to be managers or trainers or maybe admin. So, those are few categories and most of them are going to be students. So, the default value of role for every user here is student. Student/learner. So, either student or learner, we can have as a default role. And with time, let's say one or the other student or learner got hired into Telesco only to maintain the notes or maybe to teach, then we will update their role to trainer. This is how the system works with default. So, these are all the constraints which we have in our databases. Now comes the next part of our relational databases. One of the most important part is join. Join is basically used to associate two tables. That means to manage relationships between multiple tables. And why do we do that? To basically maintain relationships between different entities. So, let's see how many joins options do we have. The first and the most common join option is one to many. So, we have a users table. We have ID here, and we have F name only. Again, I'm going to use the same entry, one and two. And here, I can write any name. So, here are the two names, Akshay and Gaurav. Two entries basically for this users table. And again, we are creating a blog site. So, that means both Akshay can write multiple blogs, and Gaurav can also write multiple blogs. So, we will create another table to maintain our blogs, which will have ID, the content, and the author ID. So, maybe the first blog, which is on HTML again, is written by Akshay. The second blog is on AI, which is written by Gaurav. And then, there is third blog, which is on system design, which is created by Akshay. So, here we have one to many relationships. Because for a single record here, we have multiple options or multiple rows associated with that particular row. So, this is one to many relationship. With this, if we reverse this, we can also have many to one relationship. So, what we will do? Here, we were talking about users to blogs relationship. And here, we are talking about blogs relationship with users. So, here we can safely say that multiple blogs are associated with the same user. So, here we can have multiple blogs associated with the single user. So, this is many to one relationship. Now, let's move forward for our third relationship, which is many to many. So, in order to understand many to many, let's again go to our LMS. So, in LMS, we can have students. And we have courses here, right? Students also, we have ID maybe, and only F name is here right now. And in course, we have ID, and then we can have the course name here. Now, let's fill in some entries here. So, here we have students as Akshaya and Gaurav. And our courses are Master Java, Master AI. Now, Akshaya as a student can enroll into multiple courses. So, we can sense that from students, we can have multiple relationship for courses. And also, one course can have multiple students. And it is also possible that in Master Java, we have both Akshaya and Gaurav. So, that means our students can enroll into same course. So, whenever we see a situation like this where we can have many students or many records from single table associated with the single record of another table, and vice versa is also true, we are going to get a many-to-many relationship. So, in order to maintain multiple relationships, we have to have a junction table in between. So, this is our students-courses table. And here, we will have a unique ID of this particular record. Maybe this is required, maybe this is not, based on your queries and use cases. Here, we will have students ID. And here, we will have course ID. And now, while entering the data, we can simply say the record one, we have Akshaya enrolled in Master Java. Now, record number two, we have Akshaya again enrolled in Master AI. Then, for the third record, we have Gaurav enrolled in Master Java. And the fourth record, Gaurav enrolled in Master AI as well. So, with this junction table, we are going to figure out how many students are enrolled in how many courses, and how many courses have how many students. I hope this makes sense. This is a little confusing if you are starting, but this is how we maintain many-to-many relationships. With this, we can have one more relationship, which is one-to-one. Suppose we are building a platform like YouTube or blog site which also have podcast, which also have maybe video section. So, we have three kind of content, right? The first content is text for blogs. The second content is audio, and the third kind of content can be video. Now, the processing of all these contents are different. We can handle these multiple options by two ways. Either create a common table named as contents. So, in content now we have three types. For video, we are going to store MP4. For audio, we're going to store MP3 maybe. And for text, we're going to use the text which is there in database. We can use varchar, long text, short text, maybe text. Now, there are three kind of content. We can basically divide them by using a field which is type. So, in type we will have options like text, audio, or video. So, here the first record can be on again HTML, which is a blog type text type. So, we will type one here or text directly here. For the next content, it can be anything. Let's say the content is on improve focus, and in order to make that content, we don't have a video. So, we have something like audio here. And for the third thing, we have any video, let's say system design. And for this video, we have the type as video. Now, if you have worked into systems with these type of content, the processing of each type is very different. And if we curate all these data into a single table, it is going to be a really heavy one. Now, what are the drawbacks of having a heavy table? That is, whenever we are trying to filter, we have to basically filter through each and every content type and each and every record as well. So, instead of having all these kind of data into single table, what we can do is we can segregate the data already into multiple tables and have those IDs as a foreign key. So, the other approach is we will create a simple contents table where we will have ID here again and maybe the content name. And then we will not have the entire video or audio. What we will have, we will have the ID of that particular content. So, that means we are going to create multiple tables, one for videos and one for audios and one for maybe blogs. They all will have a common ID. With common ID, I mean their primary key and we will use the ID from videos, from audios and from blogs into this particular table. So, we will not have all the data here. Here we will only have content ID maybe. And with this, we can also have content type. So, this type will determine where we need to follow. So, this content table will only contain all the fields which user can search. They can search for name, they can search for type, they can search for maybe some keywords, some slugs. So, all these details will be there in our content field. And the actual data, the actual content will not be in the contents field but in their respective tables. So, all the blogs will contain all the blogs, all the audios will contain all the audio files, all the videos will contain all the video files. So, now if we have one and type as video, we know that one is going to fetch some data from this videos table where the ID is equal to one. So, this is one to one relationship. Where we know that we are using a different entity to our entity and the relation between us is one to one. Whenever we write one here, we are not going to fetch any other data and also we are not going to use the one again in this table. So, this is one-to-one relationship. So, we have understood that in relational DB, we have entities, right? And we join multiple entities through relations. That means every entity will have particular set of properties, and then they will be joined, and we will get the data accordingly. Let's understand the same thing with the example of posts and comments. So, suppose we are building a blog site, and in blog site, we have some post, and then we have some comments. The post table will have some ID, unique identifier, then some content associated with the post. Now, content can be anything, right? It can be images, it can again be text, or sometimes it can be video, also. So, these all are the category of post. Now, we have different type of posts, but we have to somehow pass those IDs and manage three tables for image, text, and videos. We can manage them in the same table, as well, but that will increase our latency, because different kind of formats are curated into a single table. That will increase the size, right? With content, we can also have content type, through which we will basically apply some filters, if we want to. Now, if we talk about it, we already have four tables. One for images, one for videos, one for text, and one for content. Now, we will have comments, as well. So, in order to have comments, we will have some comment ID, and then we will have comment. Now, comment can also be a sub comment of a parent comment. So, that means we can have a parent kind of comment ID, as well. Now, in order to handle comments, we have to handle users, also. Now, in order to handle user, we need one more table. We will have ID, maybe name here. So, our number again got increased to six. Now, in with this PID, we will also have user ID who is commenting on our post. So, in order to maintain a simple post and comment section, we will have to have four to five to six tables, right? And then we have to maintain the relationships as well. So, that means even for a small blog site, we will have to maintain so much data. And when the size of the blogs increase, with that I mean this will get hard to scale. Now, why I'm saying it is hard to scale? First, understand how can we scale any database? We have two options only, right? First is by scaling them vertically, and the second option is by scaling them horizontally. In vertical scaling, what do we do? We add the capacity to a single server. So, that means if we are using 4 GB data, we will add more space into our server to have more data. We can only expand this kind of vertical scaling to a extent. After that, we will have to use horizontal scaling. That means having different servers across different places. So, in this case, we will have to maintain relationships between the different entities in all of these databases. And this will be a tedious task. So, in order to avoid this, we can use NoSQL. So, we can say the first advantage of using NoSQL databases is it is easy to scale both vertically and horizontally. Because we will have to maintain a single document, and we can replicate it on different servers or even split them into different partitions and pass it to different servers. We will understand about that also in a bit. Now, what is the next issue? The next issue is if we are maintaining a table, we can't change the table again and again. We have some fixed columns, right? We have some fixed attributes or columns. We can't add or remove different column types in order to maintain different kind of data. Now, let's say we are going to handle the blog site, but this time we are going for NoSQL database. In this, what we can do now, we can create again and content entity and we can basically use any kind of content which we want. So, we'll create the first object and maybe we'll write something. Let's say user ID is one, then we will write the content. Here, the content is an image, so let me pass some URL. https maybe something something.jpg. Now, when we are adding next content, let's we can add it directly into the same content document. So, what we'll do, we'll again use some user ID. Maybe this time it is two and in form of content, now we have some textual data and we can have some text. Also, if you want to use it in a more refined way, if you want to add some rows, we can use that, right? We can use user ID as three, then maybe heading as anything, let's say Java, and then maybe we can have some description. This is description. And like this, we can have as many fields as we want. So, that means in a single entity content, we can have different fields and also we can have different number of fields in the same document. And if we go about relational database, we can't do that there, right? So, in these kind of scenarios where the document structure is not fixed, this is basically called schema-less, we need to go for NoSQL options because in SQL we don't have this option. So, that comes to our second advantage of using NoSQL, that is we can handle schema-less objects as well. So, now let's discuss about third point. So, in NoSQL up to now we have seen it is easy to scale, then it is schema-less and what makes NoSQL more feasible is when we don't have to handle a lot of linking between different entities. That is we don't have to maintain a lot of relationships between different entities and also every entity in a NoSQL database stands on its own. Think of this as a key-value pairs. Let's say a course ID. ID is the key here and in the course content we can have anything. We can have only name or we can have entire object. Or in third place we can have entire course with lesson. Of course there are going to be nested lessons in a course structure. Again with lessons in fourth place we can have course which will contain some lessons as a nested object and those lessons can also contain some comments. Now all these things are possible in NoSQL which were not there in SQL. If we want to have similar structure in SQL we have to maintain different entities and we have to maintain different relationships between them. Here we don't have that struggle. So that makes our NoSQL work easy. So this is why we use NoSQL over SQL and with time it is gaining popularity. For example in Netflix we use Apache Cassandra in order to maintain user activities. In Amazon they use DynamoDB in order to scale their application. In Facebook or Meta they use HBase in order to maintain user messaging and large-scale storage. In Uber they use MongoDB in order to handle flexible and real-time data. And with that Twitter or X use Redis for caching and timeline purposes. So the conclusion is that NoSQL is also being used in variety of systems nowadays. Let's distinguish it for a bit now. So when we should go for SQL and when we should go for NoSQL. Whenever we are handling payments, we don't have so much variety there. So, payments can be easily managed through SQL. So, with payments, we can also think about transactions or any other feature which needs consistency where the data is not changing, the schema is not changing, and also we need to handle those relationships perfectly. In all those areas where we need consistency, we can easily pick SQL. Now, when do we pick NoSQL? When we are talking about scaling and also we can talk about speed because as in NoSQL, we have a single document to search from whether in SQL, we have different entities or tables who are joined through one or more relationships. So, we have to traverse multiple tables in a SQL database and in NoSQL, we don't have to do that. So, by that nature, the speed of NoSQL database is faster than the speed of SQL one. And also, one of the core reasons to use NoSQL is unstructured data. So, in other words, whenever the consistency is on more priority than availability, we can easily pick SQL. And when availability and scalability is on more priority than strict consistency, we can choose NoSQL. With this, I hope you all get why we use NoSQL databases also with SQL and in what areas will we pick SQL over NoSQL and vice versa. Now that we have understood what NoSQL database is and why do we use that, let's see some examples and application areas of NoSQL database. Now, the thing is in SQL, we have only considered all the databases which will have tables, similar relationships, and in NoSQL, there can be various ways in which we can store data because it is like saying Java and NoJava. In Java, we have Java and in no Java, we can have many applications, right? So, like that, let's start by our first example, which is key-value pair. Now, if you are a developer or developing front-end, back-end, or anything, you must have used cache. We use the format of key and value whenever we are trying to insert some value in cache or maybe cookies or in data storage. We use this kind of data. So, if we talk about key, the only feature which a key should have is that a key should be unique. And for value, we can use any kind of value. We can use basically JSON or a string or maybe a number. Maybe if you want to add blob, we can use that. We can also store it as byte array or any array for that matter. We can also obviously have objects as well and we can also have the combinations of them. Like a list of object can be stored in an array or an object can also have nested objects. And with that, obviously, it will be having some strings, numbers, blob, byte array, or any of that values. Now, the two important points here are we don't have to follow any structure because the NoSQL database follows schema-less structure. So, we don't have to follow any structure. With that, we also don't have to maintain any relationships. Suppose, if you want to add post and comments, we can simply use any key. Let's say post is the key here, post one maybe. And in order to have that object, we can have any ID, post ID, or any content. So, these all things are key basically of this object. Post ID can be a number. Post content can be anything. And with that, we can have comments and we can have array of objects in comments. We can have multiple comments field also. Let's say it can have a comment ID and the actual content of the comment. Like this, it can have multiple objects and this all can be done without any relationships. So, this is a good example of key-value pair, which we normally use in our cache, cookies, or any other places where we don't need to maintain any structure. Now, let's move to the second one, columnar DB. So, the thing is whenever we are having any table, let's say we have student table, which have typical ID, a unique identifier, the name, and then the marks. Maybe total marks of all the students. So, ID is one, name is Akshat, and marks is maybe 90. With that, let's have one more record. The ID is two, name is Gaurav, and the marks maybe is 95. Now, what we have to do is we have to get the average marks of class. So, the students is basically maintaining a class, we are assuming that, and all the marks, if we sum them, we will get the total marks, and if we divide them with the total number of students, we will get the aggregated marks. Now, in order to do that, if we do it in a SQL manner, the SQL manner basically reads the data from left to right. So, even if we don't require any name in our data, we have to still read our table from left to right for each and every row. This is a heavy task, right? Because we don't need those values. Here, we have only three columns. What if we have 17 columns? Then also we have to read all the rows from left to right, and which is not mandatory. So, in order to fix this issue, we have columnar DB. What columnar DB does is it gives us the flexibility to read the data column-wise. So, instead of reading it row-wise, now we can read the data column-wise. That means if you want to deal with only marks, we can read only marks data column-wise. And then we can aggregate all the marks. And if we want some other column, those can be also read by column-wise. And how we can link them? We can link them with the common IDs. So, the common IDs will be there whenever we are reading column-wise, and then it will be easier and faster through our unique identifier that is ID here. Where we are reading the data, but column-wise instead of row-wise. The common examples of columnar DB are Google BigQuery, Amazon Redshift, and Snowflake. So, all in all, if we have to read a lot of data, we can go for columnar DB. So, it is good for analysis. And imagine writing the data into columnar DB, that is going to take again a lot of time because we have to write also column-wise. So, that means we have to first maintain an ID, and then the name will be written, and then the marks will be written, and then the other values if we have them. Those will be also written. So, in order to read the value, it is useful. And when it comes to write, it is going to take more time than a SQL database. The third kind of NoSQL database is graph DB. Imagine, we have all seen those movies where detectives basically pinpoint many photos and join them with some thread or something, right? So, like this only, we have graph DB where we have different nodes, and they are joined by the threads which are called edge. So, every edge basically represent a common relationships between two nodes. Two nodes are basically the entities, and edge signifies the relationship between them. Now, what is different in graph DB is both nodes and edges can have properties. Suppose we are creating any node which is student, maybe, and which contain all the student information. Now, we have another node for course, maybe, and we can name the relationship anything. Maybe it is enrolled. Now, the enrolled can also have properties in it. It can contain year, it can contain marks. It can contain year of passing maybe. And all of these things the edge or the relationship can also have. So, this is what makes our system unique. Graph DBs are often used by data scientists to find patterns between different scenarios. It works basically in the same level which we see in any detective movie as well. So, if you want to work with graph DB, we can learn Gremlin or we can go for SparkQL. Also, we can use Cypher in order to work with graph DB. As I said, it is used in huge companies whenever we are dealing with a huge amount of data in order to face some patterns or basically analyze the customer behavior on our site. So, as we can see the two entities are going to have some properties and also the relationship between them will also have some properties. Also, two entities can have different relationships. And also it can be linked via different entities as well. So, student basically studies in this college. We can write all the parameters of the studies edge also. And college provides the course. So, in this provide relationship also we can have multiple properties. So, which makes our graph DB complex. And also since we are dealing with multiple entities with properties and also multiple relationship with different properties, it is going to be a bit slow. With this, let's move to our final and the most famous NoSQL database which is document DB. So, in document DB we will have some document and in that document we can write JSON and can store data with any length. We don't have to follow any structure, we don't have to follow any schema. So, that is flexible in nature. Also, it is schema-less. So, similarly, document DB also don't have to follow any relationship. At this point, if we think about this, the graph QL is kind of an exception on the borderline there because we do have relationships between them and with relationships, we also have properties of those relationships, which makes it entirely unique and different from no sequel and sequel both. But on a large level, it comes under the category of no sequel only. The common examples of document DB is CouchDB and also MongoDB is widely used. So, that is also an example of our document DB only. Our document DB is highly used in logging the systems because we need flexible log structures. So, it is highly used in logging, logging the error, maybe logging the warn messages, logging any kind of stuff. Also, it can be used to handle profile section because the profile section can also contain different values for different users. Suppose some have given all the values, some have given less values. So, that can be easily maintained through profile. And with that, if we talk about content like content on any application, let's say Instagram, we have different kind of content. We can have image, we can have video, or we can have some text. If we talk about Facebook here. Now, these different kind of posts or content don't have to go to different tables. In document DB, we can basically create a single document and curate all of these content into the same document, obviously with different attributes and values. So, again, as it is a no sequel DB, it is going to be complex and the retrieval of any information will be faster. Easily, any no sequel databases can be used for any kind of analysis. So, this is all about the types of no sequel databases. After understanding about databases, one thing is very sure that each and every important information needs to be stored in databases and will be retrieved from there itself. That means if we have any user here who is trying to access, let's say telesco.com only from their mobile application, the request eventually go to our backend and from backend if we are showing any information, it will be retrieved from the database and will be shown to our user. Now, the thing is for every information we need to hit our database. So, even if we have a homepage which have, let's say, three most popular courses aligned like this. This is our course one, course two, and course three. Maybe the details of each course are visible. One, a thumbnail is visible. Then, with that the name is visible. Maybe the price is also visible. And with price, the discounted price is also visible. Also, let's say we are showing some of the important sections. So, yeah. These are all the details of every course which is visible on our homepage. Now, this maybe is coming from any DNS because that's where we are saving any static files, remember? The name will be stored in a table. Let's say the table name is course or courses. For price, we may have the prices in the courses table itself, but according to area, according to the currency, the price keeps on changing. So, we will create a separate tables for prices. So, the price is coming from price. Then, the discount price also based on the locality. So, these both details are coming from the same place, prices table. And then, the important section. Important section may have some criteria or some course content which we need to show. So, this maybe it is coming from courses section only, but courses section normally have the course main course detail and then accordingly we can have different sections. So this is maybe courses table and we can create some other table which will have all the information for courses. We can name it as course info. So here also the things are coming from course info table. So that means in order to show these three courses we are hitting 1 2 3 and 4 resources, three tables and one DNS. And that means that for every user who is trying to access our site telesco.com, it is going to hit all of these four resources again and again. So if the count increases to 10,000 maybe daily active users that means we are going to hit the database and the DNS 10,000 times for each and every user. Also don't forget that the courses are three. Maybe in future we will increase the number to six. So that means 10,000 requests multiplied by six that is 60,000 requests. In short, for every view we are hitting six courses and from those six courses we are hitting these four sections. So for every user we are hitting 24 requests. This is totally going to break our system because 24 requests means it will add latency to our home page. And in these fast times where nobody wants to wait for any resources, these latency are eventually going to affect our business. Also the more the latency the poor the performance. So this is clearly not a good sign. We can't keep hitting our databases again and again in order to fetch the same information for each user. We need some other mechanism. So this is where cache comes into the picture. Now let's understand what cache is. Cache is nothing but a memory storage, which is away from databases and it can either be in our backend or into our front end in order to load the resources faster. Now, how does it work? Let's take the same example. Our user is trying to access telesco.com and is hitting backend to get the information and backend eventually is hitting database to get the information. Now, once we understand that these six courses are going to be static on our home page, right? So, that means we don't want to fetch this information again and again from our databases. So, what will we do? We will eventually get that particular information and put it onto our backend either or we can also put the same information on our frontend storage as well. So, when the user again comes on telesco.com, we don't have to hit the entire database again and again. We have that information handy on our backend or frontend or in both the areas. So, whenever we hit our home page again, we can get those information directly through our cache, which is stored either on our frontend or on our backend. Here, we are saying that our user is accessing mobile device. Maybe it is accessing our site through any web application. So, there also we can handle cache, okay? These caches, which are on client side, are normally referred as client side cache. And the data, which we stored in backend systems, are referred as server side cache. In databases also, there is some mechanisms where they can also store the information ahead of time, that is known as well. And we can get the most requested information from this data only. We don't need to hit our database tables. Also, we can have cache in DB as well, which is known as database cache. Up to this point, we have understand why do we need cache from a very high level point. Now, let's understand how can we implement the caches in the real system. In order to understand them, first we have to make sure that we know some of the terms. The first term which we need to know is cache hit. Now, what is cache hit? Cache hit basically means let's say we have any request which is coming from our front end to back end. Let's say we have cache installed here and here is our final DB. Now, whenever we are hitting the request and we found the data in the cache, that is known as a cache hit scenario where the data is present in the cache and we don't need to hit our database. But, if the data which we are trying to get is not in cache and we have to hit our database, that is known as cache miss. So, what is cache miss here? Cache miss is again we are trying to access some data from our back end and we don't find the data in our cache. Instead, we have to get to our database to fetch that particular data. So, from where we are getting the data in cache miss? We are getting it from database. And from where we are getting the data in cache hit situation? We are getting it from the cache itself. So, whenever we hit a cache hit kind of situation, our responses will be faster. And similarly, in cache miss, our responses are going to be slower. With this, the next term which we need to know is TTL. TTL basically means time to live. Time to live basically specifies for how long the data is going to be in the cache. In other words, we can also say after how much time our data is going to expire from cache. Up to now, I hope we have understood what cache really is. So, how do we store data in cache? We store the data in cache in normally a key value form. And we get these data by using the keys, obviously, and by value, we also have TTL with them. In order to check whether the time is expired for that particular key-value pair or not. If it is expired, this key-value pair will be eliminated from our cache so that it makes room for having more data. So, at this point, we understand that the cache works faster than our databases. Then, why don't we get all the data from our databases and put it in cache so that every request which we make will be faster. If you understand software development, you understand that I'm asking a silly question. But, if you are new, just hear me out. Now, this is those kind of question where the answer lies in the question itself. We are saying that cache is faster. Now, let's understand why it is faster. Because we are only collecting the information which is frequently used. Okay, so that's why the size of our cache is very smaller than our DB. Because DB have all the information which our site needs. So, that means the size of cache is limited. And we have to keep refreshing the data in cache so that it performs well. Why do we need to refresh? Let's say today we have some campaign of maybe selling our most sellable course, maybe Java we are selling on the let's go. We are saying mastering Java. So, you can master Java. This is our most prominent course today. But, tomorrow we change our focus from Java to maybe AI. Let's say most students are not interested to learn Java at that time. But, are interested to learn AI. At that time, we have to replace the content of Java to AI. So that we can get this information faster. Why it is faster? Because it is easy to find something in a limited space than in the entire database. That is why cache is faster. And the second point is if let's say somehow we managed to create a large size of cache itself and we managed to save our entire database into cache, in that case, every search query or everything which we are trying to find is going to take a longer time into our cache itself. So, it defeats the whole purpose of having a cache. That is to reduce the latency and to get the performance better. So, with this two points are very clear. First is the size of our cache needs to be way smaller than the size of our DB so that we can get the responses very faster. And now that we have size constraint, we need to keep updating the cache data in order to get the values which are relevant to our users. Now, I think we are very sure what cache is, why the size is limited, why do we need to refresh the content again and again. Now, it's time to go a bit deeper. Let's go into the strategies through which we can update the cache data. The first strategy is read through cache. As the name suggests, read through cache strategy is designed to handle the reads from the cache only, not the rights. So, let me create a diagram. Let's say this is our server. Here we have our back end and our cache and with this we have our actual database here. So, read through the query suggests that every time we have a request of getting any information, we are only going to read through cache. We are not going to hit database. We are only going to read the information from cache. And if and only if the data is not present in our cache, then only we will need to hit our database. Again, for right, we are not going to write any value in our cache. We are directly going to write our data into our database. So, in order to read, we are going to hit our cache, and in order to write, we are going to hit our databases. Here, clearly, we can have two cases. The first case is cache hit. In case of cache hit, that means we are trying to get some information, the back end is going to hit our cache, and cache have that value, right? Cache returns that value to our back end system. So, this is good. This means that we are going to have a faster retrieval. Then, we have our case two for cache miss. What happens here is our back end is again going to ask our cache whether they have the information or not. And in this case, as this is cache miss, that means we don't have that information into our cache. So, here, cache itself is going to ask to our database and fetch that particular data. So, database is going to give that information to our cache, and then cache will return the data again to BE. So, clearly, it adds a next level step to get the data from database, which is going to make this request call slower. So, that means whenever we are reading any data, we are not going to go to database directly. Our cache will be connecting to database and getting the value which is required for our back end. And from cache, we are going to give that value again to back end in order to process it. So, here, if you see what we are doing, we are not adding any recently added data directly to our cache. We are adding data directly to our databases, and only the data which is getting retrieved from our users are going to be in our cache. Let's say, from our back end, we are making an order placement, and that data we are not seeing that again. So, that means that data is never going to come to our cache because no one is accessing that. Only the data which user is accessing are going to come to our cache, which makes our cache always ready with the information which user wants. So, this is all about RTC. Let's move to the second strategy, which is WTC. WTC stands for write through cache. As in RTC, the strategy is only for reading, here this strategy is only for writing. So, that means we have again our client application. Here we have our backend and our cache with our database. Now, whenever we are going to write any data, we're going to write it into cache and then eventually from cache, the data is going to be there into our databases. So, this means whenever we are writing any data, we're going to write it into our cache first and from cache, the data is going to be written into databases finally. So, by doing this, our cache data is always going to be updated with the latest value. Where it can be used? It can be used if we talk about stock values, where we always want to see the latest data. And with this, it can be used to any other application where we want to see the latest data first. With this, let's move to the third strategy, which is WAC. WAC basically stands for write around cache. So, up to now, we have only talked about either read or write. With WAC, we're going to talk about read and write both into one strategy. So, read around cache. So, when it comes to write, we are going to write the data from any query from our client, it is going to call our backend services and from backend, we are directly going to write the data into our databases. No cache is in between. So, that means all the writes will be directly dumped into our database. And we haven't updated any cache here. So, this is about write. And with read, what we are doing, whenever we are reading any data, we are going to read it always from cache. If the data is there in our cache, that is a cache hit situation, then we're going to get this information directly. So, this is good. If we get any cache miss kind of situation, where the data is not there in our cache, the cache is going to call database and update the value in the cache first and then will give the value to our backend. So, this is how WAC works. You may think that it is a combination of RTC and WDC, which is correct. So, in RTC and WDC, we are only talking about read and write respectively. But, in WAC, we are talking about the entire flow of data. So, it is heavily used in applications like Twitter. Now, it is called X. So, here the scenario is we have a lot of users who are going to create tweets. But, we can't directly create those tweets and save them in our cache, right? And whenever the users are trying to access any tweet, at this point it is decided to keep this tweet in cache memory because now it can be used by some other users as well. So, we don't decide the importance of any tweet at the time of its creation. We decide the importance at the time of reading those tweets, right? So, with WAC, we also have one more strategy, which is WBC. WBC basically stands for write back cache, which basically means whenever we are trying to write any data, it is going to be written into our cache and at this point our write operation is completed. We are going to write this data into our database, but this is an async process. So, that means while writing our data, we don't care about consistency much, but we care about speed. We want to get the update faster. So, whenever we write any data into our cache, it is going to give us the okay response, maybe. And after that, the data will be dropped into our databases eventually. Now, as this is async process, it is very possible that we may get some or other error here. So, we have to handle this kind of scenario or strategy very carefully. And now, let's talk about read. While reading the data, again, we are going to read the entire data from our cache itself, right? That is the whole point of having a cache. So, as most of our data is directly written into cache, it is most likely to have the most updated values. So, normally, it is going to give cache hit. And if we get cache miss kind of situation, so we are again going to call our database, update our cache, and from cache, we are again going to read the value from our application. So, as you can see the WAC and WBC are pretty common, but here we are using async to write the data. That means we are trading off between speed and consistency. So, even if our data is not consistent, we are making sure that the speed of application remains fast. Now, WBCs are basically used where we have a high write traffic. The most common example of this can be any food delivery application. Let's say Swiggy or Zomato. So, in Zomato or Swiggy kind of application, what normally happens is at a particular time, we may be handling multiple orders with multiple status. And the status keeps on changing. So, instead of saving all the data changes into our database, we choose to save them into cache. Because we know that the status of this particular order will change very fast. So, we use WAL here because we need to update the information fast and also the user who have created the order are also going to see the latest information through this cache only. And in the back process or in the backend or async manner, we are going to keep updating our databases. So, this way it is going to handle million of request and status updates at a particular time. So, up to now we have understood that how do we handle the data into our cache? But, we have only added the data. We haven't deleted the data. So, now let's understand the cache eviction policies through which we are going to remove the data which is not used by our cache. Here I'm writing policies here. We can easily use strategies. I just wanted to sound little different. So, that's why I added policies. Um just for fun, you may say. So, the first policy basically is LRU. LRU basically stands for least recent used. So, as the name suggest, least recent used. That means the data which is not used recently will be evicted from our cache. Suppose Apple launches a new iPhone which is 17 Pro Max updated something something very acronym synonyms of Pro Max Ultra something. And now everyone is keep looking for 17 Pro. No one is in today's time looking for 11. So, that means 11 is a stale data which was used earlier by our cache maybe. But, in today's time we don't need to store that information into our cache because a very few clicks were there who were still searching for 11. Now, with this let's talk about the second policy which is MRU, the exact opposite of LRU. There we were saying least here we will say most recent used. So here we are going to delete the data which is most recently used. This sound a bit strange, right? Why do we delete something which is most recently used? But if you think about it, let's say you are surfing through an e-commerce application and you already apply a particular coupon. So in that case we don't need that particular coupon into our cache, right? So we will directly remove that. Also, if you think about it, we have streaming applications. For example, let's say this YouTube only. So in YouTube's the streaming normally happens in sections. When you are watching any video, let's say you have watched the video till here. At this point this data gets loaded. And you may see a white line moving forward which denotes that the data up to that point is loaded right now. Let's say currently we are at this point and this data is already loaded. Now at this point we don't need the previous video information. This can easily be deleted from our cache at least. Because in this case the chances of me going back into the video is very slow. So that's where we remove the most recently used data. So I hope you are getting all the points. The next part, the next eviction policy is LFU. LFU basically stands for least frequently used. So LFU basically means the data which is not frequently used will be evicted from our cache. What does that mean? Let's say today I opened any e-com application and search for plant. Also, I am a gadget guy. I basically purchase a lot of gadgets. So suppose I have a history of seeing any secondary screen also. With that I also purchase a lot of clothes. So clothes section is also there. Now, between these three, I keep on seeing about the secondary screen and I keep on seeing the clothes in one or the other manner, but the plant search I only did once. Maybe I saw some YouTube video or liked some plant into some Instagram story of others. Only at that time I thought of purchasing a plant and after that I didn't think about it again. So, that means the plant is the least frequently used terms for my history of that e-commerce applications. So, now whenever we are going to evict any data, it is going to be this. So, this is another strategy where we remove the least frequently used data from our cache. After LFU, we have two standard ways of handling cache data or removing the cache data. The first strategy is FIFO. We all know about it. FIFO basically stands for first in, first out. Suppose we have assigned 180 MB to our cache and we don't want to exceed this limit. Now, whenever we are trying to add any value and and if we have reached our limit, first data which we are going to remove is the first data which we entered into the cache without thinking about anything, without thinking about frequency, without thinking about how recently they are being used. We will simply remove the first added data from our cache. And with this we have the last eviction policy which is LIFO. LIFO basically stands for last in, first out. You may think of a stack kind of situation here, right? Where the last object which is inserted will be evicted first. So, this is how LIFO works. So, in this what we will do, again we have 180 MB memory and here we I have written bytes. Here it is bits. Don't worry about that. It doesn't matter. Now, in that 180 MB memory, I don't want to store any other information. So, what information will I remove? I'll remove the most recent information which I added. Okay? So, maybe this information which is added first will be there for the longest time, and we will keep on removing this or this or this information in order to have more space for the added information. So, this is about LIFO and FIFO. I have not added any application areas for LIFO and FIFO both. I want you to explore this a bit and tell me in the comments. And with this, we have understood about caches, their eviction policies, and how do we add the data into our cache. I hope you all get it. Up to now, we have understood how our request basically flows through different components of our system and ultimately provide some information to our user. Right? We have seen who our customer is. They're going to interact with either some web application or maybe some mobile application. From where the request will flow to a server where our back-end code is, and through the server, we will hit some or the other database in order to retrieve that information and provide it back to the user. With this, we have also discussed about DNS through which our clients are going to get the address of our server. And then, the cycle repeats. So, this is all we know up to now. This all looks very good, works very efficiently up to a single point. Why? Because here we are using only single server, and a single server can scale only up to certain limits. Suppose we are already using 128 GB of our server, and somehow our processes are consuming this much resources. That means we are getting more requests than we were expecting. Maybe our app is tracking attraction now from across the globe. And at that time, we have no choice but to scale our system. In order to scale the system, this is the first step which you can think of. So, instead of having a single server, we need to have multiple servers. Let's name them server one and server two. So, we have two servers. That means our client need to give the call to either server one or server two. But, how our client is going to decide where to give information to? This is where we need to discuss one more component which is load balancer. Now, let's make the diagram again with load balancer. Now, what happens? Our client or the user is going to access the same information from any mobile application or website, and they are going to hit DNS in order to get the IP address of server. Up to now, things are not changing. Everything is pretty straightforward. But, now our DNS is not going to give the IP address of the actual server, but it is going to give the IP address of load balancer. And then, the load balancer is connected to multiple servers. Suppose this is server one, this is server two, this is server three. And then, the load balancer basically decides to which server our request should go to, whether it should go to S1, S2, or S3. And if it goes to S1, S2, and S3, they are basically going to connect to a database. Maybe they are connected to same database, or there can be a possibility that S3 is managing the data in some other database, and through migration, replication, or partitioning, we are handling the data between those databases as well. So, this is what the actual picture of a microservice applications looks like. Where the load balancer is going to play a huge role in order to pass those requests from client to server. Now, if we talk about load balancer in brief, our load balancer mainly is going to perform two tasks. The first task is how do it give responses to the perfect server from which it can get the response faster, right? So, the first thing is choosing the server. Also, if we are giving the responsibility of choosing the server to load balancer, that means load balancer should know how our servers are performing in the current situation. So that no server will be overheated and no server will be underutilized. So, the second thing which load balancers are going to do is maintaining the health checks of our server. So that whenever any new request comes to load balancer, they are the one who is going to decide whichever server is working in a fine condition plus can handle that request pretty well. So now, let's discuss these both points one by one. So, in order to choose a server, we need some algorithms, right? So, there are various algorithms and hybrids also from which our load server decides where the request should go. So, let's discuss those algorithms. The first algorithm here is round robin. Round robin is the most simplistic approach in order to pick the web server for the next request. So, in round robin, what do we do? Suppose this is our load balancer and we have our server one here, server two here, and server three here. Load balancer is now going to pick server one for the first request. For second request, it is going to pick server two. For third request, it is going to pick server three. And where will the fourth request go? It will again go to server one. Then five for server two and six for server three. And this is how every request will keep generating and going to the next server which is in the list. So, there is no much calculation needed here. We only need to know that we are following the sequence of S1, S2, and S3. And if the current request is being processed by S2, the next request is going to be on S3. This is how round robin works. So, that means round robin send request one by one, right? Apart from this, it doesn't check anything, which makes the round robin very easy to implement. That means if you are using round robin algorithm, each server are going to handle almost equal number of requests. So, we can say the distribution of requests are equal. And as in this algorithm, we are not managing any state of any server, basically, we'll manage only a single counter from which we are going to decide where the next request is going to be. And also, we need to manage where the current request is. So, with simple implementation, we can easily set up round robin into a load balancer. But, there are some demerits to it. What if server one, server two, server three doesn't have equal configurations? What if the RAM configuration between them is different? What if the storage is different? What if the CPU power is different? Let's say for S1, RAM is 4GB. For S2, it is 8GB. For S3, it is 16GB. Again, the storage, let's say for server one, we are using maybe 100GB storage. For server two, we are using 200GB storage. And for server three, we are using 500GB of storage. Also, the CPU, let's say it is 16 core, it is 32, it is 64 core. So, the configurations are entirely different. And what we are doing in round robin, we are not checking any of these matrixes, but we are simply following the next counter. So, that means even if with uneven configurations, the load on server one, server two, and server three are going to be same. And this is unfair because the server three may do all the task very frequently and can sit idle. Whereas server one will struggle to complete the task and it will be overloaded, maybe heat up, maybe stop working. So, this is the demerits of using round robin. Now, let's jump to the second algorithm, which is geo-based, which basically states that suppose this is our load balancer and we have our server one again and server two again. This is in India and this is in US. So, if the majority of users are from India and some users are from US, that means they need to hit their respective servers in order to process the information. That way, they will get the response faster because if I'm sitting in India and I'm requesting any information from the Indian server, it will be faster to process those information in the Indian server as well with respect to processing the same information through US servers because the connections are going to take time and which will increase the latency of the application, which the user doesn't want, right? So, this is what our second algorithm implies. It is based on geo addresses of the particular user. So, here also we are not maintaining any matrices for server specifications. We are only maintaining two matrices. The number one matrix is where the server is and the second matrix is from where are we getting the request or we can say where the user is. Now, this algorithm is used by many applications across the world whichever have the global appearance. Whenever we are trying to hit google.com or facebook.com or any other global applications, our request basically moves to the server whichever is closest to us. Maybe we are residing in this area. Here we have some server and also here we have some server. Maybe this is US server, this is Indian server. So, our server needs to be situated near us so that we get the response faster and all the requests are maintained through the same server. So, whenever I'm trying to access any information, they are going to be addressed through the same server. So, that means our session and other informations are also will be in sync for this particular user. In this algorithm, there are some disadvantages as well, right? Because now our load server needs to manage more information. Now, it needs to know from where the requests are coming and it needs to know where each and every server is located. So, this is a lot of information to be seen by load balancer. And now as our servers are distributed across the globe, we also need to maintain databases accordingly. So, every region may have their own databases for faster retrieval. So, that will include the computation power of replication and partitioning, which we will be covering in further series. Also, let's say if we are using Indian server or this server particularly, maybe there are two servers in India. This is India B server, this is India A server. For some reason, this server breaks down. Then we need to reroute our request to this particular server, which is again needs all the information which we are accessing through this server. That means the data or the application on which we are working on should transfer the data immediately to this server as well. Even if the server A doesn't crash, then we need all the information which is being tracked by server A. But this is a necessity in geo-based location algorithm. Now, the third point here is if any user is using VPN or other proxy servers to change their location, that means VPN or proxies can mislead the traffic. With this, let's move to our next algorithm, which is least connection algorithm. So, in this, what happens is we have our load balancer in place. And suppose we have two servers, server one and server two. And server one and server two at current times are managing multiple requests, right? Suppose S1 is maintaining 30 requests or 30 connections at this particular time and S2 is maintaining 50 connections. Now, whenever we get a new request, it is going to be addressed by S1. Why? Because S1 currently is having least connections. So, this is how our least connection algorithm works. Whichever server have the least connections, our next request is going to that particular server. In this algorithm also, we are not considering any of the matrices of server. We are also not maintaining any of the requests or response time. We are only maintaining the number of connections. Let's say if these 30 requests are heavy request and these 50 are lightweight, then also the next request is going to be taken care by S1, which is wrong and it is going to take time, but this is how our least connections work. Then why do we use this? Basically, the least connection algos works very well when there are sticky sessions. Now, what is sticky session? Where we have to maintain a proper channel for a particular communication. Let's say we are using web sockets for maintaining any kind of application. Let's say we are maintaining a chat application or a video streaming application or maybe we are handling some gaming kind of setup. In all of these cases, we needs the request and response to be faster, so we will pass our request to those servers who are having least connections currently so that we can get the response faster. Now, if we talk to disadvantages, the first disadvantage is this only heavy and lightweight. Maybe these calls are for AI calls which are going to take time and these calls are basically chat calls or maybe some web CTR calls or maybe some REST API calls which are lightweighted normally. So, they are working faster then also we will send the next request to 30 until the number of connections drops from 50 to maybe 29. Then only we will consider S2. So, this is how we are going to work. Now, if we talk about disadvantages of least connections, the first we already discussed. The second disadvantage is that our load balancer basically needs to maintain the number of connections for each web server. So, if S1 is maintaining 50 connections at that time and it give response to one of them, that means currently it is maintaining 49 connections. It needs to be updated to load balancer. So, our node balancer will keep updating the number of connections again and again which is of course a tedious task. The third disadvantage is we are only considering least number of connections. What if our server one is of very low configuration than server two and it is maintaining eight connections at that time or request at that time and this is maintaining 16. It is easy for S2 to maintain 16 connections or maybe 100 connections and it is hard to maintain 10 connections for S1. Then also we will send the next request to S1 because we are not checking anything apart from number of connections. So, this is how our least connection algorithm is going to work. After least connections come least time. So, it is our fourth algorithm least time algo. Suppose load balancer is maintaining two web servers S1 and S2. The response time of S1 is nearly about 50 ms. The average response time, basically. It is handling some thousand requests, and for server two, it is currently 10 ms. So, in this scenario, the next request is going to be handled by server two. Because the average response time of server two is lesser than the average response time of server one. Now, if we talk about response time, if any server is having less response time, that means the configurations of those servers are high. Right? That's why the response time is low. So, this algorithm basically takes care of the actual matrices of the server by taking the response time into measure. Now, the least time algorithm is used in those applications where we can't handle more latency. That can be our real-time applications, like the trading app or even our search engines. In both of these areas, we want the responses to be very fast, and that's why we use least time algorithms there. And now, if we talk about least time algo's disadvantage, that is our load balancer needs to calculate the average response time. So, with each request they are sending to server, also the average response time will be calculated. And based on this, our load balancer needs to manage where the next request is going to be. So, calculating these things can be really complex because if we are calculating average time, that means we need to know number of maybe requests, and also the response time of each and every response. Then only our load balancer is going to calculate the average response time. So, this is for sure complex. Now, in this scenario, if our web servers maintain any kind of spike, it is going to affect the calculations of our load balancer. So, we need to be very careful there. Now, let's talk about the fifth algorithm, which is IP hash. Here, as the name suggests, the IP of every request is going to be processed by our load balancer and will be given a unique number. And according to those numbers, our servers are going to decide. Let's say our server one is maintaining the hash values from one to 10. So, that means all the IPs which results between this range are going to be addressed by S1 and maybe from 11 to 20 are addressed by S2. So, this is how IP hash algorithm works. Every request is associated with some of the other IP. They are going to process through a hash function, and suppose the result is five, then it is going to be addressed by S1 because S1 is maintaining one to 10. As we all know, the IP of any user normally doesn't change. That means this user for at least one session is going to be addressed through the same server. And it will help. Basically, if we are maintaining any session data, it is going to help because we don't need to replicate this data to other servers. We are only handling these requests through the same server. So, it is very easy. Now, if the connection breaks in between the session, then we are in problem. In that case, this next request will go to S2, and we need all the session data here. And if that data is not maintained, our user may need to address or add the same data again into server two, which is a loss case, which is not recommended at all. So, for this to work efficiently, our server basically needs to be healthy enough to maintain a proper session. Plus, even if the session breaks due to any reason, due to any server crash, it is very important to replicate those data to other server as well. The major disadvantage of this is, as we are basically focused on IP functions and hash functions, so scaling is challenging here. Let's say we are adding S3 here, then we again needs to reconfigure our hash function. So, that it consider S3 as well. And also, we need to reassign these values also. Maybe next time it is only handling 1 to 8, and maybe it is handling uh 9 to 12 maybe, and this one is handling 12 to 20. So, whenever any server is down or we are adding any new server, basically the function will get affected and it will reassign all the values to the entire server. This is hard to scale in this manner. And that's why it is not recommended for most of the microservices architecture we have today. It is basically used where the data was used in the old kind of applications where the applications were monolithic and mostly were legacy apps. Like in today's scenario, if you want to maintain a session of a particular user, we don't only stick for that particular session. We use many other tools like JWT token we use, right? So, this is how we are going to maintain an entire connection through a server and a client. We don't only rely on giving the request to the same server again and again. Even if the server changes, it is going to recognize us through our JWT token. And this is going to work excellently with our distributed systems, microservices, and also if we use Redis. In all these scenarios, we now don't need IP hash functions. We don't need our request to be handled through same server. Even if the server changes, our request or our session should be consistent. Also, there is another algorithm which is extension of round robin, which is called weighted round robin. So, in which the round robin, as it was discussed, is working same, but we added weight. So, that means let's say this is S1, this is S2, and this is S3. Let's say the RAM capacity of S1 is 8 GB, for S2 it is 16, and for S3 it is 32 GB. Now, what we are doing, we are adding a weight to our request. So, more the configuration, more is going to be the weight. So, if our load balancer basically keeps track of this, so it knows that the S3 may have weight three, S2 may have weight two, and S1 may have weight one. So, whenever a new request arrives at load balancer, it is going to be addressed by the one which have the most weight. So, here the weight of S3 is maximum, so it is going to be addressed by our S3 server. And then, based on the weight and round robin fashion, our request are going to be answered. So, with weighted round robin algorithm also added in the list, we have now covered all the algorithms, major algorithms basically, which we needs to know when we talk about load balancers. Also, in real base, no one algorithm basically works. We always work with hybrid approach. And load balancer basically balances multiple algorithms. It is very possible that we are using maybe IP hash with the combination of round robin. And also, other combinations are also possible. Maybe we are combining two, maybe we are combining all six at the same time. Like here, we were talking about least time algorithm and least connection algorithm. We can combine these two algorithms in order to get a better algorithm. So, in order to fulfill our requirement, we normally don't rely on a single algorithm, we rely on multiple hybrid algorithms. So, after discussing all the algorithms, we know now how the load balancer basically chooses a server for the next request. The second thing which load balancer does is doing the health checks. Let's understand how load balancer basically manages the health checks. Here the thing is we have two approaches how a load balancer can check the health checks of entire servers. Let's say we have a load balancer here again and we have server one and server two. The first way how we can check any performance is by simply seeing how server one and server two are performing. We are not adding any new request in server one or server two. We are just observing how they are responding to the actual requests. This is the passive way of checking the health. By this, we don't add any new request to the servers. We don't basically increase the load of any server, but we simply observe. By we, I mean load balancer. The load balancer simply observe how the server one is responding to request and maintain that track. And let's say at a particular point, if server one breaks or stops responding, at that time the load balancer knows about this by again tracking the actual request. It doesn't add any new request to server one. So, this is what the passive way is. Now, there is another way which is active way. In active way, what a load balancer does is it adds additional request to our servers. And based on the responses on those requests, it checks the actual health of the server. So, these are the two ways of checking the health of servers. One by simply observing the request and second by actively adding the request to the servers. It is very important to check the health of every server. Why? Because it gives us the pattern to take decisions. Like when to scale or when to scale down. Both of these cases are very usual by working on any application on a day-to-day basis. Let's suppose if we are maintaining our application only for India region, in that case also we know that in day time the requests are going to be heavy. Maybe in evening time it will be heavier. And in night time it is going to be little or lesser in count. So, at that time we can maybe scale down our server in the night time in order to save some cost. So, let's see what are the other parameters of health checks. The first parameter of health check is interval. This means how often do we check our server? For example, it can be maybe 5 seconds. So, if the case is active, every 5 seconds I'll monitor all the requests I've sent to the server and see how the performance is going. And also, in the passive case we'll see the responses and calculate the matrices every 5 seconds. The second params can be time out. So, time out basically means for how long do we wait to get the response? Suppose there is any server who normally takes from maybe 50 milliseconds to the maximum of maybe 5 seconds in order to process any request from a long time. And now suddenly it is taking 10 seconds. So, this should be an alarming case and we should immediately check what went wrong. Okay, with that particular web server. What is that particular request which is taking 10 seconds? Is there any issue with the code? Is there any issue with the request? Does Do we change any configuration? Or does our server is managing some other task because of which our this request is being affected? We need to know the answers of all of these questions in order to make a better decision. We also need to know about the threshold. Threshold can be like healthy and unhealthy both, right? In unhealthy, we basically take care of the failed calls. So, we will basically maybe set an alarm after 20 failed calls. Okay? We can configure them based on a particular region, based on a particular area of our code, maybe a route, particular subdomain of a route, or maybe randomly. At a particular time, if 20 calls fail, that is an alarming situation for us. In normal scenario, many application may give a faulty response based on various factors. It happens on a day-to-day basis, but after that n threshold, after that count of threshold, we should start investigating the cause. And similarly, we have our healthy threshold, where we should put our marker maybe after every some calls. So, maybe after every 100 calls, 100 positive calls, we need to check is everything fine with those calls. The response was expected, and the system is working the way it should work. So, these are the three health parameters of our web servers which our load balancer needs to check end over time in order to make sure that our web servers are working fine. And with this, we now understand the two major factors of load balancer, how it gives request to the other server, and plus, how do it check the health of every server. Now that we have understood load balancer, it is very important to know that in terms of scaling, we also need to scale our databases, right? So, in databases, what normally happens is, suppose we have 100 GB of data, and we have a storage of maybe 200 GB. This is still fine, right? Maybe we have 1 TB of data, maybe 100 TB of data, it doesn't matter. The thing which matter is this data will eventually get full. And there will come a stage where you can't expand your databases vertically. You have to add more databases into our system whenever it comes to scaling. Also, now that we know about load balancers, we know that our server can be placed into different regions of our world, right? This can be placed into US region, this can be placed into India region only. And what we were doing is we were adding both of these data into single database. This is effective if the user count is one, the request we are getting are minimal. But if the user increases, the traffic increases, the data increases, it will be hard to cater both of these servers from the single database. This is where we need to segregate this data into multiple databases. One may be catering Indian server and the other might be catering the US server. Now, this way we segregated our data into two databases so that the requests can be faster and also with that the data will be segregated in such a manner that it will be easy to maintain. Now, this can be one of the case where we don't need to have same data into two databases. In this case, what we are doing, we are assuming that the data in this data table will be different from the data into this database. Normally, this is not the case, right? Normally, what can happen is suppose we have multiple servers for Indian region only. So, this is also Indian region, this is also Indian region. And we can have multiple databases to cater the same server. Why? Because if we have a single database and if that fails, we don't have anywhere to go and recover the data from. That's why we manage multiple databases in order to recover the data, maybe maintain the data, and also it increase the efficiency of our system by reducing the latency. And also we may have some portion of data here and some portion of data here. Both of these things are possible. These things are basically replication and partitioning. In replication, what we do, we basically copy the data from one database to other database so that even if anything happens to database one, we are able to retrieve the data from database two. Also, if database one is handling so much calls, we can redirect those requests to database two as well. And in partitioning, what we do is we basically divide the data into single database and put one part here into other database and the other part anywhere else. So that if they are getting different requests, it will be easier to cater each and every request with their specific database. We are going to cover both of these topics, but for now let's talk about replication. So we have understood that replication basically means keeping the copy of data. And why are we doing this? Why are we making copies? The first point is we are avoiding or improving our single point of failure issue. We don't want our database to fail and our system to collapse. We want some other database at that time so that our system will be working. The other reason of this is availability. By having data into multiple databases, our availability as a system can increase. We can have different data centers and it will increase our performance. Also, as we discussed, if we talk about different localities or different regions of area, we are increasing the performance by adding particular database into that site. So that will keep the data close to our server and will be retrieved faster. And also with all this, we are eventually increasing our read throughput. So suppose with a single database, we were catering maybe 10,000 requests per second. Now with two databases of same storage and data, we can cater two times of the previous one. So this is how the three throughput will also increase. So after understanding what replication is and why do we use it, let's talk about how can we achieve replication. So we are going to talk about three algorithms. The first algorithm is single leader replication. That means there will be a database which will be our leader and from the leader only we will replicate the data to other follower nodes or follower data centers. Suppose there is any user who is maybe updating their profile picture. And when they are updating their profile picture, the request from our client basically moves to a server and from server we are only sending that request to our leader only. We don't directly communicate to our followers because it is the leader who is going to then replicate our data to followers. So every request will go to our leader. To be specific, every write request will go to our leader and then the data will be replicated to our followers. This is how a single leader approach works. Let's understand this through an another diagram. This is our user. Maybe this is our leader and we have our F1 follower database and follower two. Assume this as a timeline, okay? Now what we are going to do, suppose at this point the user is requesting to update the profile picture. And this request will eventually go to our leader node and once the request is taken care by leader, they will send the same request to our follower nodes as well. Follower node one, maybe it is taking longer time because it is far. So at this point the request went to follower one and follower two. At this point two things can happen. First thing is if the calls from leader node to follower node are async, in that case leader will do its work and update the user that the task is done. And in the back processes, the follower nodes can continue updating the profile picture and will eventually update our leader that the task is done. This type of request where leader updates the user directly after updating the data without getting the acknowledgement from these follower nodes is called async operation. Async basically means once the request is catered by a leader, it will directly update our user. And in the back end, it will also share the same request for follower one and follower two node to perform the same task and update our leader in the back end. In this case, even if our F1 fails to update, F2 fails to update, or anything went wrong with these other nodes, the leader have already given the confirmation to our user. So, the task is done. And eventually, when the nodes are recovered, these operations will be performed again on F1 and F2 to keep the sync alive. After async, let's also talk about sync approach, where the user updates the profile picture. The request basically carried by our leader, and it sends the update request to our follower nodes as well, F1 and F2. And the leader in this case will not give any confirmation until it get the okay response from both of our followers. So, this gives okay, and again, this gives okay. Once it get confirmation from both of these follower nodes, then only our database is going to update our server, and eventually, our user that the task is done. So, this kind of approach is called sync approach, where the leader will provide the same operations to be performed by F1 and F2. It will wait for the responses, and once the response is taken, then only it will update the user. So, this is going to take a lot of time, because our databases can be placed into multiple places. There can be two follower nodes, as we have mentioned here, or more. So, in that case, our time will increase, and eventually, it will update the user after getting the confirmation from each and every follower. Now, let's talk about advantages and disadvantages of both of these approaches. If we talk about synchronized approach, sync approach, the advantage is all of the followers will always have the updated values. The other advantage of sync can be, even if our leader fails, it will be easier to select another leader, because every node we know have the current updated data. So, it will be easy to migrate our leader to any of the follower nodes, maybe follower one, maybe follower two. The disadvantages will be it is going to take a longer time and also after getting any request, our leader is waiting for the responses from other follower nodes. It is going to block that particular resource and other operations on that particular resource is also be blocked because of our asset principles, right? And because of these two disadvantages, we can say that the sync operation here while replication is an imprac- tical approach. Any leader can't wait for all the followers to update them first and then they will update the user. So, we always prefer async approach here. In async approach, as we can see clearly, no resources are blocked, right? And the responses will also be faster. And if we talk about disadvantages, we are basically trading off our consistency. That means our data will be mismatched. Suppose if a user is updating any data to leader node and leader provides the response to user, our user will assume that the task is done. So, even if they read from any other follower nodes, the data should be reflected. And in the async approach, it is very possible that if user is trying to access the data and it get connected to any follower nodes, it will see the stale data, which is eventually going to update by our leader, but currently they are seeing the stale data. So, this is the issue in our async approach. Now, before moving to the other algorithms, let's first talk about how can we add a new follower? So, let's say we already have a system where we have a leader and we have maybe follower one and follower two already in our system. Now, we need to add our follower three. How can we add it? Now, in order to add a new node into our system, we need to perform some operations. Our follower three will also need to have all the data which our leader have. So, for that, what we do, we create snapshot of the data from leader or maybe we can create it from follower as well. But, we need to make sure that if we are picking follower two in order to do the replication, we will again need to use F2 only to update the data. Let's say the current time is 12:55 p.m. and we are taking the snapshot of F1 or F2 at this point. So, that means whatever the state of our F2 is at this 12:55 p.m., we are only capturing the current state of that particular database and we are that dumping it into new node, which is F3. Now, this process is going to take time for sure. So, this is our snapshot one, which is at 2:55. So, this will contain the entire state of our F2 node. Now, what will happen again is suppose the replication process took 2 hours or 3 hours, maybe, because the data is huge and everything. Now, we need to know what changes did the F2 went through in this 2 and 3 hours. So, in that case, what we will do, we will again take the snapshot, but this time we don't have to capture the entire state. We only need to capture the difference between the snapshot and the current time. So, we will create another snapshot, which will include the changes from 12:55 to current time. And finally, we are going to dump this data also in F3. Once we get to know that the F3 is completely in sync with F2 and F2 is already in sync with leader, we will make the connections of leader to our F3 also. And with this, we will have a new follower node into our system with all the updated data. After this, what happens if the leader only fails? Let's say we are having this topology again, leader, F1, and F2. Again, we have some databases linking. The replication process is working fine, then suddenly our leader fails. In this case, we need to elect a new leader. Now, how will we elect? Basically, we will take care of two factors. The first factor is which of these F1 and F2 have the latest information. So, we can take care of that by seeing the timestamp of the latest update. So, whichever we will see, we will pick from F1 and F2, and we will see which one is updated recently. And the second step is we need to update F1 to become a leader, and our F2 to see F1 as a leader now. So, this is the process of electing a new leader when the leader goes down. With this, you may have also heard these terms like FS image or maybe added logs. These things are highly used in the replication process. FS image basically con- tains the full metadata snapshot, and added logs is used to update the current changes. So, these both are also used while doing the replication. And while choosing the new leader or adding a new follower, these two things are also helpful. Now that we understand how to add new leader, how to add new follower, how to take care of things, let's move to our second algorithm, which is multi-leader algorithm. So, as the name suggests, it is having multiple leaders instead of one. So, that means there is a possibility that every data center, be it DS1 and DS2, will have their bunch of leaders and followers. So, maybe for DS1, we have this leader, and we have follower like F1 here. Also, here we have another leader and follower. So, for DS2, the leader is L2, and for DS1, the leader is L. Now, what is going to happen? Let's say the user is maintaining their records through DS1. So, every record which DS1 handles will eventually first go to their leader, and then the leader will update their nodes. With this, now leader also needs to update the other leader into other data centers. And then this leader is going to update these nodes. This is how the process flows. And similarly, if any request is being made to this data center two, our leader two is going to update their followers, and also will send some query to other leader to update the leader as well as their followers. So, this is how a multi-leader replication works, where the leader will not communicate to each and every nodes, but it will communicate to leader nodes, and maybe their follower nodes. So, this is going to increase our performance. Also, we have multiple leaders, that means even if a leader node breaks, we can use the other leaders to update the other nodes. So, we have more tolerance to threats. Now, since we have two leaders, we can also perform collaborative operations, like they can be working on the same file. Now, we can work on the same Google file, same Google sheet, those kind of operation also we can perform, because one request will not block that resource, and the two requests can eventually work simultaneously. Now, when we are saying that both of these resources are going to perform actions on a similar table or single data, that is going to increase our chances of conflicts. Let me explain it through another diagram. Let's say this is user one, this is leader one. Here we have leader two, and then we have another user. Let me create the timelines again. Let's say, user one and user two both working on the same file, which is named as A. Now, user one wants to rename that file to B, and user two want to rename that file to maybe C. Now, these both will eventually hit their request to their particular leaders. And based on the async approaches we have seen, our leaders can eventually give the okay response to our users, right? That okay, it is renamed. And here also, it can give the response that okay, it is renamed. So, these two users will see two different data. This is not possible, right? And also, our leader is going to communicate with each other. So, this will send the request to update the data with C. And also, this leader will also send the same request to update it to B. Now, this is the conflict, and how do we resolve it? Basically, there are three ways of resolving it. The first way of resolving is the last right win. So, that is this right is performed, let's say, at this point, and this right is performed at this point. So, as this operation is performed later, so that means our L2 needs to update our file to C. So, eventually, the file name will be C. This is our first approach. The second approach here is while working with different leaders, we assign some IDs to each and every leader. Suppose, leader one have ID 10, and leader two have ID 11. Now, based on the ID, we can decide which leader is more powerful, and which leader we have to follow. Ultimately, if leader two is of higher ID, that means we have to follow leader two. And now, it doesn't matter if the last right was performed by L1 or L2. It is going to update it with the value of L2 only. So, here, instead of the last right, we are going to focus on the ID. So, we can say replica with higher ID wins. Replica is nothing but a replication. Like, every node which have the replica of content can be called replica. So, we can write leader also here. Okay, no issues. The third approach basically is the approach which we also see sometimes on Git when we try to solve merge requests. So, the same approach is used by the replication process as well. So, whenever there are conflicting situations, our leaders or any other nodes are not going to solve it. In this case, we will prompt our user directly that the file name has been changed to C and the last change which you have made was B. So, do you want to keep the current changes or do you want to update it to C? It is up to user. So, in this case, we need to add the application logic to basically pass our conflict to the users and eventually user will update it. After this, the third algorithm is leaderless replication. So, in this replication, we don't assign a specific leader to any data center or to any other node. We don't have any kind of leader in this leaderless replication. As the name suggests correctly, so here, what do we do? Here, let's say we have any client there. So, he is our user and now we have some databases. Let's say this is our node one, this is our node two, this is our node three. So, these are the three databases onto which our data needs to be replicated. So, this time whenever our user request for any update, let's say again this user is updating the profile picture, but this time the request basically goes to all of the nodes and eventually all will update the data and provides a response to the user. Here, the thing is in other applications where we had a leader, we can basically rely on that leader replica and based on the response which we get from leader, we can eventually decide that whether the operation is performed correctly or not. But here, we don't have any leader. So, what can we do? Do we wait for all the replicas to answer us and at this point we update our user or there is some other method? Let's talk about that in a bit, but before that, let's jot down some points. So, the first point here is we don't have any leader here. So, here we are bound to send our queries to more than one replicas, right? More than one nodes. So, every query, when I say every query, I mean both read as well as write queries, will go to multiple nodes and then collaboratively we'll get the response. When I say read also, that means let's say in this database only, if there is some other user who is also trying to access some values, and while accessing some values, the user can use this replica at this point or this replica at this point or this replica at this point. In all of these three scenarios, the user is going to get different values. So, here the user will get updated profile, and from here they will get the stale data. So, based on multiple entries, we have to decide whether to give this user updated data or the stale data. So, this is our struggle with this kind of replication. But, apart from the struggles which we see here, most of the applications in databases use this setup. It is used by various applications like Amazon Dynamo, Riak, Cassandra, VM. All of these use leaderless application. So, now the only issue is should we wait for each and every node to give us confirmation so that we can proceed to tell any user any response or is there any other way? So, as you may have guessed, definitely we can't wait for this long. There is a way. That way is basically termed as quorum. So, in quorum, what do we do? Suppose we have total number of nodes as three. We denote them by N, and for reading, we have to use more than half of the total nodes. So, it should be more than N by 2. Again, for writing, we should get the confirmation from more than the half nodes. This way we maintain the quorum and we will get the responses which we want for. So, in the same example, if I redraw it, suppose the user is again going to update any information, so updating profile picture again maybe, and the request went like this for first node, for second node maybe the network is faster here, and for the third node. Now, this is the time each node took in order to perform the operation. So, here we don't have to wait for this response because we already got the responses from more than the half of the nodes. So, we can easily say that profile picture is updated. So, here we can confirm that the operation of updating profile picture is done. Again, if a new user appears here, and the user is trying to access the value, so it can basically sends a read operation from these all nodes. Maybe at this point, maybe at this point. Suppose this point gives a result here, then this point also gives a result here. So, in these two responses, the user is getting different values because this is giving them stale data, and this is giving them updated data because the update is already done here, right? So, in this case, there are various other mechanisms also. You can go for timestamp, or they can go for any other mechanisms. But, let's say they don't go for any other mechanism. There is one more mechanism here where that is if the requests are equal, and we are still getting the different data, we will consider the third request and response, and then again calculate the results. So, here we are getting updated from two of the nodes, and we are getting stale value from one of them. So, we will move ahead with the updated value, and this user will get the updated profile picture. So, there can be various ways of solving this conflicts, but the thing is ultimately the user don't have to wait for each and every response. This is a special case where half of the nodes are saying that things are done, and half are saying things are not done. We don't have three servers also. We have more than 10 or 12 servers in a large system. So, this case becomes a rare case. So, yeah, this is all about the replication which we needs to know at this point. So, after replication, the other way of segregating our data into multiple nodes in order to scale them properly is partition. Now, before moving to partition, first see what can be the issue with replication. Replication basically suggests that we will copy entire data to other node. What if the data is so huge that we can't have them in one node? With this, the second concern is what if the data is so huge that even with secondary indexes, our time of searching any element is getting worse and worse. So, with these two concerns, we can't really have all of the data in one database and same data in other database. What can we do then? We can easily or through some logic break the system. We will do the partitioning of data and maybe place some amount of data here and other amount of data in some other node. And then, we can replicate this partition data. Why? Because this data is comparatively smaller and it will be easier to manage. Let's say, in a particular node, we are only saying that we will store up to 10,000 records. And then, once we hit this point, we will again create a new partition and will add the new records there. Or maybe divide these records into 5,000. So, these all things can be done only when we have a new way of partitioning the data. So, this is what partition really is. While partitioning the data, there is only a single rule. That is, if we are doing the partitions like this, then if we combine them, it should give us the entire data set. This is the only condition which is required for partition. And And makes sense, too. We don't want to lose any data, right? So, this is our first condition and the second condition is that let's say we have again two partitions. Now, we want our data to be equally distributed among them. We don't want any nodes to get let's say consumed by 90% of data and here we only have 10% of data because this basically beats the reasoning of partitioning. We are doing partitioning so that every node will be able to access some data and will be able to work frequently. So, basically we are saying that the data should be evenly distributed. So, these are the two major conditions of partitioning. Apart from this, everything works fine. So, the first condition makes sense. It will take care of itself and in order to fulfill second condition, we have to basically maintain some system where we will protect the database to get overloaded or to get underutilized like this. So, now let's talk about those solutions. So, the first thing here is we will partition using key. Let's say we have some table, maybe user table. We are handling these entities and then we have some ID here, user one or user two and the series goes like this. So, what we will do? We will basically in the partitioning based on the keys will insert the values. Let's say this user entity can hold up to 10,000 or maybe 100,000 values. So, what we will do? We will divide these 100,000 to 50,000 here and 50,000 here. So, that means from user one to user 50,000, these data will go to the node one or we can say partition one and the users from user ID maybe 50,000 one to user ID 100,000 will go into partition two. So, this is how we will segregate our data so that it will be easier to retrieve the data afterwards as well. This may looks fair on the surface value, but it is quite messy. What if these users are from different regions? What if half of them from 1 to 50,000 are from India and half of them are from US? Maybe here also they are distributed like this only. So, half of them are from India and half of them are from US. So, in that case, both of these nodes will be busy. This is a good scenario because both of the nodes will be used and will be busy in order to provide the information. And also it is possible that the node one is only taking care of India request and the US request are being taken care by partition two or node two. So, in this case what happens? Let's say the application is very popular in US, but is not that popular in India. So, maybe P1 is getting maybe 100 requests per second and on the other hand our partition two is getting maybe 10,000 requests per second. Now, earlier this was looking good on the surface level, but now this is messy because one partition here is clearly becoming the hotspot. Now, what is hotspot? A hotspot is that partition which is getting more requests compared to other ones. So, it is our duty to maintain this hotspot as well. We don't want any node to become hotspot because eventually a hotspot can leads to the node failure. And if that node fails, we have to basically distribute the data into multiple nodes then and then do the configuration again or maybe change this node or maybe transfer this data to other node. All the things we have to manage, but that thing is surely not recommended. So, we avoid any node from becoming a hotspot. I hope this is making sense to you. So, one way of handling the hotspot is let's say for every request, we also attach timestamp and if most of these requests are going to node one and very less are going to node two, that means the data distribution which we did is not good. So, we have to rearrange our data with some other methods. So, let's see what the other points are. The second approach here can be partitioning the data with hash value of key. What we will do here is, let's say we have user one, user two, maybe user three as the ID or unique identifier of the data. And now we have to put that data into different partitions. We will not here choose ID, but we will use any hash function to basically transfer the ID to a unique number. Maybe this is one, this is two. And user three belongs to maybe one again because of the hash function which we are using. So, based on this, one and one will go to partition one and two will go here. Or maybe we are catering some range here, so maybe one to 10 can go into one direction and 10 to 15 can go into other direction. So, this is also one way of doing the partition. The challenge here is still same. If the request bombarded at P1, we don't have any other way, but we have to rearrange like we discussed in the previous example. So, based on our discussion so far, the hotspot is becoming a real issue. Before solving it for partitions, let's first see how do we solve this issue in a local DB. Let's say we have a table for products. And in products, we have various attributes. Let's say we have some name and color or maybe price. We can have more filter values, right? And like this, we can have as many attributes as we want. So, name, color, price, material. All these attributes basically are used in order to filter these products. Name can be used in query parameters. Other than that, color, price, and range can be used in filter easily. So, what we will do in normal scenario? We will create indexes based on material, based on color, maybe based on price as well. I'm not sure about it because price normally goes into a range, but we can easily make a secondary index out of this and by that, whenever any user basically tries to search that particular product with material, maybe material is wood. So, what will happen? We will not go to our table or this huge table directly. Where we will redirect this query to, it is going to redirect it to our second query, which is maintained for material. And if that data or that value is here, we will then redirect those records particularly to our display. So, this is how we manage the queries to find out if we have the data or not, and if we have the data, where is that data particularly. This is how we solve it in local DB or a single instance. Now, we are going to use the same way into partitioning as well. So, what we are going to do? We are going to do the partitioning by the secondary index. What do we mean by this is, we are going to maintain secondary indexes in each partition. So, that means all the secondary indexes will be present in each partition respectively. This way is also used by Cassandra and also by Elastic Search. What we are going to do here is, let's say this is our partition one, which have some data. Maybe this partition have car data from ID, let's say 200 to 400. And we have partition two, where also we have some car data from ID, let's say 500 to 700. Here, we are maintaining some secondary indexes. Maybe we are maintaining color as a secondary index. And for color, we know that the blue color is for car maybe with ID 209 and 305. Similarly, for red, we can say the ID is 350 or 359, anything, right? For P2 also, we are maintaining it like this only. Again, for color, we know that the blue color cars are maybe ID 509 and 609 and red cars are 610 690. So, these are the indexing which is done in both of these partitions. So, whenever a query comes for a blue car, we don't have to scan to all the records, but we can directly see the blue car here belongs to 209 and 305. And here, we have blue car for 509 and 609 only. Let's say a new request come for silver car. So, we don't have to basically indulge into all the records, but by seeing secondary indexes on color only, we will get that this partition doesn't have any car which is of silver color. So, we don't scan this partition entirely and this request can now go to some other partition. So, this is how we are maintaining the request so that our data doesn't get overloaded with a lot of request, but based on the request, if they are present in our secondary indexes, then only we will entertain them and show them the records or fetch some records, otherwise, we will directly skip them. Now, this kind of setup also have its challenges, right? Because partitioning is done, but secondary indexes are also present in each partition. That means even if the partition doesn't have any value, we still have to send a request to that particular partition. This is again a drawback of the system which can make the system heavy, which can send the request to many partitions where the data is not there and we are still getting the request. So, this is also wrong. So, that's why we have a fourth and final way of solving this, which is by having common global index. What we will do here is instead of having secondary indexes in each and every partition, we will choose a partition or any data center where we will maintain the secondary indexes. So, if we are saying that we want the car with color blue, we should know that blue car colors, according to the previous examples, are only 209305 and here we have 509 and 609. And basically, this belongs to our P1 and this belongs to our P2. So, we should know this first-handedly. So, that whenever anyone is requesting to get any information about blue color car, we will directly redirect it to P1 and P2. And suppose we have some other partitions, P3, P4, and others, we don't send the request there. So, that these partitions can take care of other requests. So, this is our fourth way of maintaining the global index. So, with this, definitely, we are going to improve our reading, but the writing becomes a challenge. Why? Because even if we are working with partition 79, where we are adding some values, and again have to update that, "Okay, we have some new car, maybe 1011, which is of blue color." So, like this, it is handled. So, these are the ways of handling partitioning into our system. After understanding about partitioning, replication, and load balancing, we now know that we need to segregate our data into multiple nodes in order to scale them. We can't scale them into a single database after an extent. So, after understanding this, let's see what CAP theorem basically says. CAP theorem is one of those theorems which we have to know whenever you think about trade-offs between capacity and availability. So, first see what CAP theorem really stands for. In CAP theorem, there are three terms basically. C stands for consistency, whereas A stands for availability, and P stands for partition tolerance. So, CAP theorem basically states that you can only provide two of these three variables, which means if we talk about consistency, what does it mean? Consistency basically means providing latest information to every user. So, consistency stands for latest information. Now, if we are providing latest information, let's see what it really means. Let's say this is our partition one, this is our partition two. Some data is updated on partition one, and someone is reading that data immediately after the update. So, this update from partition one and partition two will also take some time. And at that time, we basically show something like system is loading or data is loading kind of thing to user until the change is completed on P2. Then only we can show the latest data. So, this means that we will trade off our availability of that particular information for consistency. The second thing is availability. Availability basically states that we will always respond to every request. Now, what does this mean? In the same scenario, if it is taking time to upload a data from B1 to B2, and while updating someone request in between, so they will not see loading icon. Instead, they will see the stale data. So, this is what availability means. Now, the third term, which is partitioning. Partitioning, we all know now we need to divide our data into multiple nodes, right? Now, with partition, we can also see tolerance here. What does it mean? Let's say there are some nodes attached or linked to each other. Now, this is partition tolerant when the network of this node is completely broken. So, this can't be updated from any other method. We can either wait to basically fix this partition connection and update the value or we can keep it working to provide the information. But, then the information we are going to provide is going to be stale data. Why? Because the connections between this node and the other nodes are broken. Now, let's talk about the combinations one by one. So, first combination is CA, which means we are saying that our data will be consistent and it will be available also. In this case, we can't provide the partitioning part. Because if we are saying that our data is consistent and available, that means we are maintaining a single database. We can't basically have two data centers or two nodes and think about consistency and availability at the same time. Suppose we have updated any data here, it is going to take at least some fraction of time to update the data to other node. So, in that meantime, if someone request about that particular data, we can't decide basically whether to show that data or node. Because if we show that data, that means we are compromising our consistency there. And if we don't show that data and wait for the update, that means we are compromising with the availability. So, this combination is only possible when we are working with a single database or a single node. We can't do partitioning here. With this, let's move to our second combination, which is CP. CP means we are choosing consistency over availability. So, here we are saying consistency and partitioning will be there, but we'll be trade-off availability. Now, we have understood this term, let me take the example again. These are our two nodes and the partition happens. Basically, the connection between these nodes break. Now, this doesn't have the updated value. Now, when we are choosing consistency, we have to let go of the availability. So, we are saying no request will be processed by this node. Until when? Until it gets updated with the latest data. So, this is what happens when we are working in a partitioned environment and choose consistency over availability. That means the requests which are calling this node will be redirected to some other nodes which have the latest or consistent data. With this, let's see the third combination as well, which is AP. In AP, we are providing availability to every request, right? So, we are providing availability with partitioning. So, what is going to happen here? When there are two nodes and the partition tolerance happen, that means this node doesn't have updated no updates. At that time also, because we have chosen availability over consistency, we will keep addressing the request by showing them the stale data. And that means we are compromising with consistency. So, why are we learning this CAP theorem? The CAP theorem basically states that you have to do some trade-offs in order to keep your application working. Suppose we are working on Instagram. In Instagram, the availability matters over consistency. Suppose you have updated a video or a photo, it doesn't matter for your followers to see that photo immediately. They can wait for 1 or 2 seconds basically. So, in Instagram, we will be following AP. But in any application, let's say banking application, where each transaction matters to us, where each change matters to us. So, if I have sent 100 rupees to any other account, the person will have to wait in order to process that transaction, and after that only they will be able to see. So, here CP matters. And for CA, CA will be there if we have a single data. That means for every small application, CA can work. But when the system scales, we don't have an option to pick CA. That's when we have to choose between consistency and availability. So, this is what CAP theorem is. I hope you all understand it. Now, let's understand one of the most important component of our system design, which is message queue. Now, before going into depth of message queue, let's first understand the type of request we deal with. We normally deal with two type of request. Or we can also say requests or maybe processes. Some requests are sync. That means whenever the request is received, we have to immediately provide them some output or response for the system to keep working. On the other hand, we have async calls, requests, or processes in which we get the request, but there is no hurry for our responses. Also, it is also possible that we don't give any response at all. So, so that means our system only takes the request and basically fulfill the requirement in the backend processes. So, in case of sync type of calls, requests, or processes, we can't do anything. Our system needs to be concentrated on these requests and have to provide the responses as soon as possible, which we have discussed throughout these courses. Now comes the second part, which are async requests. So, let's understand async process or request with some example. Let's say we are an e-commerce application. We have some store, maybe some product is there, and finally someone purchased this particular product. So, at the time of purchase, what are the operations we need to perform? First is, we need to send some email to the user that order is confirmed and here are your details. We have to also update the inventory so that if, let's say, only one product is left, that product should immediately be out of stock so that there will be no confusion for any other record. Other than this, we also have to inform our delivery partner, right? So, that they will start packaging and moving the order further. Now, out of these three processes or request, which do you think is the most immediate action? So, let's see. Updating inventory is one of the crucial task which have to be performed immediately. We can't wait for it, right? Otherwise, it can create blunders. So, this is definitely a synchronous task. But, other than that, we can use some third-party email service to process the email, right? We don't have to send the emails immediately. Even if the email goes, let's say, 1 minute late, that is also fine, and our system will be keep working. Similarly, for delivery, we can say that delivery also is an async operation because we are not in any hurry. Also, our system doesn't need to take care of delivery, as well. So, we will simply pass this information to any delivery service, and our current system can basically focus on some other task. So, this is how a distributed environment works. Basically, we have multiple services who communicate with each other in order to fulfill the requirement. So, if the services are different, and we have to use, let's say, email, with email, we can also use SMS service, or maybe WhatsApp service. We can use them, and these all are async kind of calls. We don't have to stop our system in order to process this request. So, I hope up to now we have understood about async and sync kind of request, and in async, why we can use some other services, and for sync, we have to wait for the response in order to show some immediate data, like out of service product. Now, let's talk about some of the examples for sync. Every financial application can be an example here. Wherever we are concerned about security, we can't rely on async kind of operation. We have to basically provide the communication immediately. The third area can be dependent. Wherever there is a dependency on one or the other task to be performed after a particular task in a synchronous manner, we have to complete this task in a synchronous manner. So that the dependent processes can also work. For example, we can't process any emails for order details before processing the order. Once the order is processed and confirmed, then only we can put down the emails or other notifications. So after this, let's talk about async also. Async request basically works wherever we need to simply fire our request and our system can then forget about that. So this is the golden rule to understand what system is async or what request is async versus sync. Whenever we get the feeling or we get the components where we can simply fire a request and then our system can forget about that, we can easily move to async calls, which will not only speed our systems but also free our system in order to work on different tasks. So some examples on free and forget can be broadcasting. Broadcasting can be of anything like email broadcasting, even the matches, the live matches which we see online on any application, there also we can feel some latency. The latency can be from 0 seconds to 7 or 8 or 10 seconds also based on the network connections you have. So broadcasting we have discussed, email we can write here. Also we have seen SMS or WhatsApp. Basically any communication can be held asynchronously. Also the OTP applications. In all the OTP application, there is a timer and that timer is mostly more than 30 seconds. Why? Because in 30 seconds our system can handle this request in an async manner. So, now we have understood sync and async, let's talk about message queues. In order to understand message queue, let's take the same example. So, this is our e-commerce application and we are using the service for emails. Now, on our e-commerce application, we are getting some order and based on that order, we have to send emails. But, in between, we will implant message queue. In diagrams, message queue is denoted like this because it is basically a queue and each of these order request or email request can be hold in the message queue and then through our message queues, it can go directly to our email services. So, what our application needs to do, it will simply dump all the email request to our message queue and from there, the message queue will take care of those requests. It is like a buffer or we can say broker in between two apps or services. Now, whichever party or application is putting the request into message queues are known as producers and whichever service is taking the request from message queues are called consumers. With this, producers can also be called publishers and consumers can also be called subscribers because publishers are publishing the message to message queue and then subscribers are the message who are subscribed to take those request from our message queue. So, this is how a message queue basically works. You may think now that why are we using message queue? Can't we directly call the consumer or the email service from our application? Yes, we can call, but that will keep our system busy. We don't want to keep our system busy and we also want that whatever request we are sending should be taken care by. So, these two things can only be done by a message queue. Now, if we talk about qualities of message queue, before writing the qualities, I just want to say that if you still don't get what message queues are, just bear with me for some minutes and you will be absolutely get why do we use message queues. So, the first quality here is that our message queues can basically hold the request. With holding the request, our message queues will have to communicate those requests to our servers. So, they can communicate to servers or we can say services here. With this, why do we use message queue? The reason is it can also be used to handle the failed calls. And with this, one of the major reason of using message queue is handles the load which we are giving to the third party or the service application here, email service. At this point, let's talk about direct communication again. If we again send the request directly from our e-commerce application to email services, that means every time a new order is placed, this call is going to be there. If our email server is down or anything, that call is going to handle the failure case also. That will be responsibility of our e-commerce application. But now, since we are using message queue, these both queries and these both troubles will be handled by our message queue itself. So, we don't have to care about the failed request also. So now, what happens is there are various ways of sending request from message queue to the server. Normally, our message queues follows FIFO. We all know about FIFO. FIFO basically means first-in, first-out. That means whatever request comes first will be delivered first to our consumer. And this is how the series will follow. So, in this case, the first request will be taken care and then after that second, after then third, and so forth. So, this is what the first-in, first-out principle is and it is used by our message queue in order to process the request. So, in FIFO, we have two approaches. First is strict order approach, which basically means, let's say this is our message queue again, and while processing the orders or requests, let's say first process is processed by our consumer, done. After that, we'll come to the second one. So, the second one is also processed. Then, while processing the third request, it breaks down. So, maybe something is wrong with the request or maybe our consumer is down for some time. Because of any reason, our request was not processed. So, if we are following strict order, even if anything fails at this level, our queue will not proceed. Our consumer, even if it starts working again, can't process the fourth request. So, this is not recommended at all because of obvious reasons, because we want our process to keep continue even if one or other request fails. So, the second part solve this issue, which is unordered queue. So, in unordered queue, what we'll do, we'll again create like this only structure of our message queue. So, every time our consumer or subscriber takes back our request, so one, two, and even if there is some issue with the third request, our system will jump to the other request in order to fulfill that. So, our consumer will get the request to perform the operations. Our system will not break. What will happen to the third request? Let's talk about that in a bit. So, after unordered queue, it is also possible that the things which we are getting in request in the message queues, maybe our first request, second request, third request, and fourth request, between all of them, our fourth request is like very important to us, is of high priority, and maybe second request is also of high priority, but not first and third. So, in this case we can't follow FIFO principle, right? So, our consumer needs to get the second and the fourth request first. This is where we used priority queue. What we will do, we will attest a priority like number or some ID to every call. And whose priority is higher, those calls will be picked first by the consumers. So, in this structure if we talk about if the priority of every call is set, let's say the priority of first call is 10, the priority of second call is maybe three, the priority of third call is eight, and priority of fourth call is one. So, that means the first call which our C is going to cater is fourth one. After fourth, it will cater the second call. After second, it will cater the third call, and after third, it can cater the first call. Also, these numbers are in ascending order. I have created uh my system in that way that one will be the most important priority request, but you can reverse the order as well. So, this is how our priority queue is going to take request. After understanding priority queue, there are two more concepts here. So, the one concept is pull request. So, in pull request or pull-based request, what happens is whenever we have some data in our queue, let's again put 1 2 3 or some random values. Now, these requests are in queue, which means that the queue message queue will take care of them. But, the consumer here will decide when to pick the request. Maybe our consumer is working with some other task, and the moment it gets free, it can pull the request. So, message queue will not send the request to consumers. Our consumer will pull the request accordingly. Again, the reverse of this is push-based request. In push-based request, what happens is the opposite of pull-based request, which means if we have some request in our queue, our message queue is going to start the communication with consumer and going to push our request to the consumers. So, here the communication starts from message queue, and in the previous case of pull-based, it will start with consumer. Also, I can change the uh direction of our request. So, because it is pulling, so request will come from here. So, I hope up to now the things are clear. Now, let's talk about pub/sub models. So, in pub/sub kind of architecture, what normally happens is we have publishers here who are like sending the message to our message queue. We have message queue in between, and here we can have multiple subscribers as well. So, what we are going to do, these publishers are going to send some or the other message to our message queue, which will be taken care by our message queue by providing them to the subscribers. Maybe this is using push, and this is using pull. So, this is how the system works in pub/sub model. Pub/sub is nothing but the understanding of our message queues only. So, in this model, we include subscribers and publishers as well. Now, as discussed in the previous example, our message queue needs to perform some operations in pub/sub model as well. First thing is it will hold the request. It will send these requests one by one to the subscribers. And also, in case of any failed response, message queue needs to take care of that. With this, our message queue is also responsible in a way to take care of subscribers as well. By taking care, I mean our message queue needs to check subscriber is working or not. If it is not working, our message queue will not send the request to that particular subscriber, and it will redirect the request to maybe some other subscriber. This is how the things work. So, our message queue basically maintains or the whole state of the request as well. Send the request to subscribers. Take care of the failed request by using DLQ. We will see that in a minute. And also take care of the subscribers health. Also keep checking whether the subscriber is it still alive to work or not. We can also say that it's still alive or not. We can also say that our message queue takes care of request and takes the response from subscribers as well. So, that means our message queue know which subscriber is working fine or fast and which is not working that delicately. So, every time we get a priority queue or a priority task, it will be sent to the subscriber who is working efficiently. So, this is what Pub/Sub basically is. Let's talk about some of the factors which can affect Pub/Sub. The first thing which you can talk about is message order. Let's talk about message order. So, we are saying that all the calls which are going to message queue are async calls. Then why do we need to maintain order? Okay. First thing is that even if we want to maintain some order, we know that we can use priority queue. And this is the only way of maintaining any kind of order in message queue. There is no other way. Maybe it is handled by our application or maybe we can add some additional information of order in the request itself. This is how we can handle message orders. Other than that, it is for async calls where the order doesn't matter. The second thing we can talk about is how our messages are going to be consumed. So, we know that publishers publish the message and they will store in message queue and consumers are going to consume this. But how they are going to consume this? We are not maintaining any order. That means these consumptions are random. Maybe out of 100 request, the consumer can pick up the 100 requests first. Even if we are using priority queue, we can make the priority of 100 requests first. So, there is no particular order in which the requests are going to be fulfilled. Consumers can pick any of the request anytime. Also, message queue can send any of the request anytime based on the priority either or it is completely random. Let's talk about the third factor, which is poison message. So, all the poison messages means all the messages that subscribers are not able to process. Maybe because they are bad requests or maybe invalid. It is also possible that they are failing like after multiple returns as well. Also, if we think about it, let's say a request failed at the consumer side. And then, if we send those requests again and again, those are going to use or consume the consumers energy and will do nothing. Those requests are basically our poison request who are taking time and resource from our consumer as well as message queue but are not able to fulfill. Now, at this point, let's talk about DLQ. So, this is our message queue. This is our publisher or producer, we can say. And here, we have our consumer or subscriber. Now, let's say we have a request which has not been processed by our subscriber due to any of the reasons. So, in this case, our message queue can't stop. It will send the next request. But, this first request will go to a different queue for retry or to maintain that this request was failed. This queue basically, which is maintained by our message queue only, is called DLQ. DLQ stands for dead queue or dead letter queue. So, our message queue maintains this DLQ in order to keep track of the failed request as well. So, that even if the publisher have put the async operations, eventually they will have to know that these cases are failed. So, we will see the failed logs or failed requests through any logs, from which we will see, "Okay, this request was failed." Or other than that, we can also send some or the other information to our publisher in a async manner or in a report kind of manner, where we will give the stats of these many requests are passed, these many requests are failed. And here are the reasons of the failed request. So, this DLQ is the mechanisms through which our message queue will take care of the failed requests as well. I hope you get it now. Also, poison. Poison means any request which can't be processed, which is using or consuming the resources, but can't be processed. So, with this, let's move to our four factor. Fourth factor basically is duplicacy. So, if, let's say, our message queue have processed this request when it is already processed by subscriber one, then it should not travel to subscriber two by any other way. Because the request is already processed, it should not be processed again. What if this request contains some important information which can't be done twice? So, in order to maintain duplicacy, our message queue only takes care of this thing. So, with taking care of each request and dead request, it is also duty of message queue that whenever a process is done, it should be deleted from our message queue, so that we don't perform any operation on that particular request. It should be deleted. And if configured, our message queue keeps end track of this, that there was some request which was obtained from P1 producer and was handled by our S1 subscriber. So, this is how our message queue will take care of the duplicacy of the request as well. After discussing all these things, let's talk about some of the use cases. Like where we can use message Q easily and where we should avoid using message Q. Let's say if we are working on any async kind of environment, any async operations, any async request, we can easily go for message Q. There is no doubt about that. Similarly, if we talk about any decoupling activity, which can be like taking care of user analytics we want to see and capture, maybe we want to capture where our user lands, if our order is failing, why they are failing, and all the log systems. We can easily do this with our message Q as well. There is no doubt about this. The third area can be our load balancing acts. So, if we think about it, our message Q does everything what a load balancer does, right? So, our message Qs can be used as load balancers as well. Where it will take care of all the request, it will keep them in a Q, and it will provide those requests to servers respectively. Also, we can use the message Q with this with the deferred system. Where we have some operations, but we can basically do them later, like generating reports and everything. After every day, we can generate some reports. Or maybe there can be any schedule processes for doing anything. Let's say we are adding products into our catalogs like whole day, and in the evening we want them to be live. So, we will schedule a process in order to work with them. So, the message Qs can be used with load balancer as well as they can be used by our deferred system. Now, message Qs are a costly service. So, if we don't have a lot of request, we should not use message Qs, right? Because it is a costly service, and why waste our cost when we can use them in a synchronous manner? Or maybe if the request count is low, we will directly call the subscriber from producers. Like for emailing, we will directly send the request for our email service. With this, if we are using any real-time application, we can't use message queues basically. Why? Because we need the response to be in a synchronous manner. We need the response to be immediate. And if we are using message queue, our request can take some time to basically respond from any email service or any other services which we are using. So, in these cases, we should avoid using message queues. And also, we should avoid using message queues whenever we need some acknowledgement. Because if we need some acknowledgement, that means our server or our system is waiting for the some response to get. But message queue normally doesn't do it. In this example, where we were sending some reports, this will be also done by some or the other intervention of our code only, so that we can see the processes. But if we want response from every request, it can't be done by message queue. So, whenever we need acknowledgement, we don't use message queues here. And with this, we have covered about message queues. Now, let's talk about faults. Whenever we think about faults or error, we basically, while building any system or while building any software as well, we have to take care of each and every fault and error. Now, while studying system design, we have encountered very components and we know what the complexity our software also holds. So, let's talk about faults and error. So, our faults or errors can be called as in any condition, if our system is not responding in a way it should respond, that means we have some issue or some fault or some error with our system. We can easily categorize them into three categories. The first category is hardware. So, hardware faults are basically belongs to our server. Maybe we are using databases, so DB can also crash. We are using message queues, we are using each and every components, and every component can fail our system if they stops working. So, this hardware issue or hardware fault is our first type, and the nature of our hardware failures is it can be random, right? Like our system can fail entirely anytime. There can be various reasons of its failure. We can have like a disk is full or something out of memory issue, or let's say our server is down. We also use network cables, so maybe they are damaged. Maybe there is an issue with the power supply. Maybe one or the other node is not configured correctly, or maybe it is experiencing some spike in request, so it is down because of overheating. Also, we are using databases, so database can also be compromised, right? These all things are basically the fault of our hardware. We do have some control over it, like we can pass some alerts whenever we are sensing any risk out of them, but they are like inevitable. Whenever a hardware fails, it mostly fails abruptly. That's why we use multiple systems in databases as well, and in terms of servers as well, so that if any server crashes or any databases goes down, we can use our system by using the other database or other server, maybe. So, this is what the hardware issue is. Now, let's talk about the second category of our issues, which is software issue. Now, our software issue can be caused through anything. Maybe the code which we are working on is written badly. Maybe we have forgot to handle any exception or anything. Maybe while testing our application, we tested all of the cases, but there are some edge cases which comes to our picture when the user actually uses the application. So, there can be some edge cases. Also, while coding in microservices or using APIs, we also configure them into our configurations. Maybe there can be some issue with the configuration itself that our system stops responding or maybe not responding in a way which it should be responding. Other than that, we can have some deployment issues as well. There can be some issues with the development environment and the production environment mismatch. So, something is working on production but not working on our development or vice versa. These things come on a day-to-day basis in the life of software developers. So, don't worry about this but we have to take care of this and this is our software issue or software fault we can say. With this, if I have to write any other thing, uh one of the major pain points can be merge requests. So, let's say two developers working on similar feature or same file parallelly and when the code compiles of both of them, we need to thoroughly test both of the functionalities so that it doesn't break down each other on the production or on staging or on any environment. So, this is one of the most pain point thing of any developer. Other than that, our software fault or software issue can be, let's say, our requests are taking too much time. So, the performance is also something which software should take care of. But the good and the bad thing about software issues is that it is not random. There has to be something in the configuration or code file which we can find out and solve that issue. Also, this is not random, this is a good thing so that we can find out the issue. But with not random, it is also deterministic which means by following the same steps, we can get that proper error again and again. And if that error is not fixed sooner, that can basically break our system or give a bad experience to our users. So, we need to fix software issues very carefully and ASAP. Now, the third fault is not really a fault but it comes into the category of fault and is considered the most important faults in our system which is human fault. We know that every human is unpredictable and we don't have any control over ourselves. We can do basically anything. So, this kind of issue or error can cause unpredictably. Why? Because humans are considered to be most unreliable components of software development among all. Every component, whenever they are failing or not working, give us an alert beforehand. But with humans, it is sometimes possible, sometimes not possible based on the value of that particular developer or anyone attached to the software development cycle. But with saying these all things about developers or humans, we also need to know that it is one of the most powerful component or person in the software development life cycle. If human stops working, nothing is going to work. Even if the code is written by AI agents or AI anything, Claude, OpenAI, or any other open source, it is still needs to be rectified by human only. Because we need some accountability over that code because that code is going to build a product which is going to be used by humans only. So, we need human in between all these processes. So, this is one of the most powerful thing. That means that makes us responsible for handling the code even more. So, these are the three categories in which we divide our faults normally into. The software issue, the hardware issue, and the human fault or human error. Human issues can be solved by having good behavior or not doing the band-aid fixes or quick fixes in the wrong manner, but going deep into the system and fixing the thing entirely for each and every area. Also, by software issues, we should not write bad code, handle exceptions properly, see the edge cases, maybe do testing thoroughly of each and every component every time you make a build. It can be solved, right? Also, deployment issues can be solved if you configure each and every environment variable carefully. There can be other configurations for databases or for other APIs which can be configured on development environment as well in order to replicate that issue and eventually solve it. Now, if we talk about hardwares, hardwares are something which we don't have any control on. So, if any hardware is going down, it is mostly unpredictable. So, this is also a danger point. That's why we have to scale our system in order to handle the system perfectly or in a better manner. So, this is all about faults and errors. Now, let's understand about the last topic of system design, which is most important but many playlists skip this one. This is our monitoring and observability. We all know that in our product life cycle, our product is once developed will be deployed to any of these servers and then will be maintained. Now, creating a product is entirely different from maintaining that product. Here, we don't have to maybe change a lot of code and add lot of features, but we have to keep monitoring whether our product is working fine or not. So, we have to take care of these following things. Are there any errors in our system or not? Is every component basically is working fine or not? How's the health of each and every server, every component, every database? If there are coming edge cases or any errors in our system, are we recording them correctly? Do we have logs in place so that each and every customer request can be tracked and can be seen whether they are working fine or not. And if there is any error, can we like go to the RCA of that particular error so that our developer can debug and perform the required operation. And also, if any other component is going down or basically down at this particular moment, do we have other systems in place who will take care of the system? And also, do we have proper alert systems so that we can rectify or get these messages beforehand so that we can take care of the situation in a better way. So we need to take care of all of these things plus more in the maintenance phase or while maintaining our application. For example, let's talk about microservices. So one microservice can do two operations, right? Either it can handle a request and work on it or the other thing it can do is it can even redirect the request to any other microservices. So in this case, we have to monitor two things. The first thing is how our APIs are performing and while handling any request or whenever a microservice or a server is working on anything, we need to also check how it is affecting our machine. Like how much memory it is consuming, what are the consequences of this particular request if it gets overloaded or something. So we have to take care of the machine as well as the APIs at the same time. Now let's talk about both of them one by one. So if we talk about API monitoring, the first thing we need to check is our throughput. Now what is throughput? Throughput basically means how many requests can our server handle. Let's say our server can handle 10k requests per second. So that means if our server is already hitting 9k or maybe 8k responses, we have to configure some alerts in order to know whether we are going to hit our throughput or not and maybe we'll migrate the data or the request to some other servers at the particular time because we need this server to perform or to be alive. The other thing which we can monitor while using the APIs can be our error codes. Like we all know about 500 issues and 400 issues and maybe we are using some redirects also so 300 issues as well. We need to know how many 500s are we getting, how many 400 requests are we getting, how many 300 requests are we getting. So the first thing is when we are getting too many error things, we need to know the RCA of it. So, that means our logging should be in places so that our developer can work. One thing is that. Also, we need to put some alert whenever the count increases after a particular point so that we can get to know about the 500 issues or 400 issues or 300 issues and fix them accordingly. Third thing is our health check. So, in order to check health of any components, we have already seen that we can do it by two ways, passive and active. So, we have to constantly monitor the 200 responses as well and see if our component is in a working condition or not and is giving the positive replies or not. The fourth thing is to check our latency. Latency is a very good metrics in order to check the performance of any system. How can we check the latency? Suppose we have some 10 requests and suppose these values are the response time of those APIs. Now, we need to know the response time of our particular server, of our particular API system. So, how do we calculate them? If we use, let's say, average, the average gives the wrong value because, let's say, our average value for this will come to 6.8 seconds, right? But, if we see most of our requests are being handled in a much lower rate. So, this average value basically gives a wrong impression of our services. So, apart from average, we check P values. What is P? P basically stands for percentile. So, what is a percentile? Percentile basically says if we are writing P90, we are saying that our 90% of the request can be handled in a particular seconds or maybe milliseconds, whatever the time is. In our current example, if we arrange them in an ascending order, something like this, we can see that we have 10 requests and P90 will be calculated here and all of the requests like 90% of the requests will take lesser time than this time. So, this is our 12 seconds maybe. So, let me also remove this milliseconds for a bit. 12 seconds should not be idle time for any API response. This is just for the example, okay? Similarly, if we talk about let's say P50 here, P50 will be 4 seconds, right? So, that means 50% of our request are currently covered under 4 seconds. So, we can see that P50 is 4 second and somehow P90 is 12 second, that means something should be off between these two. We have to check all the APIs which are giving us the response of near 12 seconds. And we have to basically optimize them and improve the performance of our entire system. Again, these P90, P50, P70, P maybe 99.9, when we have a large system and a lot of calls, so all these matrices and values percentiles help us in jot down how our system is working in a majority portion. And also, we can optimize the performance of our system by checking the differences of different P values. So, it is very useful in case of optimizing our code as well and also, we need to know how our system is eventually working. So, this is what percentile is used for and we use it to calculate the latency of our project. Again, here also, we can provide some alert system. Let's say our P90 here is 12 second and if our responses are taking 50 second or something, we should get an additional alert because this is an unusual behavior for us now. So, this is how we take care of latency of our system as well. So, after APIs, let's talk about machine monitoring. By machine, I mean hardware, right? The factors of measuring how our hardwares are working, the first factor if we talk about it can be our CPU usage, like how much power is being consumed by that particular operation or that particular hardware while doing some particular operation. And if that usage basically exceeds any limit, let's say I'm taking example of 75, maybe you can take 70, 90 accordingly. We should get an alert that your CPU usage is already attained a 75%. So you need to take care of the systems. Again, the other thing can be memory usage. Let's say already we have consumed 90% of the memory. So we know now that our database will not be able to hold more values. So we need to immediately either scale our system or we need to see whether we are getting some error or not. Similarly, we have a lot of input-output operations as well. So we have to take care of disk IO operations as well as network also. In both of these cases, we can set the limit and once the limit is exceed, we can send alerts accordingly. So this is all about monitoring our APIs and machine. Now, let me give you a quick recap of all the things which we have discussed so far. We have discussed about system design, what is system design, what are the different components of system design. Then we have discussed about data intensive and compute intensive applications, then functionality and non-functionality requirements, what is DNS, APIs. We have also understood REST APIs in details. After that we move on to DB, our SQL and no SQL DB with detail. Also, cache and their strategies of eviction as well as how do we store the data in cache. We have completed all the cache part very extensively so that we don't get any issues afterwards. We have also covered load balancing and load balancer in which we have talked about how a load balancer acts as a mediator between the coming request and the request which goes to server. Also, it works as an orchestration between different servers and take care of each and everyone's health. With that, we have covered various forms of replication, partitioning. Ultimately, one of the most important theorems which we're going to cover in each and every interview, that is CAP theorem. Whether you'll choose availability over consistency or vice versa. After CAP theorem, we have covered message queues, fault tolerance, and then we had a brief discussion about monitoring and observability also. So, with all these topics, now we are ready to give any interview or to design any system design component which we want to. We have a solid foundation now. Now, we can design any system. So, congratulations, you have unlocked a new trick, a new component, a new system in your resume, in your abilities. Also, if you feel like I have missed any point or any topic, please mention that in the comment. I may make a video of it in the coming days. With this, let's move to the last part of our video, which is designing a system. So, whenever you appear in an interview of system design or maybe you will design a system by yourself, it is very important to think out loud. So, you have to take your decisions very specifically. No one is looking for the perfect solution, but everyone here is looking for what are the trade-offs you make, what are the components you use. Also, when I'm talking about components, whenever you are using a component, it is very important that you use it for the right reasons. Just because you know about all the components, it is not recommended to add all the components into your system. Because remember, every component you add will add the costing of your system also. So, we have to use the component and design the system very efficiently so that it can be cost-efficient as well as work efficiently to solve our purpose. So, for now, let's design a video streaming application. So, see, we already have a lot of applications. We have YouTube for streaming. We also have, let's say, Hotstar, Netflix, Prime. Also, if we talk about streaming applications, we can also say G Meet is also a streaming application because we can do the live streaming. Uh we can call it a Zoom call or a G Meet also. So, Zoom can also come into this category where we stream our video live to other members. So, a call is basically also an example of a streaming application. Now, with this, we can also use LMS or any other software for streaming our data. We can have more applications. I'm just jotting this down so that you get the idea of the applications which use streaming. Now, before starting, it is very important to jot down the requirement. So, for our video, we doesn't care about user login. We don't care about their reviews and maybe rating also. We don't care about any other operation, but we only need to know how a video basically process from one system to finally our client system. This is what we need to know in this particular example. Now, whenever you appear on an interview also, it is very important to jot down the requirement because let's say they give you an example of designing any software like Netflix, you need to know what are the features the interviewer is interested in. With that, while creating your systems also, you need to know specifically what you are designing because you may be designing an entire LMS, but for that moment, you need to pick feature by feature and design each component and at the end, maybe collect all the findings and create a system. This is how every system is built. Now, here, we only are talking about this process of getting a video to our client system from any server or from any other source. Okay, so let's start from very basic. What is a video? A video is nothing but a collection of different images we can say and with this we also have some audio here. So different images are combined with audio to create a video, okay? So in order to calculate different images we can see FPS or frame per second. We can have 30 or 60. These two things are available. Also, we can use 120 or 240 if they're available. I'm not that sure about it. But yeah, these two frame rates are quite common in our day-to-day life. So what does it mean to have 30 and 60 FPS? Basically, in 1 second, if we are using 30 FPS, our video will be divided into 30 images. And if we are using 60, for 1 second, it will be divided into 60 images. So that means the size of 60 FPS will be more than that of a 30 FPS video. But if we talk about the video smoothness, also the 60 FPS video will be more smoother than a 30 FPS video. Now with this, let's stick to 30 FPS thing. Let's say a size of a normal video, let I'm like I am recording a video in 30 FPS right now. My recording, let's say went for 1 hour and for the 1 hour recording video, the size of my recording is basically around 2GB. So if, let's say you are watching this video and if you want to download the entire video in the start before playing and then you play, what will happen? It will add latency to our system because downloading 2GB will take time for sure. Also, you have to see buffer and let's say you downloaded all the 2GBs of content into your system just to see a particular section or maybe you see the first 10 seconds of the video and didn't like it. So, you wasted your internet and storage. So, this is not a good option to download 2GB entirely first hand and then see a video. It is completely waste of time. So, we have to think about something else. So, the thing is here we have to use some network which is suitable for our system. So, in order to process information in video or images form, we normally go for TCP. Because TCP maintains a sequence of things. Why do we need sequence? Let's see in a bit. So, in TCP we have two protocols. One is RTMP which is Real Time Messaging Protocol and the other one is RTSP which is Real Time Streaming Protocols. Both of these protocols basically help us in order to stream a particular video to our device. Now, what this protocol does is let's say we have a complete video here. It is going to divide our video into different chunks called as segments. And our client machine or the server from which we are watching is going to pull these segments one by one. Now, in message queues we have talked about pull and push. This time I'm saying pull. So, just connect the dots. Keep connecting the dots while I'm saying things, okay? So, this is going to pull our segments one by one based on the network. Now, we'll come to this part in a bit. So, this will solve our issues. This will give us a low latency because we don't have to download the entire video. We can download some segments also. With this we'll now be able to stream in a much better way and it will be more efficient than downloading the entire video which was consuming our resources and network bandwidth. Now, this time we have to only download some segments which is going to be more efficient because this time we are downloading in parts. So, suppose we are watching one video, first 10 seconds is over and now we don't want to watch the entire video. So maybe some or the other sections will be pre-downloaded for us so that if you go ahead we don't see buffer, but we don't have to download the entire video which will save us a lot of space and lot of network bandwidth as well. Now with FPS we also have one more factor which changed the game entirely which is resolution. With videos we have different resolutions, right? We can use 4K, we can use HD, we can use maybe 720p, we can use 480 or 240 or even 144p. Even 64p was an option. I'm not sure whether our video will be able to render in that quality or not. I have like way before when I was in school, maybe I saw that. After that I didn't. So yeah, these are all the resolutions on which we can see our video. 4K will obviously have better quality and 144p is going to have bad quality. But why are we talking about resolutions is even if let's say we are streaming a 4K video, which I already said for 1 hour video we need to store it in 2GB space. Suppose we divide this into multiple segments for each second, then 1 second will be 0.57 MB. Now this looks small but is a huge size if we talk about network. What if we have a poor network? What if we are traveling? So our network is keep on fluctuating on a different level. Also if we sit by working on our office or on system, our networks keep on fluctuating as well. So that means we are not going to have a common bandwidth throughout our video viewing experience. So our network will keep on increasing and decreasing. So we have to take care of that also. Let's say I record videos in HD only and if I start recording in 4K, that means the size of 2GB can become big, right? The 2GB can go to 4GB. Maybe I use multi-cam setups. At that time, the 4GB can also go up to 8GB, maybe. Also, in my videos, I'm not doing much activity. The frames are pretty still. Only my hand movements can be shown once in a while. I'm sitting still. I'm just facing the camera or the screen. I'm not doing much activities. Also, the screen you are seeing is black on which I'm writing in white. So, there are no colors, also. So, this is pretty easy video to see. But, if I start recording outside or maybe I start recording any action sequence, so in that case, the size can also get to 16GB for the same 4K video of 1 hour. So, this size can also be increased to four times. So, that will be around 4MB. So, the issue here is for even 1-second video, we are using 4MB. And if our network is not that good, we are still going to see buffer or face loading issues, which is going to basically ruin the experience of our viewer, and they will leave the application. This is not what we want entirely, right? So, we have to do something about it. Also, if you think about it, there are different screens on which you work on. We maybe watching something on TV. We maybe using our laptop screen. Uh also, we can use our mobile screen, maybe our watch as well. Maybe we are seeing it on iPad. We don't want 4K qualities in all of them, right? Let's say we are watching on watch, we don't want 4K. Maybe on watch, 480 works fine. And also, on iPad, also, I don't think 4K is required. Maybe we can show them in SD, and it will be enough. On TV, we basically require 4K. Like, we don't have to compromise here. But, on laptop, also, we can switch between HD and 4K. We can choose. We can pick based on the requirement or based on the configuration, based on the network also. On mobile also, we can work pretty well with SD. We don't need 4K here as well. So, that means not only network, but based on our screen size, we can change the resolution of our video. So, why are we changing? Because it is going to reduce the size of our segment. And the lesser the size, the faster it will be to show. So, in order to maintain streaming, we have one mechanisms, which is adaptive bitrate streaming. What it basically conveys is, let's say you start watching a video on 300 Mbps. And your networks keep on fluctuating. Maybe it went down till 10 Mbps. So, when the network fluctuates, we can't download with the same consistency. And if we are not able to download with the same consistency, there's high chance of seeing the buffer icon. And we don't want that. So, in order to achieve this, what can we do? We have a source video of 4K, right? We have to divide this video into different segments, that we know. Also, we have to divide those segments into different qualities. So, for example, this 4K video is divided into 10 segments of 4K quality. But now, also we have to divide these segments into more configurations, the lower configurations. Now, our basic resolutions and segments are ready. Now, let's see in real time how our function really works. So, let's say here we have our client who is watching something on our desktop screen. In starting, the network connection was 300 Mbps. So, we start showing them the 4K video. So, it sees segment one, maybe segment two also he watches. And then, the network drops to 10 Mbps. So, at this point, maybe this is already loaded into their system in the form of cache. So, they can still see this section into 4K. But after that, we need to load the data again. And the network is now at 10 Mbps. So, we can't load the 4K data. What we will do, we will load the lower configuration data. Maybe according to this we will pick 480p. So, we will start downloading this data. And once the network restores to maybe 300 or 150 Mbps, we will start switching our configurations accordingly. So, we can go to 1080p as well. And if it then drops to 50 Mbps, we can still give them 720p. And at the end, if network basically restores to 300 Mbps, we can show them the last segment in 4K again. So, this is how an YouTube or any other stream basically works. They will keep switching our quality based on our network bandwidth because we are mostly seeing that entire video on a single screen. And based on our network, they will keep switching the qualities. And we see the entire video into one go without seeing the much difference there because normally the network doesn't drop so drastically. We just keep these segments in order to show them into different devices. If you pay attention in most of the streaming applications where you are seeing the video, in the side corner, you also see a segment where you can switch your configurations again. You can choose between auto, maybe HD, or maybe they will directly use the configuration that is 720p or 480p, something like this. So, you can choose between them. And if you choose auto, they are going to perform this orchestration or this game while you watch the entire video. So, what did we see here? If the network throughput, that means our network speed, is greater than the bitrate of the downloaded segment, that means we have downloaded in a lower quality and now network is greater than that. So we can now switch to a better quality. Similarly, if the network throughput is less than the bitrate of downloaded segment, so in this case what we will do, we will switch down the quality of our video. So after getting all this knowledge, after discussing all these things with your interviewer or with your team, then you start deciding what components do you use in your system design. Now the path is very clear, right? We need to store the current data or the actual data somewhere. Maybe this is our CDN where the actual data or the actual video is uploaded and it is uploaded from where? From any server. Now from here we need to create the segments, so that means we need to give this data to a service which can basically transform our video. So we can name that we can say it is a transformation service. Now after this we have to send the segments to our queue. We can use priority queue here, right? So we can create a queue. And why we are using priority queue? You need to answer yourself. Now from this message queue, our system is going to use the services of downgrading each and every quality. So we use worker term here. Worker is basically used in order to denote another service. So we may be using worker one for downgrading it to HD. Also we can use worker two for maybe downgrading it to 720p and so forth. So after working with these resolutions, again we need a message queue to store the results into segments and again we need a priority queue here. Okay, with this we will send this request to a distributed CDN kind of services from where it can go into different part of our servers. So, if someone is watching from India, they can access the data from this server and they can watch it from US server and the other servers are for other regions. Now, by doing this, we have completed the entire system design of our video streaming application. And from this server, eventually, we are going to access it on our client machine on which our user is going to watch their video. So, now after creating this diagram, let's also do some maths. Let's say our source video is of 50 GB and it is of 20 minutes. So, it is a high-quality video, maybe 4K, and it is having 60 FPS. So, that's why the size is too big. So, this is we are taking as an average size of the video which we are going to stream. Maybe we are streaming an entire match. So, this is the size which we are going for our 20-minute video. Now, let's decide how many segments can we divide it to. So, I'm doing an easy maths. So, 20 minutes multiplied by 60, that will convert it into seconds. So, it will be 1 2 0 0 seconds. And also, I am making the segments also equal, so that means 1 2 0 0 segments as well. Also, with this, let's talk about different resolutions. So, let's say 4K is of 50 GB, which will be divided by our segment. So, here the size of our segment is too large, right? Because it is a 4K video. Maybe we can divide it into more segments. So, but for this example, let's stick to it. Let's say our 1080 pixel video, let it be for 20 GB and again, we are going to divide it by 1200. It is going to be again 16.6 MB. With this, let me write all the resolutions. Now, this is what the calculation looks like if we divide it for each segment for each resolution. For 720, it will be 8.3 MB. For 480, it will be 4.17. And for 250, it will be 2.08 MB. That means if we combine them all, it is going to be 72.65 MB, approximately. So, that means the size of one segment of our video is going to be 72 MB, which is too huge, I feel. So, maybe we can divide it into further segments. But for now, this is going to be the size of our one segment. And accordingly, we need to load the data into our stream. Also, while calculating the size, we should also take care of our user. That means we should know how many users are going to see the stream. So, if the user count is, let's say, 100, we can use the same server or a single server only, right? For 100 number. If we count this, it will comes down to 87.5 GB. So, we can store 87.5 GB into a single server, and from which these 100 users can view our streaming easily. What if the user changes from 100 users to 100,000 users? Now, this will change our picture. Now, this is where we will know that our one server is maybe not enough to cater so much requests. So, we will divide our servers into two, maybe. And based on the number of users, we have to keep increasing the count of servers. Maybe we'll use message queues. Maybe we'll add some caching algorithms. And all of this will be managed through our diagram. Here, I have not used any caching. But we can use the caching on CDN level. Or we can use the cache on our browser level, which is going to hold the segments of the coming part. So, this is what the design look like. This is what the calculation is. And this is what is the logic behind the system design of my system, which will stream our video to a 10,000 or a 100,000 user. Now, this diagram can be different in your case also. It is very possible that you will design a system better than me, and it is also possible that you will see some other YouTube video who have designed the video better than me or maybe worse than me. So, these designs are basically your practice. The more you practice, the more you see other designs, the more you read different papers, your designs are going to improve. And more your design improves, the quality of your system or your workflow increases with time. So, with this, I end the discussion of system design. And I really hope you all enjoyed this series so far. This was a long video, and we covered a lot of topic. I hope you all enjoyed it. Now, you can like this video or comment the most interesting section you found out in this video. Also, you can comment out any topic which you want to see in future on Telescop. With this, my name is Akshat Agarwal, signing off. Thank you.
Keep this transcript
Save it to LunaNotes and it becomes a real note in your library — editable, searchable, and ready to turn into flashcards or a diagram. Free to start.
Save to LunaNotesOr download subtitles for another video.
These subtitles were extracted using the Free YouTube Subtitle Downloader by LunaNotes.
Related videos
Download Subtitles for CLAUDE CODE Full Course 2026
Enhance your learning experience with downloadable subtitles for the CLAUDE CODE FULL COURSE 4 HOURS: Build & Sell (2026). These captions help you follow along easily, improve comprehension, and revisit key concepts anytime. Perfect for learners who want clear, accessible content at their own pace.
Download Subtitles for Introduction to DaVinci Resolve Full Course
Enhance your learning experience by downloading accurate subtitles for the Introduction to DaVinci Resolve full course. Captions help you follow along effortlessly, improve comprehension, and make the tutorial accessible anytime, anywhere.
Download Subtitles for Complete RAG Crash Course with Langchain
Enhance your learning experience by downloading subtitles for the Complete RAG Crash Course with Langchain video. Subtitles help you follow along easily, support better comprehension, and make revisiting key concepts effortless. Access accurate captions to maximize your understanding of Langchain in just 2 hours.
Download Subtitles for Harvard CS50 2026 Computer Science Course
Enhance your learning experience with downloadable subtitles for the Harvard CS50 2026 full computer science course. Easily follow along with lectures, improve comprehension, and access the content offline anytime. Perfect for students and enthusiasts aiming to master computer science concepts.
Download Subtitles for Adobe Illustrator Beginners FREE Course
Enhance your learning experience with accessible subtitles for the Adobe Illustrator for Beginners FREE Course. Download captions to follow along easily, improve comprehension, and master the software at your own pace.
Most viewed
Untertitel für 'Nicos Weg' Deutsch lernen A1 Film herunterladen
Laden Sie die Untertitel für den gesamten Film 'Nicos Weg' herunter, um Ihr Deutschlernen auf A1 Niveau zu unterstützen. Untertitel helfen Ihnen, Wortschatz und Aussprache besser zu verstehen und verbessern das Hörverständnis effektiv.
ดาวน์โหลดซับไตเติ้ล DMD LAND 3 The Final Land Day 1
ดาวน์โหลดซับไตเติ้ลสำหรับวิดีโอ DMD LAND 3 The Final Land Day 1 เพื่อช่วยให้เข้าใจเนื้อหาได้ง่ายขึ้น และเพิ่มความสะดวกในการติดตามทุกช่วงเวลา เหมาะสำหรับผู้ชมที่ต้องการความชัดเจนและเข้าถึงข้อมูลอย่างครบถ้วน
Subtítulos para TIPOS DE APEGO | 6 DE COPAS Episodio 56
Descarga los subtítulos para el episodio 56 de la tercera temporada de 6 DE COPAS, centrado en los tipos de apego. Mejora tu comprensión y disfruta del contenido en detalle con nuestros subtítulos precisos y accesibles.
Descarga Subtítulos para NARCISISMO | 6 DE COPAS - Episodio 63
Accede fácilmente a los subtítulos del episodio 63 de '6 DE COPAS', centrado en el narcisismo. Descargar estos subtítulos te ayudará a entender mejor el contenido y mejorar la experiencia de visualización.
Download Subtitles for Inside Out 2 Extended Preview 2024
Get accurate and easy-to-follow subtitles for the Inside Out 2 extended preview (2024) featured on Fandango at Home. Enhance your viewing experience and ensure you catch every detail of this exciting preview with our downloadable captions.
Found this transcript useful?
Take it with you. One click puts it in your own LunaNotes library.
Save to LunaNotes