# System Design One Shot Full Course

https://www.youtube.com/watch?v=Vnm-ycSfJx4

[00:00] Welcome back aliens.
[00:02] My name is Vin Reddy, and in this video we'll talk about system design.
[00:07] I know you are waiting for a long time for a system design course on Telesco, and finally we are here.
[00:14] Now, in this course we are going to understand different aspect of system design.
[00:18] Now, why it is important?
[00:20] 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.
[00:26] 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.
[00:35] And let me give you a statement which highlights this, and I have it here.
[00:40] Anyone can write a code that works.
[00:44] A system design is what makes it work for million people at once, and that's the power of system design.
[00:50] See, when you write a code, of course when you learn a language, you learn a framework, you can build application.
[00:55] That framework can I mean, the entire project will work.
[00:59] The moment you deploy it, the moment it is in production, and
[01:00] When you have users, not just 10 users,
[01:03] 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?
[01:11] That's the question.
[01:13] 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.
[01:20] There are millions of users, but still if you can see, they work.
[01:29] So, how do we do it?
[01:31] And that's where system design plays a huge role.
[01:33] Now, to understand this, we have we will be going through these concepts.
[01:36] 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.
[01:51] Now, once that is done, we'll talk about how the communication happens between different systems.
[01:54] 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
[02:03] Django and any web framework.
[02:05] Then we'll move towards the data.
[02:07] Of course, when you have a lot of users, how will you store data?
[02:11] Not just their personal data, but their activities.
[02:13] 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.
[02:23] Then, let's say your users are growing day by day.
[02:25] How are you are going to manage your application?
[02:27] And that's where scaling and distribution comes into picture.
[02:30] In which we'll talk about load balancers, replication, partitioning, and the CAP theorem.
[02:36] That this will be an interesting the CAP theorem.
[02:38] And then, we'll talk about operations and reliability.
[02:43] And the most important part there becomes a fault-tolerant.
[02:45] What if something goes wrong?
[02:46] Does the application do have something to do that?
[02:50] In which we'll talk about message queues and monitoring as well.
[02:52] And of course, we'll cover different examples here to understand different concepts.
[02:56] And the entire section or this part will be taken by an amazing trainer, Akshay, who is very good in explaining stuff.
[03:03] And I hope you will enjoy the entire part.
[03:06] And do share your thoughts in the comment section.
[03:08] Don't keep it blank.
[03:11] You what you like, what you don't like.
[03:12] If you have any questions, do point it there.
[03:14] And we'll try to answer them.
[03:16] And if you enjoy this type of videos from us, let me know in the comments as well.
[03:20] That is our motivation.
[03:22] And I hope you're motivated.
[03:24] Let's get started.
[03:24] Akshay is all set.
[03:26] [music]
[03:28] Hello everyone.
[03:29] Welcome back to Teleschool.
[03:31] My name is Akshay Agarwal.
[03:33] And today, we are going to start the system design course.
[03:35] In this course, we are covering each and every topic which includes in system design.
[03:39] So, let's start with understanding why do we need system design at all?
[03:44] In systems, we have a lot of systems around us.
[03:46] If we talk about human body only, we have digestive system.
[03:49] And also, we have a system.
[03:52] Along with this we have a lot of systems, but these kind of systems are pre-built.
[03:56] It means we have not created them.
[03:58] We just discovered them with time and we got to know about various components which are required for us to
[04:05] Breathe or to digest our food.
[04:08] So, in these systems as they are not built by us, we can't actually change anything.
[04:12] Maybe through surgery we can change some of the other component, but not much.
[04:17] But the kind of system we talk about in IT industry are the systems which are built by human or engineers like us only.
[04:25] 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.
[04:47] So, in system design if we go through the words we have two words here, right?
[04:50] One is system and one is design.
[04:52] What is a system?
[04:55] If we go through the definition, system basically means there are a lot of components.
[04:59] There can be more than one components in that system.
[05:02] So, let me write components.
[05:04] And those components are working eventually to
[05:06] Solve a particular use case or maybe multiple use cases, but the common purpose of the application remains same.
[05:13] So, that means if we write system is equal to components plus common goal, this sums up our definition of system.
[05:20] 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.
[05:34] But in order to start, let's not dig too much into the technical details in this video.
[05:37] Let's start from a very basic.
[05:40] Let's say we have a requirement of creating our own application or our own bank.
[05:46] Let's say we have a bank named Alien Bank because we are in Telesco, why not?
[05:51] And in this bank, we are not dealing about each and every operation.
[05:53] Currently, we have a single operation, which is we have a cash counter, and we have a person sitting on a cash counter.
[06:00] Let's name it as cashier.
[06:03] Okay, so here we are ready with our cashier, who is on our cash counter, and the requirement or
[06:07] The flow is pretty simple.
[06:09] For the flow, let's understand the concept of our bank.
[06:14] 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.
[06:25] So, let's write it down as customer flow cycle.
[06:28] So, in our customer flow cycle, there are four steps, basically.
[06:31] 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.
[06:41] The purpose of our application is done.
[06:43] So, these are the core functionality of our system.
[06:45] It is very basic, very easy.
[06:47] You might have seen this already in some of the banks.
[06:49] So, we are building the same architecture right now.
[06:52] The architecture basically looks like this.
[06:55] 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.
[07:03] We are going to face five issues, and based on the issues and solutions, we are going to understand how system design looks like.
[07:10] So, here comes our first issue, which is the process is really slow.
[07:14] By slow, what we meant is, let's say, our cashier takes 10 minutes per customer.
[07:20] So, that means we are serving only six customers in 1-hour span.
[07:25] 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.
[07:35] So, in order to improve this, let's first focus on our cashier.
[07:39] So, let's understand our system from the cashier's point of view.
[07:44] So, basically, our cashier is taking time to understand the requirement.
[07:49] By requirement, I mean whether the customer needs to deposit the amount or customer needs to withdraw the amount.
[07:54] They have to make this interaction, which is time-consuming, right?
[07:57] 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.
[08:05] And then our cashier will prepare a receipt, which will be again given to our customer.
[08:09] So, these are the time-consuming tasks for our
[08:11] Cashier.
[08:11] How can we improve the cashier time?
[08:15] So, in order to improve the working of our cashier, we have three major issues.
[08:17] First is they are not able to understand the requirement.
[08:20] Next is they are counting the cash manually, which is taking time.
[08:25] And again, they have to prepare the receipt.
[08:29] So, these are the issues which our cashier is feeling, and we are trying to solve these issues.
[08:36] Maybe we can train our cashier in order to count the cash very rapidly.
[08:39] Okay.
[08:42] Also, our cashier is also responsible for maintaining the receipt.
[08:44] So, we will improve the typing speed of our cashier in order to make the receipt very fast.
[08:48] So, the second thing is train to type fast.
[08:54] So, with this, what we are doing, we are not adding any resources to our cashier.
[08:59] Simply, we are making our cashier super fast, right?
[09:02] We are improving the skills of our cashier, which is required for them to maintain this job.
[09:07] And let's say through this training, the cashier is really improved now.
[09:10] He is or he or she is now taking, let's
[09:13] Say, 5 minutes in order to fulfill one customer's need.
[09:17] So, this is a huge improvement.
[09:19] By this, we are able to improve the process by 50%.
[09:24] 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?
[09:34] Growing very fastly.
[09:37] So, now the issue two is our customers count is increasing.
[09:40] This is our issue two.
[09:42] In this case, what we know so far?
[09:45] We know that our cashier we can't improve our cashier performance because it is now at its peak.
[09:49] So we have to basically handle some or the other components to our cashier in order to make the work very fluently.
[09:56] So maybe the desk on which our cashier is sitting, we will increase the size of desk.
[10:02] 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?
[10:09] So we'll provide cash counting machine, right?
[10:12] So with this also the time will
[10:14] Get reduced and our cashier will be able to attend more customers.
[10:19] 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?
[10:35] So our cashier will now don't have to communicate each and every request to our customers.
[10:39] Uh, they can simply see the form and based on the form they will fill out the thing.
[10:47] And now our cashier have cash counting device also, so the process will be fast.
[10:52] 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.
[11:03] This is also a huge impactful thing.
[11:05] So now our cash counter is capable of attending more customers in lesser time.
[11:10] So that means even if the customer count is increasing, we will be able to process more customers.
[11:14] And enroll more customers into our Alien bank.
[11:17] So this issue is also kind of solved.
[11:19] Now let's move to the third issue.
[11:21] The issue three is our customers are still waiting to get their application resolved, right?
[11:28] Currently, what do we have?
[11:30] We have our cashier who is upgraded to its maximum level.
[11:34] So, we can't upgrade the cashier more.
[11:36] Also, the desk on which it is sitting, the cash counter, is also upgraded to its maximum limit.
[11:40] So, we can't upgrade our cash counter more.
[11:42] So, these two things are pretty solid right now.
[11:45] We can't improve it now.
[11:47] 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.
[12:00] So, that is a huge drawback of our system right now.
[12:02] And why that drawback is coming?
[12:05] Because we have only single cash counter in our system.
[12:09] 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.
[12:16] So, let's add them.
[12:18] So, now we have our cash counter one and cash counter two.
[12:20] Now, at this point, we have added one more counter, and things are pretty solid right now.
[12:28] So, our customers will eventually have two counters to go to, and both of those counters will be able to solve our issues.
[12:34] It feels good, right?
[12:36] Now, we have two counters to process.
[12:37] So, our customers will not have to wait for longer time.
[12:40] They can either go to counter one, or they can go to counter two.
[12:44] 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.
[12:53] And similarly, our second counter is also maintaining its own data.
[12:55] And they are not synced.
[12:59] So, this creates two issue, right?
[13:01] 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.
[13:14] Now, the second issue is this only.
[13:18] First account, they can also withdraw the amount, and they will not update the second counter.
[13:25] So, that means they can again withdraw the amount from cash counter two also.
[13:29] This will create an issue of data discrepancy.
[13:31] That means our data is not synced.
[13:34] 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.
[13:45] 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.
[13:55] And if the counter two is getting withdrawal request, they will also get the amount out of the same account.
[14:01] So, in order to fix this, we need to have a centralized data.
[14:05] That means our counter will look like this.
[14:07] This is our counter, let's say two.
[14:07] This is our counter one.
[14:10] And they will eventually connect to a centralized database.
[14:14] And as it was before, our customers are standing in a queue waiting for their turn to come in.
[14:19] Order to get the request.
[14:22] Now, after solving all these case also, we have a new issue in hand.
[14:27] Which is, let's say the gate of our bank is here.
[14:30] This is our alien bank.
[14:32] 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.
[14:40] Or maybe processing lesser request, far lesser request than the cash counter one.
[14:44] This will again end up adding the wait time to our customers.
[14:49] And again, we will be end up handling lesser customers than our potential.
[14:53] So, let's write that down.
[14:55] This is our issue five, which is underutilized counter.
[14:57] Now, in order to solve this issue, we need to have a middleman.
[15:02] Which will stand apart from our counters.
[15:04] Let's say this is our counter two.
[15:06] Again, this is our counter one.
[15:10] And here are our customers.
[15:12] And now our customers will not go to the counter directly.
[15:14] They will first go to this middleman.
[15:17] Then the middleman will check how much load each counter is handling.
[15:20] 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.
[15:32] And the count will increase to six, right?
[15:36] And the next customer will again go to counter two, and the next customer is again going to counter two only.
[15:41] When the limit reach, let's say we have 11 customers here and 11 customers here.
[15:47] And if then any new customer arrive, they will again ask man where to go.
[15:52] Let's say on some fine day our counter one is not working.
[15:57] 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.
[16:06] So, let's end this example here at this particular point and see what have we learned.
[16:11] Through this story, through this single story and five issues, I have tried to capture multiple concepts of system design.
[16:17] So, the first concept which we discussed is designing a system, that is for sure.
[16:22] Ultimately, what design we do have here?
[16:25] We have one cashier and the other cashier.
[16:30] Each cashier is having their own counter.
[16:32] So, this is our counter two, maybe this is our counter one.
[16:34] We have a number of customers waiting for us.
[16:37] Also, we have a middleman now.
[16:41] With that, we also have a common database, okay?
[16:43] So, this database is nothing but centralized database.
[16:49] The customers which are coming to our bank is nothing but requests.
[16:54] And if they are standing in a queue, we can say they are creating a traffic, okay?
[16:58] So, these are the traffic which we are going to handle.
[17:00] Now, all the requests or all the traffic is coming through a load balancer, the middleman.
[17:05] So, this is nothing but our load balancer.
[17:09] So, from the load balancers, all the requests are coming to either of the cash counter.
[17:14] So, we can say that our cash counter is nothing but servers.
[17:19] And the person sitting there doing the work is nothing but our application code.
[17:21] Now, let's see the
[17:23] System again through the system design point of view.
[17:25] So, the first issue which we have was our process is slow.
[17:30] So, in order to solve that, we improved our code quality, right?
[17:35] So, first thing which we do in our systems also, we improve our code quality.
[17:39] So, this is where our LLD will come and this is where our DSA will come.
[17:44] 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.
[17:56] So, while solving the issue two, we increase the size of our table, we added some functionality, we added this cash counter.
[18:03] That means we upgraded our server.
[18:05] So, in order to upgrade our server, this term is called vertical scaling.
[18:10] In vertical scaling, we don't add multiple servers, we basically update our current server only.
[18:14] And again, the current server updation have a particular limit.
[18:19] After that limit, you can't upgrade your system.
[18:21] So, then comes the issue third.
[18:24] Which is our customers need to wait for the single server to respond.
[18:29] So, in this case, we added more servers.
[18:31] So, in this scaling, we added more server that is called horizontal scaling.
[18:36] So, after having multiple servers, we need to maintain the data at the common point.
[18:40] So, that's why we added databases.
[18:43] 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.
[18:54] So, this is nothing but centralized database.
[18:56] So, after having centralized database, again the issue comes where we don't know how to handle multiple requests.
[19:03] That means our requests are again going to one counter only or one server only.
[19:08] Now that we know they are going to one server only and the other server is underutilized.
[19:13] So, what we did, we added a middleman.
[19:15] Our middleman is no one but our load balancer.
[19:18] Our load balancer basically do two things.
[19:23] They will check whether our servers are healthy or not and based on.
[19:25] That, they will distribute the request equally into multiple servers.
[19:29] So, these are all the concepts which we discovered through this particular example.
[19:34] 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.
[19:51] 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.
[19:59] So, we can say through a large lens, the data consist of these four kind of information.
[20:06] And all of the applications which we are using in our day-to-day life consist of these data's only.
[20:10] 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.
[20:20] So, in the center, as we discussed, we have data.
[20:22] Data can be of various form.
[20:25] It can be image, video, audio or text.
[20:30] Now, if we think about data, it is not
[20:31] like we are seeing the data once only.
[20:34] We have to see the data and also while
[20:36] storing also, we need to store the large
[20:39] amount of data. Now, in order to store
[20:41] the data, we do have databases. So,
[20:43] databases are basically our first
[20:45] component of system design. What is
[20:48] functionality of databases? Pretty
[20:50] simple. We need to store our data and
[20:53] whenever we want to retrieve some data,
[20:54] we need to get the data from our
[20:56] databases only. They are represented by
[20:58] this cylindrical figure. Databases can
[21:01] be of multiple ways. It can be
[21:03] categorized into no sequel or sequel.
[21:06] Now, there are various kind of databases
[21:08] in both of these categories. In sequel
[21:11] also, we have various databases from
[21:13] which we can select which database we
[21:14] are going to use. And similarly, in no
[21:17] sequel also, we have various kinds of
[21:19] database from which we can pick which
[21:21] database we need for our application
[21:23] right now. But, the core remains seems
[21:26] that we are saving our data in some or
[21:29] the other database. We will discuss
[21:30] about sequel and no sequel databases in
[21:32] the coming videos. That's why I'm not
[21:34] going to deep into this at this moment.
[21:36] Let's think about the scenario where you
[21:39] and every user on the planet knows the
[21:41] queries of database, knows how the
[21:44] tables are structured if we are talking
[21:46] about sequel, or how the documents or
[21:48] nodes are connected if we are talking
[21:50] about no sequel. If we talk about both
[21:52] of these scenarios, if user, the end
[21:55] user, already know the database query
[21:58] languages and know how to deal with
[22:00] different kind of data, in that case, we
[22:02] might not need any application if you
[22:04] think about it. We will simply go to our
[22:06] database, or the database will be
[22:08] accessible throughout every application.
[22:11] Suppose we are seeing the LinkedIn, but
[22:13] on LinkedIn we will see an interface on
[22:15] which we will write our query, and the
[22:17] data will be fetched to us. That will be
[22:20] an hectic task. But, if users know about
[22:23] that, and if users start exploring that,
[22:26] that will be easier, right? In that
[22:27] case, we don't need any application
[22:29] layer in between us, and in that case,
[22:31] we don't need any client-side
[22:33] application also between us. We simply
[22:35] will see a database, query it, and get
[22:38] the results, right? In that case, what
[22:40] will happen? Each query have to be
[22:42] managed through the users only. And
[22:44] these queries, when I talk about large
[22:46] systems, let's say we are talking about
[22:48] LinkedIn, there can be multiple tables
[22:51] through which our data is curating and
[22:53] coming to us. Every user can't do it,
[22:56] right? That's why we have different
[22:58] layer in front of our database, which is
[23:00] our application code. So, in application
[23:02] code, what we do is we hide the
[23:04] complexity of dealing with databases,
[23:07] different tables, different documents,
[23:09] and we give the endpoints to our
[23:12] application or to the world so that they
[23:15] can access the kind of information they
[23:17] are looking for. For that, we create
[23:19] APIs or we can say we create endpoints.
[23:23] There can be multiple endpoints based on
[23:25] different features, based on different
[23:27] operations. So, through endpoints, we
[23:30] communicate to our application, which
[23:32] will again communicate to our databases
[23:35] to get the data we are trying to get.
[23:37] There can be various operations, like we
[23:39] can insert some data, we can update some
[23:41] data, we can retrieve some data, we can
[23:44] delete some data based on our request.
[23:47] So, the thing becomes little easier to
[23:49] us. Now, we don't have to deal with all
[23:52] the database tables, but now we have
[23:54] assigned endpoints through which we can
[23:56] do the work which we want to do. And
[23:58] endpoints are pretty simple.
[24:00] So, in order to get some data, we have a
[24:02] get endpoint. Let's say https, and here
[24:07] comes our Teleschool. So, this URL or
[24:10] this endpoint can be used to fetch all
[24:13] the students which are there in our
[24:15] Teleschool environment. But then, what
[24:17] we are doing? By introducing application
[24:19] code, we are moving our logic and data
[24:22] separately. That means we need some kind
[24:25] of connections between these two. In
[24:27] which we can connect through IP
[24:29] addresses, we can connect through some
[24:31] HTTP protocols, or we can connect
[24:33] through some TCP protocol. There are
[24:35] many ways of connecting the database
[24:38] from the application code and getting
[24:39] the data which we want. So, in order to
[24:41] show the APIs or in order to interact
[24:43] with the APIs, we have to know what is
[24:46] JSON and how we are going to send the
[24:49] data to our APIs and how we are going to
[24:51] fetch the data from our API.
[24:54] In this level also, if we know how to
[24:56] handle JSON, if we know how to handle
[24:59] various operations through which
[25:01] endpoint, it will make our life little
[25:03] easier than accessing the databases,
[25:05] right? So, in that case, we don't need a
[25:08] front end if we know how to hit the
[25:10] endpoints through which we'll get the
[25:12] data. But, for our normal users, for
[25:15] other users of any applications, this is
[25:17] also a tedious task. So, in order to
[25:20] make this easier, we have a different
[25:22] layer between our system that is our
[25:25] client application. Client applications
[25:27] are nothing but the applications through
[25:29] which we are interacting to the
[25:30] database, through which we are getting
[25:33] those databases. So, our client
[25:34] applications, be it a mobile
[25:37] application, be it any web application,
[25:39] be it any ATM machine for that matter,
[25:42] they are connected with the application
[25:44] code, and further, the data is being
[25:47] consumed by us. So, again, in order to
[25:49] connect the application layer and the
[25:51] client code, we again need some kind of
[25:54] communication between them. We either
[25:56] can go to the same HTTP or TCP or maybe
[26:00] IP. Now, we have our application ready
[26:02] in our hand and we can use it. So, if I
[26:04] draw it like we used to draw it, this is
[26:07] represented by our client, either a
[26:10] desktop or a mobile device. Now, they
[26:14] are sending queries to our application
[26:16] code, and our application code is
[26:18] further getting the data from database.
[26:21] Now, for our client to communicate with
[26:24] our application code, we need to put our
[26:26] application code on any server. And now,
[26:29] if we think about it, our application
[26:31] code is already exposing the APIs to our
[26:34] client. That means, it can also expose
[26:38] the APIs, or any other application can
[26:40] also use our application codes through
[26:44] our APIs and do the work which is
[26:46] needed. So, it can be connected to any
[26:49] other server also, which will contain
[26:51] their application code. And this will
[26:53] communicate with our data through our
[26:56] application code. For every query which
[26:58] we are making, we are going to our
[27:00] database, and from that we are getting
[27:02] the data which we are trying to get. So,
[27:04] if we think about it, most of the
[27:06] communications will start from the
[27:08] client side, and they will come to our
[27:10] application code through which we will
[27:12] get the data from the database. This is
[27:14] pretty much the easy application or the
[27:17] applications which we create on our
[27:18] college projects look like. Either a
[27:20] to-do application or a simple chatting
[27:22] application will look like this. Now, in
[27:24] the current scenario, what we are doing
[27:26] with this kind of architecture is every
[27:28] client is going to ask application code
[27:32] for some or the other information, and
[27:34] to fetch the data, our application code
[27:36] needs to get the data from the database
[27:38] only. We don't have any other option. In
[27:41] order to make the files accessible to
[27:43] our server faster, because the
[27:46] database's calls are heavy, which will
[27:48] take a lot of time, let's say, if a
[27:50] database query is finding the columns
[27:53] from 12 tables, it is going to take
[27:55] time, right? Now, in order to make the
[27:57] frequently used data accessible faster,
[28:01] we have a different layer, which is
[28:03] called cache. When we are going to put
[28:06] any data into our cache, and when we are
[28:09] supposed to remove the data. There are
[28:11] different strategies we are going to
[28:12] cover that also in the upcoming videos,
[28:15] but for now, let's see, this is our
[28:17] cache, and all the frequently used data
[28:20] will be stored here. So, that we don't
[28:22] have to call to our database, and they
[28:24] can be easily accessible through our
[28:26] cache only, which will make our process
[28:28] slightly faster. So, this is our fourth
[28:30] component of our system, which is cache.
[28:34] Now, let's move forward. Let's say our
[28:35] application is big, is having multiple
[28:38] servers. In that case, we may have some
[28:41] client or this client, either the mobile
[28:43] application or the web view, and we are
[28:46] getting the data from multiple servers.
[28:48] Let's say this is server one or this is
[28:51] server two. Now, when we have two
[28:53] servers or multiple servers, our client
[28:55] have to decide where to go. From where
[28:58] do we fetch the information? Now, in
[29:00] order to take this control, we have a
[29:02] load balancer in the middle, which will
[29:04] take care of each and every request and
[29:06] which will take care of each and every
[29:08] connections of the server. So, our load
[29:10] balancers are responsible for handling
[29:13] two tasks. First, they will check
[29:15] whether the server is healthy or not.
[29:17] And second one, they will divide the
[29:19] request for each servers equally. This
[29:22] is what our fifth component looks like.
[29:24] Now, let's come to our next component,
[29:26] which is messaging queue. So, in order
[29:29] to understand message queue, let's first
[29:31] understand that in order to process one
[29:33] operation, there can be multiple task
[29:35] into that operation, right? Let's say we
[29:38] are ordering something. So, when we are
[29:40] ordering, we are going to do multiple
[29:42] tasks, right? We are first creating an
[29:45] inventory update. Next is we are going
[29:47] to process the order also. We are going
[29:49] to talk to the vendor who is going to
[29:51] take the delivery. So, we are going to
[29:53] handle delivery. And then, we are also
[29:55] trying to send you the information, the
[29:57] notifications that your order is placed
[29:59] successfully. Don't worry about it. So,
[30:01] that means we are going to handle the
[30:02] mail service or the SMS service also.
[30:06] Now, in order to handle multiple
[30:08] services like this, we can't wait for
[30:10] every application to respond back. There
[30:12] are two kind of applications basically.
[30:15] First is, let's say this is an
[30:16] application and this is another
[30:17] application. Let's say this is SMS
[30:19] application and this is our order
[30:21] application or microservice for that
[30:24] matter. Now, whenever an order is
[30:26] placed, it is going to speak to the SMS
[30:28] service or SMS application to send the
[30:31] message to the user that your order is
[30:33] placed successfully. Now, there can be
[30:35] two ways of handling this. First way is,
[30:37] whenever the SMS is sent, they will
[30:40] notify the order service or the order
[30:43] application back that we have sent your
[30:44] message done. Or there can be different
[30:47] way of handling it that from our order
[30:49] service, we simply say that okay, this
[30:52] is our order information. Please send
[30:54] the message to this number and we are
[30:56] done. We will not wait for the response.
[30:59] We will move forward with our
[31:00] application and with different orders.
[31:03] So, the kind of requests in which we are
[31:05] waiting for any confirmation or any
[31:07] feedback from the other service are
[31:09] called synchronous calls. And the kind
[31:11] of service in which we will simply put
[31:13] down the service and we are not waiting
[31:15] for any confirmation, we will move
[31:16] forward to do our task. Those are called
[31:18] asynchronous services. Don't worry about
[31:21] this if you don't understand it now. We
[31:22] are going to dissect each and every
[31:24] component in details in the further
[31:26] coming videos. So, for asynchronous kind
[31:29] of services, what we can do, we can
[31:30] simply push our notification or push our
[31:32] request to another service and move
[31:35] forward. So, in those kinds of services,
[31:37] we have a message queue or message
[31:40] broker in middle. What it will do, we
[31:42] are having our order service here. It
[31:45] will put multiple request or can put a
[31:48] request time to time into this message
[31:51] queue. And then all the requests which
[31:54] our order is processing through message
[31:55] queue, they will not take care of it
[31:57] anymore. Our message queues will take
[32:00] care of it. They will connect with our
[32:02] SMS service or SMS applications and send
[32:06] the request one by one. And they will
[32:08] take care of these all operations. So,
[32:10] our message queue is like a broker who
[32:13] will take the request from one
[32:14] application, store inside it. They will
[32:17] take care of these applications. They
[32:19] will take care of the retries or if any
[32:22] request is failing, they will take care
[32:23] of it. Maybe they will communicate to
[32:26] our order application in the end or in
[32:28] the end of each day, we will send some
[32:31] notification, some batch processes to
[32:34] our order application in order to show
[32:37] that which requests are fulfilled and
[32:39] which are not fulfilled. So, in short,
[32:41] our messages queues are doing two work
[32:44] here. They are storing each and every
[32:46] request which are coming from various
[32:48] other services or various other
[32:50] applications for that matter. They are
[32:52] storing it and they are taking care of
[32:54] those requests. They are sending those
[32:57] requests finally to SMS application or
[32:59] service and they are taking charge that
[33:01] okay, my first service or my first
[33:04] request is being processed. Nice. Now, I
[33:07] will send the next request. Now, I will
[33:09] send the next request and further on. If
[33:11] it is failed, there are various
[33:12] mechanisms how messages queues work and
[33:15] how they bisect and dissect each and
[33:17] every request and make sure that they
[33:20] will provide the latest status of each
[33:22] request. And in those kinds of
[33:24] environment where we have multiple
[33:25] microservices, in those cases message
[33:28] queues plays a vital role in between
[33:30] them. And with that, let's move to our
[33:32] final component which is monitoring and
[33:35] logs. In monitoring and logs, what do we
[33:37] do? As we know now, we have different
[33:39] components in our architecture, we have
[33:42] a client system here.
[33:43] We may have a mobile application again
[33:46] which is connecting through an API to
[33:49] our load balancer
[33:50] which is again further connected to
[33:52] either server one or server two.
[33:55] Our servers are the area in which we
[33:58] have our application code and then they
[34:01] may be connected to single database or
[34:03] multiple databases and those databases
[34:06] can also communicate with each other in
[34:08] order to maintain the data. And also,
[34:10] let's say our application is also using
[34:12] some third-party application for which
[34:14] we are using message queues. Our message
[34:17] queues are denoted by this. Now, this is
[34:19] our architecture. We have so many
[34:21] components.
[34:22] So, it is very important for us to
[34:24] monitor those components. To monitor
[34:27] whether our load balancer is working
[34:29] finely or not. To manage whether our
[34:32] application code does have any error or
[34:34] not. And if there is an error, we need
[34:37] to know how to solve it. We need to know
[34:39] the complete stack trace of that
[34:41] particular error. We need to know how to
[34:43] reproduce those errors on our local
[34:45] system in order to fix them. And also,
[34:48] while working with the applications, we
[34:49] know that for every each and now, we
[34:52] have multiple features which are being
[34:54] attached to our applications. So, we
[34:56] also need to monitor while adding one
[34:58] more feature to our application, whether
[35:00] any other feature is impacted or not, or
[35:03] it is failing or not. So, in order to do
[35:06] that, we have a lot of monitoring tools
[35:08] and also logs to check our system. There
[35:11] is a complete testing department in our
[35:13] team also, who takes care of these
[35:15] things. This is one of the vital role in
[35:18] our application. So, these are most of
[35:20] the common components which are used in
[35:21] system design. Whenever we think about
[35:24] any application or designing any
[35:25] application, we suddenly jump to the
[35:27] tools which are used in that
[35:29] application. We start creating diagrams
[35:31] that this is our client, this is our
[35:33] database, this is how our data is going
[35:35] to flow, this is how we add cache maybe.
[35:38] So, these all things we start doing
[35:40] without noticing a single thing, that
[35:42] is, how is our application going to
[35:45] work?
[35:46] What is this application? What are the
[35:48] limitations of this application? In
[35:50] system design, there is a smart way of
[35:52] doing that. First question you need to
[35:54] ask yourself before diving into the
[35:57] solutions is, what is this application?
[36:00] What is the type of this application? Is
[36:03] it a data intensive application or a
[36:05] compute intensive application? With this
[36:08] common differentiation, you will be able
[36:10] to save a lot of cost to your system
[36:12] design, as well as you will be able to
[36:15] handle the task properly into your
[36:17] system. Let's say, we have two
[36:20] applications. In both of these
[36:22] application, there are the same number
[36:25] of users. With that, the network on
[36:27] which both of the applications are
[36:29] working are also pretty much same. Now,
[36:32] let's put a scenario that our system or
[36:34] the application which we are working on
[36:36] is facing latency. Now, what is latency?
[36:40] Latency means our system is taking time
[36:42] to respond. There are various ways of
[36:44] handling this issue, of fixing the
[36:47] latency issue. We can add multiple
[36:49] databases, we can add different caching
[36:51] layers, we can update the caching
[36:52] mechanism, or we can update
[36:55] or the CPU powers. Now, on which vector
[36:58] we are going to do this changes defines
[37:00] how well we are going to solve this
[37:02] issue. So, now there are two type of
[37:04] applications as I discussed. One is data
[37:06] intensive application and one is compute
[37:09] intensive application. Let's understand
[37:11] them one by one. The basic difference on
[37:14] which data intensive application is
[37:16] different from a compute intensive
[37:17] application is that in data intensive
[37:20] application our core focus is on data.
[37:23] Now, for this data we need to have
[37:25] multiple operations, right? We need to
[37:26] store the data, plus we need to gather
[37:29] the data, we need to move the data time
[37:31] to time. That means we need to keep
[37:33] updating the data because new data is
[37:35] entering. And also, while new data is
[37:38] entering we can also, right, we need to
[37:39] add a lot of data.
[37:41] We can take example of any application
[37:43] which can be Instagram because on
[37:45] Instagram we see a lot of content and we
[37:48] post a lot of content. So, that is a
[37:50] data intensive application where the
[37:52] primary focus is on gathering the data,
[37:55] is on showing the data, is on the data
[37:57] you are posting. But, the focus is not
[37:59] on how the data will be calculated. The
[38:01] calculation part is pretty solid. We
[38:03] just need to move the data from our
[38:05] databases to the client applications and
[38:07] we are sorted. So, in these kind of
[38:09] systems the data mainly resides in the
[38:12] database. So, first issue can be the
[38:16] database response is low. Another is,
[38:18] since we are using network calls here
[38:20] and there, that means our network calls
[38:23] are also bulky or we need to optimize
[38:25] them. The third can be our server itself
[38:27] that our server configuration is pretty
[38:29] low, that's why we are not able to get
[38:31] the data faster. So, all in all, in
[38:34] data-intensive applications, we are not
[38:35] blaming the client to upgrade their CPU,
[38:38] we are blaming our circle, our database
[38:41] calls, our network calls, our server
[38:43] configuration in order to get the data
[38:45] fast. Most of the applications in which
[38:48] you work on are data-intensive
[38:50] application. That's why we use terms
[38:52] like cache enhancement, shredding, and
[38:55] through all of those things we will be
[38:56] able to solve this issue. Now, let me
[38:58] also write some common examples of this.
[39:00] So, the common examples here are
[39:02] Instagram feed where we see a lot of
[39:04] data as we discussed earlier. In
[39:06] WhatsApp messages also, there is a high
[39:08] amount of data because we are not only
[39:10] taking care of one chat, we are taking
[39:12] care of entire chat. The count of chats
[39:15] or the count of messages WhatsApp deal
[39:17] with is around 2 to 10 million messages
[39:20] per day. So, this is also a heavy
[39:23] data-intensive application. Now, there
[39:26] are bank transactions, analytic
[39:28] dashboard, and log process system as
[39:30] well. In all these application, the
[39:32] primary goal is to serve the data from
[39:35] database to our client system faster.
[39:37] There is not much calculation required
[39:40] for them to show on the client machine.
[39:42] Now, based on the data-intensive
[39:43] application, what are the worries of a
[39:46] data-intensive application? The first
[39:48] worry is how fast can we read the data?
[39:51] The second point is how safely are we
[39:54] going to store the data? The third
[39:56] point, as we all know, a lot of users
[39:58] are using our application, so how many
[40:00] users can use the same data
[40:02] simultaneously? The next and one of the
[40:05] most important worry of these kind of
[40:07] application is what if any server dies?
[40:10] What if any server breaks? What if any
[40:13] network call breaks? What if any
[40:15] database machine breaks down? So, in
[40:18] those cases, how we are going to handle
[40:20] the data? So, these are the most common
[40:22] worries of the data intensive
[40:24] applications. And now, in order to solve
[40:26] them, we don't go to our client system.
[40:29] We talk about the components on which
[40:32] these processes lies. And those are our
[40:35] databases, caching, replication, maybe
[40:38] data sharding, or it can be solved
[40:41] through data consistency. So, these are
[40:43] all the components or the terms we use
[40:46] in order to improve our data intensive
[40:48] application. Don't worry about these
[40:50] terms if you don't know them yet. We are
[40:52] going to cover each and every component
[40:54] in details in the coming videos. So, I
[40:56] hope data intensive applications are
[40:58] pretty clear up to now. But, for the
[41:00] sake of example, we are also going to
[41:02] take one more example. Now, think about
[41:04] Instagram feed. We are not solving
[41:06] Instagram feed issue through any
[41:09] mathematical equations. We just have to
[41:11] gather a lot of data and show you that
[41:13] data. So, what we don't do here, we
[41:16] don't do any complex maths. What we do
[41:18] then? We normally fetch the posts. After
[41:21] fetching the post, we sort them through
[41:24] time or relevance. We show a lot of
[41:26] images or videos. And according to those
[41:29] content, we normally do some operations,
[41:33] maybe like or commenting or sharing. So,
[41:36] I'm writing that. So, this is all the
[41:38] operations loosely we have on the
[41:41] Instagram feed. Now, what is the common
[41:43] challenge which Instagram is facing
[41:45] daily? That is we we have a lot of
[41:48] content. We have millions of users and
[41:51] million of content which we have to
[41:53] handle. So, let me write that down. In
[41:55] other words, we can also say that
[41:57] million of users are reading and writing
[42:00] at the same time. So, with this
[42:01] challenge, Instagram still needs to
[42:03] scale, right? How does Instagram scale?
[42:06] If we think about this, Instagram adds
[42:09] multiple databases in order to store the
[42:11] data. And also, Instagram uses
[42:13] aggressive caching in order to store or
[42:16] get the data fast. Now, we also know
[42:18] that Instagram heavily depends on the
[42:20] images and the video content form. So,
[42:23] in order to handle them, we can't simply
[42:25] store those kind of data into our
[42:27] databases directly. For that, in order
[42:29] to fetch them faster, we need to have
[42:32] certain CDN in place. And in databases,
[42:35] we will only store the location of that
[42:36] particular file which we are going to
[42:38] fetch through the CDN. Now, think about
[42:40] this. In order to fix the latency issue
[42:43] on Instagram or in order to help
[42:45] Instagram scale, we hardly touch the CPU
[42:48] or we hardly touch any GPU. We only
[42:51] touch the data or the components which
[42:54] are associated with them. Because the
[42:56] issue here is not the CPU, but the data
[42:59] movements between the components. Now,
[43:01] this is all about data-intensive
[43:03] applications. Let's now focus on the
[43:05] compute-intensive applications. Now, the
[43:07] compute-intensive application is exactly
[43:10] opposite of a data-intensive
[43:12] application. Here, the amount of data
[43:14] which we are retrieving from databases
[43:16] are pretty much low, but the
[43:18] calculations we need to perform are
[43:20] really heavy. So, instead of putting our
[43:22] focus on database caching, replication,
[43:26] sharding maybe, we move our focus from
[43:28] there to CPU and GPUs. So, let me write
[43:31] down the challenge now. So, we can
[43:33] safely say that here our systems are
[43:36] compute-bound or we can say CPU or
[43:39] GPU-bound. Let me take some examples of
[43:41] this. The most common example can be
[43:44] image processing, video rendering. The
[43:46] machine learning model training can also
[43:48] be a good example of this. Also, we can
[43:51] talk about simulation and cryptography.
[43:54] Now, in all these examples, the data
[43:56] which we are getting from the database
[43:58] are in a smaller level only, but the
[44:01] kind of processing we need to do in
[44:02] order to show these data to user is
[44:05] heavy. That's why they come under the
[44:07] category of compute intensive
[44:09] applications. Now, let's discuss about
[44:11] the worries of a computer intensive
[44:13] application. The first worry is pretty
[44:15] simple, that is how fast can we do the
[44:18] calculation or how fast can we compute?
[44:20] The second worry can be can we do
[44:22] something some processes in parallel in
[44:25] order to show the data faster to the
[44:27] user. You may have seen a lot of systems
[44:29] in which in parallel the image is being
[44:32] processed and you are able to move
[44:34] further with the application. Let the
[44:36] image process and the meanwhile you are
[44:38] moving to the other features of the
[44:40] application. The next issue can be how
[44:42] can we reduce the computational cost?
[44:46] And also as a system designer, we can
[44:48] also think about can we use GPU instead
[44:51] of CPU? So, these are the common worries
[44:54] of a computer intensive application
[44:56] where the data is not much, but the
[44:59] processing is the king. Let me also take
[45:02] a good example of a computer intensive
[45:04] application. So, in order to create a
[45:07] simulator machine, it is very important
[45:09] for the simulator to work exactly how
[45:12] the actual machine works. So, think
[45:15] about a scenario that our country is
[45:17] hiring a lot of pilots every year and we
[45:20] can't spend too much on the actual
[45:23] aircrafts when the pilot doesn't know
[45:25] how to ride it or how to fly it.
[45:28] In order to train them, we need to give
[45:31] them simulators machines and on which
[45:34] they train themself first and then sit
[45:36] on the actual plane. So, now in
[45:38] simulation machine, our common worries
[45:41] or the task which we are going to have
[45:43] is can we do anything in parallel again?
[45:46] Can we use GPU instead of CPU? Again,
[45:49] how can we reduce the cost of our
[45:50] simulator? Also, we need to find a way
[45:53] to gather a lot of good algorithms in
[45:56] order to do the task frequently. Now, at
[45:59] this point I think we are very clear on
[46:01] how our data intensive applications are
[46:03] different from computer intensive
[46:05] applications and why we need to put our
[46:08] focus on computation on different
[46:10] algorithms on GPU or CPU in order to
[46:13] make a computer intensive application
[46:15] works because the data is very low and
[46:17] in data intensive application if we
[46:19] start focusing on GPU and CPU there will
[46:22] not be any big changes because the issue
[46:25] lies in the database network calls
[46:27] caching algorithms or maybe server. So
[46:30] in order to fix them we need to put our
[46:33] effort into the right category into the
[46:35] right components so that our application
[46:38] works seamlessly. And why this is
[46:39] important? Because if we put our efforts
[46:43] into the wrong components our components
[46:45] are not free they are going to cost us
[46:47] money and if we put the money in the
[46:50] wrong place and not getting any help in
[46:52] order to solve our issue it is going to
[46:55] be a bad system design for the entire
[46:57] game. Now when we talk about data
[46:59] intensive or computer intensive
[47:00] applications we often think that these
[47:03] two are very separate applications. But
[47:05] in today's time we live in the
[47:07] environment of multiple applications and
[47:10] each application performs multiple
[47:12] tasks. So that means our data
[47:14] intensiveness or the computer
[47:16] intensiveness of the application can
[47:18] also depend on the feature we are
[47:20] working in. For example we have YouTube
[47:22] right? YouTube is data intensive for
[47:25] serving the videos. There are a lot of
[47:28] videos in YouTube environment and you
[47:30] get the videos and we can say that it is
[47:33] computer intensive when it comes to the
[47:35] recommendation. Because in order to get
[47:38] the recommendations we have to get what
[47:40] you are watching right now. So I think
[47:42] it is pretty sorted now that in order to
[47:44] fix a particular issue you need to first
[47:47] think whether the issue which we are
[47:49] facing is computer intensive or data
[47:52] intensive and then you get into the
[47:54] components and fix that. There is a
[47:56] trick to understand whether the feature
[47:58] is data intensive or compute intensive.
[48:00] That is, if the time is lost in data
[48:03] movement, probably it is data intensive
[48:05] application. Or if the time is lost in
[48:08] the computation, it is probably a
[48:10] compute intensive feature or the task.
[48:13] This one distinctions save you a lot of
[48:15] money, time, and complexity. In order to
[48:19] discuss our requirements, we divide the
[48:20] requirements into two categories. One is
[48:23] functional requirement and the another
[48:25] one is non-functional requirement. So,
[48:27] let's go to our screen and let's discuss
[48:29] this. Functional requirement says,
[48:31] "Please define all the points which you
[48:33] are building, all the features which you
[48:35] are building, all the working which you
[48:37] are building." That means, if we define
[48:40] every feature that comes under the
[48:42] functional requirement. So, let's
[48:44] understand functional requirement by
[48:45] taking an example of any e-commerce
[48:48] application, let's say Amazon. So, what
[48:51] can be the functional requirements of
[48:53] Amazon application? That means, we are
[48:55] defining each and every feature which we
[48:57] see on Amazon. So, let's say on Amazon
[48:59] application, a user can register
[49:02] themself. User should also be able to
[49:04] log in. So, let's write that. After
[49:07] login, user should be able to see the
[49:08] products. Also, user can search the
[49:11] products or filter them. Let's write the
[49:13] searching and filtering into two parts.
[49:15] So, search the products and user
[49:18] can also filter the products. After
[49:20] filtering, searching, user should be
[49:22] able to add any product to the cart.
[49:24] After adding any product to the cart,
[49:26] user should be able to get some
[49:28] promotions or get some discounts, right?
[49:30] So, they should be able to apply the
[49:32] coupon codes to get the discount. And
[49:34] once all this done, user should be able
[49:36] to place the order. After placing the
[49:39] order, user should be able to do the
[49:40] payments, maybe. And once the item is
[49:43] placed, once the order is placed, user
[49:45] should be able to track that order. So,
[49:47] all of these points are the functional
[49:49] requirements of Amazon or any e-commerce
[49:52] application for that matter. In which we
[49:55] define all the functionalities, all the
[49:57] actions which user can take, all the
[49:59] working of the application is defined
[50:01] under functional requirement. So, if we
[50:04] have to write this, what is functional
[50:05] requirement again? Functional
[50:07] requirements means all the features
[50:09] which you are going to have in your
[50:10] application are the functional
[50:12] requirements. Now, let's move forward to
[50:14] the non-functional requirements. For
[50:17] non-functional requirements also, let's
[50:18] start with the example of Amazon only.
[50:21] Let's say the first non-functional
[50:23] requirement is that on our Amazon site,
[50:26] we have
[50:27] approximately 1 million users. So, that
[50:30] means our system should be able to
[50:32] handle 1 million daily active users.
[50:35] Now, in order to give our users a good
[50:37] experience, we can say that the response
[50:40] time should be less. But, in
[50:42] non-functional requirements, we have to
[50:43] define how less.
[50:46] So, let's say for Amazon application,
[50:48] the response time should be less than
[50:51] 200 milliseconds for each request. Now,
[50:54] our application is built and is running,
[50:56] that means our application can't handle
[50:58] failure. But, that is not possible,
[51:00] right? So, we should define up to how
[51:03] much is our availability of our system.
[51:05] That means for how much time our system
[51:08] will be available. That are defined
[51:10] under SLAs and SLOs. So, we have to
[51:13] define them. That for 1 year, our system
[51:16] downtime should be this much amount
[51:18] only. And for 99.9%
[51:21] time, our system should be up. That is
[51:23] defined under availability. After
[51:26] availability, we don't want our data to
[51:28] be flowing easily, so we want to encrypt
[51:30] our data. And let's say on any sale day,
[51:34] let's say Black Friday sale or Diwali
[51:36] sale or Holi sale, in those times our
[51:39] normal users can go up to 10x. So, our
[51:42] system should be able to handle that
[51:44] much traffic also. So, let's write that
[51:46] down. With this, our system should be
[51:48] also able to handle the faults. Because
[51:51] there are going to be faults in the
[51:53] system. No application is perfect so
[51:55] far. Every system have their own faults,
[51:58] have their own downtime. But we need to
[52:00] see how can we track them and how can we
[52:03] fix them as fast as possible. So, that
[52:05] is we need to make our system fault
[52:08] tolerant. So, with this example of
[52:10] Amazon, we get to know that our
[52:12] functional requirement are the features
[52:14] of the system that we can say what our
[52:18] system is going to do. And with
[52:20] non-functional requirements, we define
[52:22] how our system is going to perform. So,
[52:25] these are the specific non-functional
[52:27] requirements for Amazon. If we have to
[52:30] write it in a generic way, there are
[52:32] some generic terms which we can write.
[52:34] So, we can talk about scalability. Let's
[52:37] say our current configuration of server
[52:39] is reaching to a point where it is not
[52:41] able to handle the kind of traffic it is
[52:43] getting. So, now in order to scale, will
[52:46] you scale it horizontally or vertically?
[52:49] That will be taken care under
[52:51] non-functional requirements. Apart from
[52:53] that, as we have discussed, availability
[52:55] of every system will be defined under
[52:57] the non-functional. As we have already
[52:58] discussed, that means our system uptime
[53:02] will be calculated here.
[53:04] Which is defined under SLAs and SLOs.
[53:08] So, in these agreements, it is already
[53:10] defined that, let's say we are using
[53:12] Amazon server in order to deploy our
[53:14] application, then Amazon will give us
[53:17] some contract that we will be down up to
[53:19] this time. And apart from that, you will
[53:22] not see any issues. Now, in those cases,
[53:24] if we see any issues, let's say for a
[53:27] day, Amazon says that we will be down
[53:30] maybe for 5 minutes maximum. But then,
[53:32] if Amazon fails to keep that promise or
[53:35] that agreement, the companies which are
[53:37] using the Amazon service can sue them.
[53:40] Because the Amazon services have given
[53:42] us the SLA's in writing that the
[53:45] services will not be down after certain
[53:47] point. So, availability plays a huge
[53:49] concern there. Next, we have
[53:51] reliability. In reliability, we can say
[53:54] that our system should be reliable. That
[53:56] means there should be no data loss in
[53:58] our system. After reliability, comes the
[54:01] performance. Under performance, we are
[54:03] going to define how our system is going
[54:05] to work, how much latency can we feel in
[54:08] the system. What is our P95? What is our
[54:11] P90? What is our P99? These all things
[54:15] are defined under performance. So, all
[54:17] the words which I have said in this
[54:19] particular video, we are going to cover
[54:21] each and every topic in details in the
[54:23] coming videos. So, don't worry about
[54:25] this if you don't get it now. After
[54:27] performance, we can jump to security. In
[54:29] security, we can have features like
[54:31] authentication, authorization, and
[54:34] encryption. With security, we are also
[54:37] dealing with a lot of code. That means
[54:39] we can say our code should be in perfect
[54:41] modules so that each code or each chunk
[54:44] of code can use different APIs or
[54:47] different modules in order to work in
[54:48] efficient way. After this, we have last
[54:51] but not the least requirement, that is
[54:53] observability. Even if our code is
[54:56] pushed to production, there are a lot of
[54:57] use cases which are handled after that.
[55:00] Because we don't know the exact behavior
[55:02] of users, that how they are going to use
[55:05] it. So, we need to keep track of all the
[55:07] monitoring tools, all the tools which
[55:09] are going to track the user behavior on
[55:11] our application. So that we can improve
[55:14] our system and also we will be able to
[55:16] track if there are any bugs and solve
[55:18] them. So, let me write monitoring and
[55:20] logging. So, this is all about
[55:22] functional and non-functional
[55:24] requirements. I hope you all get it. But
[55:27] in order to completely get it, we all go
[55:29] through a lot of applications on a
[55:31] day-to-day basis, right? We may be
[55:32] scrolling through Instagram, maybe
[55:34] watching YouTube, maybe watching
[55:35] Netflix, or Amazon Prime, or purchasing
[55:38] anything from Flipkart, Amazon, or any
[55:40] other application e-commerce platform,
[55:42] or we may be scrolling through our
[55:44] WhatsApp messages. Now, I want you,
[55:47] while using your application, just sit
[55:49] back for a few minutes and think about
[55:51] all the functional features which you
[55:53] are working, or all the functional
[55:55] requirements which you are using, and
[55:58] all the non-functional requirements
[55:59] which the app must have configured or
[56:02] thought of while creating that
[56:03] applications. Also, comment down the
[56:05] application on which you worked on, and
[56:08] write down three to four functional and
[56:10] non-functional requirements. That will
[56:12] help you and me also in order to
[56:14] understand that we are learning on a
[56:16] similar pace.
[56:17] How does our browser know which webpage
[56:20] to hit? Do they know by domain name, or
[56:22] do they get these things through IP
[56:24] addresses?
[56:25] Let's find out. So, whenever on our
[56:28] browser or on our machine, whenever we
[56:31] write any address, let's say
[56:33] telesco.com, it is going to redirect us
[56:36] to the telesco page, which is our
[56:39] homepage. Maybe some banners here, maybe
[56:41] some courses section here.
[56:44] It is like this only. Now, how do our
[56:47] browser figure out which page to show?
[56:50] Because, as humans, we communicate
[56:52] through names, but systems don't
[56:54] communicate through names. In order to
[56:56] establish the communication between one
[56:58] system to another system, we need IP
[57:01] addresses. So, that means there should
[57:03] be some place in between or some system
[57:05] in between our browser or our OS through
[57:09] which we are going to get the correct IP
[57:11] addresses of each and every site. So, we
[57:15] will send telesco.com, and in return we
[57:18] will get some IP addresses. So, this can
[57:20] be the IP address of telesco. I'm not
[57:22] exactly sure about the IP address, but
[57:24] yeah. Like this, our DNS works.
[57:27] So, DNS basically stands for domain name
[57:31] system. Domain means any specific URL or
[57:34] any specific domain. Domain is this
[57:36] only, telesco.com. There can be multiple
[57:39] domains, telesco.net, google.com,
[57:42] facebook.com, whatsapp.com, .web I
[57:44] think. But yeah, you get the point.
[57:46] These all things are domain. And what is
[57:48] subdomain? If I write any subdomain,
[57:51] let's say docs.telesco.com
[57:55] or any other subdomain, let's say
[57:57] course. So, they both are subdomains of
[58:00] telesco.com. Where telesco.com acts as
[58:03] an umbrella and under which we can
[58:05] create multiple subdomains if and when
[58:08] required. So, these are the domain and
[58:10] subdomains. But mind it, the machines,
[58:13] the computers doesn't communicate with
[58:15] each other through these domain names.
[58:17] So, they need IP addresses. Let's figure
[58:20] out ways on which our system can handle
[58:22] the IP addresses. Let's say we are
[58:24] building a browser. Why do we need DNS?
[58:27] Why do we need another system
[58:30] for maintaining the domains? We can
[58:32] basically install or store all the
[58:35] domain name list on our browser only.
[58:37] Now, is this even possible? Let's say if
[58:41] we have only two or three websites,
[58:43] maybe 10 websites, we can store their
[58:45] names, even 100 also. But the current
[58:48] number of domains which exist in our
[58:50] world is more than 350 million. And as a
[58:53] browser, browser doesn't know which
[58:56] sites I'm going to use, whether I'm
[58:57] going to use Stack Overflow one day and
[58:59] Gmail the other. So, we can't store all
[59:02] the 350 plus domains into our browser.
[59:05] That will crash our system. So, two
[59:07] reasons because of which we can't store
[59:09] the entire domain list on our browser
[59:12] are first thing is it will get heavier.
[59:15] And to store such amount of information,
[59:17] we need a high storage browser. So, that
[59:20] will also impact the performance of the
[59:21] system. Now, the other point is what if
[59:25] the IP changes after some time? What if,
[59:28] let's say, I am running any site,
[59:30] teleschool.com, I have purchased my
[59:33] domain from maybe GoDaddy, and tomorrow
[59:35] I decide to discontinue my service from
[59:37] GoDaddy, and I'll move to Google
[59:40] Domains. So, I'll purchase or renew the
[59:42] domain from there. In that case, my IP
[59:46] can be changed. And if it restores, I
[59:48] need to reassure that in all the
[59:50] browsers where teleschool.com is
[59:52] running, I need to update them. I need
[59:55] to send them some update. So, through
[59:57] this we can estimate that it can't be
[59:58] stored in one browser. And also, it
[01:00:01] can't be stored in a single server,
[01:00:03] also, because it will also get heavier.
[01:00:05] There are more than 350 million domains.
[01:00:07] That means, if we are going to store it
[01:00:09] in a tabular manner, so the here will be
[01:00:11] the domain name, and the corresponding
[01:00:14] IP addresses accordingly. So, here we
[01:00:16] will have any domain name such as
[01:00:18] google.com, and here we will have the IP
[01:00:20] address, 1.2.3.4,
[01:00:23] for example.
[01:00:24] So, by this, we will create the entire
[01:00:26] list. This is not possible for a single
[01:00:28] machine to handle, because if that
[01:00:30] machine breaks, then the entire system,
[01:00:33] the entire internet will break. Anyone
[01:00:35] in the world will not be able to use any
[01:00:38] internet services or any web pages for
[01:00:40] that matter. No APIs will hit, because
[01:00:43] it all depends on the DNS. So, one thing
[01:00:46] is sure, we need a certain kind of
[01:00:47] system in order to fulfill this
[01:00:49] requirement. That's why we have one of
[01:00:51] the most beautifully designed system,
[01:00:53] DNS. Let's start from the high level.
[01:00:56] So, this is our machine, which is going
[01:00:58] to use some internet service provider,
[01:01:01] and under this service provider, we have
[01:01:03] something called as DNS resolver. So,
[01:01:05] this DNS resolver is responsible for us
[01:01:08] to getting the correct IP of any
[01:01:11] websites or any domain which we are
[01:01:13] trying to process. In order to
[01:01:15] understand this clearly, let me take
[01:01:16] this and put it in a side, so that I can
[01:01:19] draw more things onto our screen. So,
[01:01:22] the first call it is going to make is to
[01:01:26] our root server. Now, there are 13 root
[01:01:29] servers
[01:01:30] in this entire world. That means there
[01:01:33] are 13 companies who own 13 web servers
[01:01:37] in this entire world. They are not
[01:01:39] physically 13, but they are categorized
[01:01:41] into 13. So, that means out of these 13,
[01:01:44] we are going to hit one of them and get
[01:01:46] the response. These root servers are
[01:01:48] typically named from A to M like this.
[01:01:51] Again, from this A to M, they are owned
[01:01:55] from various companies. So, you can see
[01:01:57] the complete list of the root servers
[01:01:58] with the companies which own that root
[01:02:01] servers on the screen. You don't have to
[01:02:03] remember all of them. You just have to
[01:02:05] see and understand that these are the
[01:02:07] service providers of the root servers
[01:02:09] from which we are going to get some
[01:02:11] information in order to process our
[01:02:13] domain. Now, let's come back to screen.
[01:02:16] As discussed, we were searching for
[01:02:18] telesco.com. Also, I can remove this
[01:02:21] now. Now, when we are searching for
[01:02:23] telesco.com, the root server doesn't
[01:02:25] know anything about telesco.com, but it
[01:02:28] knows about the TLDs which are top level
[01:02:31] domains. What is top level domain? If I
[01:02:34] talk about .com,
[01:02:37] this is our top level domain. .com,
[01:02:40] .net, .gov, .in, .uk, .us, .education
[01:02:46] maybe .edu, we use them. These all
[01:02:49] domains are the top level domains of any
[01:02:51] website. So, that means if we need to
[01:02:53] find out where telesco.com is, we first
[01:02:56] need to know which server is handling
[01:02:58] all the .coms. So, in order to do that,
[01:03:01] our root server will give the response
[01:03:04] that okay, you can go to one of the TLDs
[01:03:07] which is handling the top level domain
[01:03:10] for .com and the root server will return
[01:03:12] the IP address of that. Maybe this is
[01:03:14] the IP address and from now, we know
[01:03:17] that we are going to hit any TLD,
[01:03:20] top-level domain for a .com. Now, from
[01:03:23] this TLD, we are again not going to get
[01:03:26] the complete IP address of the site. We
[01:03:29] are going to get the proper server or
[01:03:32] the name server or the authoritative
[01:03:34] servers which are managing the all the
[01:03:36] IP addresses for our domains. Let's say
[01:03:39] this is the IP address of our
[01:03:41] authoritative name server. And from
[01:03:43] this, we are going to make another call
[01:03:45] which are our authoritative name
[01:03:47] servers. And from here, we are going to
[01:03:50] actually get where our telesco.com
[01:03:53] resides, the IP address, which was
[01:03:55] 19283841.
[01:03:57] And once this is captured through our
[01:04:00] browser, the IP, then it is going to
[01:04:03] make the call to telesco.com server and
[01:04:06] it is going to get the web page which is
[01:04:08] desired for. I get it this can be a
[01:04:10] little confusing at start, so let me
[01:04:11] reiterate it for once.
[01:04:13] So, whenever we click on any site,
[01:04:16] whenever we want to find any site, let
[01:04:18] it be telesco.com, it is first going to
[01:04:21] our service provider, internet service
[01:04:24] provider. Also, you can see uh
[01:04:27] it can go through router and router can
[01:04:29] also have DNS resolver. So, from
[01:04:32] internet service provider which have DNS
[01:04:34] resolver, this component is going to
[01:04:37] resolve all our queries for us and
[01:04:39] ultimately will give us a perfectly fine
[01:04:42] working IP address for telesco.com or
[01:04:45] any other site for that matter. So, the
[01:04:48] first step is it will go to the root
[01:04:50] servers. What is root servers? There are
[01:04:53] 13 companies who own these root servers
[01:04:57] who doesn't know the IP address of your
[01:04:59] site directly, but knows which TLD to
[01:05:02] follow. So, from root server, it is
[01:05:05] going to check what is your
[01:05:08] TLD, top-level domain. And in this case,
[01:05:11] it is .com. Now, as it is dot com it is
[01:05:14] going to get the IP address of the TLD
[01:05:17] which is handling the dot com domain. So
[01:05:20] after this first call now we are going
[01:05:22] to call the TLD which we get from the
[01:05:24] root server and from this also we are
[01:05:27] not going to get the complete IP address
[01:05:29] of telesco. We are going to get on which
[01:05:32] name server we are going to hit to get
[01:05:34] the complete IP address of telesco.com.
[01:05:37] So from here we are going to get the
[01:05:39] authoritative name servers IP and
[01:05:42] accordingly we are going to hit our
[01:05:44] third and final call to our
[01:05:46] authoritative name servers. Our
[01:05:48] authoritative name servers are mostly
[01:05:51] can be configured in GoDaddy or
[01:05:53] Hostinger or any other service providers
[01:05:56] in your current application. And from
[01:05:58] these authoritative name servers we are
[01:06:01] going to get the IP address of
[01:06:03] telesco.com. Now in order to click one
[01:06:06] side we have to do these three
[01:06:08] operations. This can be heavy, right? So
[01:06:11] this is only done first time and the
[01:06:13] next time when you click on anything it
[01:06:16] basically takes the value from cache.
[01:06:18] Now cache can be stored in three
[01:06:20] locations here or more than three if you
[01:06:22] think about it, but three are definite
[01:06:25] locations. The first is the DNS resolver
[01:06:28] can have the cache to have all the
[01:06:31] common IP addresses which we are going
[01:06:33] to take or the all the common domains
[01:06:35] which we are trying to hit. It can store
[01:06:38] it here. Also on our system we have two
[01:06:41] things. One is OS and one is browser. In
[01:06:44] both of these areas we can basically add
[01:06:46] that domain and the IP address in order
[01:06:49] to get the details fast. So browser also
[01:06:52] maintain that cache OS level also we can
[01:06:55] basically maintain the cache and on our
[01:06:58] DNS resolver site also a cache is
[01:07:00] maintained in order to get the details
[01:07:03] fast. Now when we are at this topic let
[01:07:05] me tell you about one more thing, that
[01:07:07] whenever we create domain name systems
[01:07:09] like this dogs or subdomains, these all
[01:07:13] entirely creates a zone
[01:07:15] in the authoritative name server. That
[01:07:18] means telesco.com including all the
[01:07:21] subdomains. So, one zone can contain
[01:07:23] multiple domain list, which will include
[01:07:26] only the domains specifically to that
[01:07:29] particular main domain. Okay? And
[01:07:32] through this it is easier to get to the
[01:07:34] main domain. So, in this case, whenever
[01:07:37] we are hitting the root server, we are
[01:07:39] getting the IP of TLD, again hitting the
[01:07:41] TLD, getting the IP of authoritative
[01:07:44] name server. And in authoritative name
[01:07:46] servers, we can have different zones
[01:07:49] attached to different domains.
[01:07:52] And in this zone, if it is telesco zone,
[01:07:55] in that case, all the domains which are
[01:07:57] associated with telesco.com will be
[01:07:59] here. So, if instead of telesco.com, if
[01:08:02] we are hitting courses.telesco.com,
[01:08:04] and from this, the authoritative name
[01:08:07] server will get that this is our telesco
[01:08:09] zone. And in telesco zone, we will get
[01:08:12] the courses.telesco.com
[01:08:14] IP address also. So, yeah, this is it
[01:08:17] for DNS for now. I hope you understand
[01:08:19] it. If you get it, let me know in the
[01:08:21] comments. If you have any queries also,
[01:08:23] let me know in the comments. Have you
[01:08:25] ever wondered, if you see Zomato, if you
[01:08:27] see Uber, if you see Ola, if you see
[01:08:30] Rapido, and all these applications, also
[01:08:32] Swiggy, they all have an inbuilt map.
[01:08:36] But, did they create their own map in
[01:08:38] their applications, or do they use the
[01:08:41] existing Google Maps in order to do
[01:08:43] that? Now, that is possible only through
[01:08:46] APIs. So, Google Maps present some APIs
[01:08:50] to other applications which they can
[01:08:52] use. Now, in order to understand APIs in
[01:08:54] detail, let's dig into this video and go
[01:08:57] to our screen. If we think about API,
[01:09:00] the API basically stands for application
[01:09:03] programming interface. Now, what does
[01:09:06] this mean? Suppose this is our
[01:09:08] application.
[01:09:09] Any application will work. Let's say
[01:09:11] this is a movie application.
[01:09:13] In which we have all the movies, plus we
[01:09:16] have all the ratings, all the reviews of
[01:09:19] the movie. Like IMDb or something, okay?
[01:09:22] Like Rotten Tomatoes or something. So,
[01:09:24] we are already capturing all the details
[01:09:26] which includes a movie like latest
[01:09:28] movie, latest hits of 2000, 2010, 2020,
[01:09:32] everything. Now, we already have this
[01:09:34] amount of data which is stored in our
[01:09:36] database and our application is already
[01:09:39] working on that. Let's say now in any
[01:09:43] other corner of the world, someone is
[01:09:45] trying to create one application based
[01:09:47] on the data which is already captured in
[01:09:50] this app. Now, they have two options.
[01:09:53] Either they can create their own engine
[01:09:55] like this, their own application where
[01:09:57] they will again curate all the ratings,
[01:09:59] curate all the reviews, and curate all
[01:10:01] the data. But now, where are they going
[01:10:03] to curate this from?
[01:10:05] For this, every application leaves some
[01:10:08] end points which can be used by another
[01:10:10] application. Now, if
[01:10:13] for our application or for this
[01:10:15] developer application, if they want to
[01:10:17] use rating of some movie application,
[01:10:19] they can directly call the APIs of this
[01:10:22] application and through which they will
[01:10:24] get the proper information which is
[01:10:25] required for them. Now, like this, this
[01:10:28] developer or this application don't have
[01:10:31] to create their own application for the
[01:10:33] task which has already been done.
[01:10:36] So, they can use the application data
[01:10:38] directly. But again, can't we directly
[01:10:41] give access to our database? This can be
[01:10:44] dangerous, right? Because then this
[01:10:46] application again have to handle a lot
[01:10:48] of scenarios based on the database
[01:10:50] queries, plus they can also delete some
[01:10:53] important data in this database which
[01:10:55] will affect the other applications which
[01:10:58] are using the same content. Also, there
[01:11:00] are some added functionalities. Let's
[01:11:02] say we are giving an option to write a
[01:11:03] review again. So, in this we have
[01:11:06] already handled that case through some
[01:11:08] or the other API. So, instead of
[01:11:11] creating a new endpoint in this
[01:11:13] application, we can directly access the
[01:11:16] endpoint of the other application, which
[01:11:18] is going to take our review also.
[01:11:21] So, in this case, this application saves
[01:11:23] a lot of time because they are using
[01:11:26] another application, the APIs of another
[01:11:28] application through which they are going
[01:11:30] to do the same work. Now, in this case,
[01:11:33] if this application wants to add some
[01:11:35] data into their database also, they can
[01:11:37] easily do this. So, this is one use case
[01:11:40] of creating an API or using APIs of
[01:11:42] other application. Also, there can be a
[01:11:45] case where you're creating an
[01:11:47] application and in the backend you are
[01:11:50] exposing the APIs which can be used by
[01:11:53] your front end. So, front end can be a
[01:11:55] web application or even a mobile
[01:11:57] application. Can be both also. Let's say
[01:12:00] we are creating some backend and from
[01:12:02] for that application we are also
[01:12:03] creating front end maybe using React or
[01:12:05] something and backend using Swift or
[01:12:08] something. In both of these cases, these
[01:12:11] languages, the React and Swift, both are
[01:12:14] capable of handling APIs. So, they don't
[01:12:17] care about which language did the
[01:12:19] backend use in order to provide them the
[01:12:22] API. They will directly call the APIs
[01:12:25] and use the information which they are
[01:12:26] trying to use. So, this is another
[01:12:28] scenario where there are no two
[01:12:30] applications, there is only single
[01:12:32] application which is divided into front
[01:12:34] end and backend part and using the data
[01:12:37] which backend is providing. Again, in
[01:12:39] this case also, you can think that they
[01:12:42] will use the database directly, but it
[01:12:44] is restricted and prohibited for the
[01:12:46] security of data which we have already
[01:12:48] discussed in the first case. So, with
[01:12:50] this we understand the core
[01:12:52] functionality or usage of the APIs.
[01:12:54] Number one is if you want to give access
[01:12:57] to some other application, and number
[01:12:59] two is if you want to give access of the
[01:13:02] endpoints or the APIs to our front end.
[01:13:05] Now, this both can also happen at the
[01:13:07] same time because it is up to us how do
[01:13:10] we want to expose our APIs. Some
[01:13:12] applications or some backend basically
[01:13:15] restrict the APIs to be used through
[01:13:17] their front end applications only. And
[01:13:19] if you want to make them open, you can
[01:13:21] make them open so that other application
[01:13:23] can also use the same API. Now, let's
[01:13:25] move forward to the type of APIs. The
[01:13:28] first type of API is called as REST API.
[01:13:31] If you are a developer, you already are
[01:13:33] using this. Also, if you are creating
[01:13:35] projects, you might already have created
[01:13:37] them or use them in your application.
[01:13:40] Now, REST basically stands for
[01:13:43] representational state transfer. REST is
[01:13:46] one of those APIs which you will see in
[01:13:49] most of the application nowadays because
[01:13:51] of its easiness, its structure, and its
[01:13:53] ability to easily maintain a large
[01:13:55] amount of data with low volume.
[01:13:58] So, that's why we use REST. Mostly, in
[01:14:01] REST we use JSON,
[01:14:04] which is JavaScript Object Notation,
[01:14:06] which is a way or a format through which
[01:14:08] we will send or retrieve the data. It is
[01:14:11] a easy to use format, that's why we are
[01:14:13] sticking with this for this today's
[01:14:16] video, and we are going to cover this in
[01:14:17] details in a minute. Also, we have some
[01:14:20] other types, that is SOAP. SOAP
[01:14:24] basically stands for Simple Object
[01:14:26] Access Protocol. This is also one way of
[01:14:28] handling the data across applications,
[01:14:31] across different platforms, and SOAP
[01:14:33] basically use XML formats in order to
[01:14:36] transfer the data.
[01:14:38] XMLs are replaced by JSON because XMLs
[01:14:42] were really bulky in nature because in
[01:14:44] order to create every object or every
[01:14:47] array, we have to mention the attributes
[01:14:50] again and again, which is solved by
[01:14:52] JSON. So, that's why we prefer JSON over
[01:14:56] XML any day in today's time. But, the
[01:14:59] SOAP or the XML was famous back then.
[01:15:02] So, that means there are a lot of
[01:15:04] applications which are still using XMLs.
[01:15:07] Why? Because there are legacy
[01:15:08] applications. They are built way earlier
[01:15:11] when JSON was introduced and still are
[01:15:14] using XML. So, in legacy system, if the
[01:15:17] APIs are created and exposed using XML,
[01:15:21] that means
[01:15:23] in order to make our system work, we
[01:15:25] also need to know about XMLs so that we
[01:15:28] can integrate those APIs into our
[01:15:30] system. Also, you can use some
[01:15:33] middleware application where the data
[01:15:36] will be taken in the form of XML and
[01:15:38] will be converted into JSON and your
[01:15:42] application can use that data
[01:15:43] afterwards. So, that's why if you are
[01:15:46] working with a legacy system, it is
[01:15:47] preferred to understand the XMLs also so
[01:15:50] that you can convert them in JSON or you
[01:15:53] can work them without converting them as
[01:15:55] well. So, after SOAP, let's jump to the
[01:15:57] third one, which is GraphQL. So, GraphQL
[01:16:01] is also used widely across many
[01:16:03] applications, many platforms. So, the
[01:16:05] basic thing in GraphQL is GraphQL
[01:16:08] basically says that I'll provide a
[01:16:11] single endpoint, only a single endpoint,
[01:16:14] and based on that, you can send
[01:16:16] whichever query you want. So, in FE,
[01:16:19] from FE side, we will not hit multiple
[01:16:22] endpoints, but we will send a request as
[01:16:25] a query. That's why the GraphQL stands
[01:16:28] for graph query language. So, GraphQL
[01:16:31] also have a query language that is
[01:16:33] similar to SQL. In SQL also, we have
[01:16:35] multiple queries from which we can do
[01:16:37] our things.
[01:16:38] In this also, only one point is exposed
[01:16:41] as I told earlier and using that only
[01:16:44] the front end now can send multiple
[01:16:47] queries and access that particular
[01:16:49] endpoint and get the data which they
[01:16:51] want. So, this is the core concept of
[01:16:53] GraphQL. So, as I said, GraphQL is also
[01:16:56] present in our today's time also. So,
[01:16:58] there can be a chance that you learning
[01:17:00] GraphQL and working on it. The other
[01:17:03] type of API is gRPC. Here, the RPC
[01:17:07] stands for remote procedural calls and
[01:17:09] for G some may say that G stands for
[01:17:12] Google because it is created by Google,
[01:17:14] but it is gRCP
[01:17:18] remote procedural calls only. So,
[01:17:21] instead of using XML and JSON, we have a
[01:17:23] new format here which is called protocol
[01:17:25] buffers. It is very much efficient than
[01:17:28] JSON and XML combined. So, that means
[01:17:31] the size of protocol buffers are usually
[01:17:33] very small than XML or JSON. So, that
[01:17:36] will enable the data to transfer faster.
[01:17:39] So, because of this only Google created
[01:17:41] this and uses this.
[01:17:43] So, this is small in size and faster to
[01:17:47] transfer. In today's applications where
[01:17:50] we have microservices, right? So, in
[01:17:52] microservices, this is our entire
[01:17:55] application and let's say our
[01:17:57] applications is divided into multiple
[01:17:59] applications which is combining the data
[01:18:03] of their endpoints through each other.
[01:18:05] Let's say these are the connections and
[01:18:08] through this they are going to provide
[01:18:10] the actual API to the outer world. Now,
[01:18:12] for this communication between these
[01:18:14] microservices, we often use gRPC. Why?
[01:18:18] Because internally at least the
[01:18:21] communication should be faster to
[01:18:22] provide the relevant information in a
[01:18:25] low latency. This will also help us
[01:18:28] having multiple microservices and having
[01:18:30] various kind of communications between
[01:18:32] them before giving the actual data to
[01:18:34] the other application or the front end.
[01:18:37] Now, let's jump to the last one in our
[01:18:39] list today, which is WebSockets.
[01:18:42] WebSockets are also used in today's time
[01:18:44] and today's application for various
[01:18:46] purposes. For every notifications, if we
[01:18:49] see, WebSockets are used. In order to
[01:18:51] maintain a chatting stream, WebSockets
[01:18:54] are used. Wherever you need some
[01:18:56] real-time connections, WebSockets are
[01:18:58] used. So, its architecture is slightly
[01:19:01] different from the other services. In
[01:19:03] other services, front end or the other
[01:19:05] application will place some request to
[01:19:08] the application and then they will
[01:19:10] provide the response. But, in
[01:19:12] WebSockets, whenever front end creates a
[01:19:15] request, a channel is created. Now, once
[01:19:18] the channel is established, then the
[01:19:20] conversation can be lead through back
[01:19:22] end also. Whereas, in other forms, only
[01:19:25] front end or the other application,
[01:19:27] which is trying to access the
[01:19:28] information, they send the request and
[01:19:30] get the request. But, in this case,
[01:19:32] since the back end also can initiate the
[01:19:35] conversation, that means it can also
[01:19:37] send some or the other information by
[01:19:40] itself. Those information can be the
[01:19:43] chat or the notifications, which is very
[01:19:46] helpful for front end to get. Because,
[01:19:48] if this channel is not there, the front
[01:19:50] end have to constantly ask the back end
[01:19:53] whether there are some new notifications
[01:19:55] or not or whether the chat is there or
[01:19:57] not. But, once the channel is maintained
[01:19:59] through WebSockets, it is easy to
[01:20:01] navigate message from back end to front
[01:20:04] end and front end to back end as well.
[01:20:06] With this also, if you have played
[01:20:07] quizzes on our Teleschool platform only,
[01:20:10] Teleschool channel, in which you may see
[01:20:12] an application which Naveen sir presents
[01:20:14] in order to share the quiz with you all,
[01:20:16] you use that application in order to
[01:20:18] give the responses. Now, those responses
[01:20:21] or the marks are calculated based on the
[01:20:23] response time and the correctness of the
[01:20:25] answer. Now, those connections are also
[01:20:28] maintained through WebSockets. That's
[01:20:30] why you see many notifications or some
[01:20:32] GIF or something something. So, this is
[01:20:34] about web socket and with this I would
[01:20:36] like to conclude this session because it
[01:20:38] is going to be a long session and it is
[01:20:40] better to understand these things in
[01:20:42] parts. So, these are the most used five
[01:20:46] type of APIs which we have. Now, in
[01:20:49] order to understand them briefly in the
[01:20:51] next video, I'm going to talk about
[01:20:53] RESTful APIs in which we will discuss
[01:20:55] the various aspects or the parts of the
[01:20:58] APIs
[01:21:00] and also see what are the
[01:21:01] recommendations and usage of those APIs.
[01:21:04] Now that we already know about RESTful
[01:21:06] APIs and all the other different type of
[01:21:08] APIs, it's time to deep dive into one of
[01:21:10] them. And for today's video, I have
[01:21:12] selected REST APIs to deep dive into.
[01:21:15] Why? Because it is the most used APIs
[01:21:18] across the world. It doesn't matter if
[01:21:20] you are starting a career or you are
[01:21:22] already seasoned, you have to work with
[01:21:24] RESTful APIs for sure. So, let's move to
[01:21:26] the screen now. RESTful APIs are also
[01:21:29] known as REST APIs. As we know, it
[01:21:31] stands for Representational State
[01:21:34] Transfer. What does it mean? It means
[01:21:36] that REST is also one format through
[01:21:38] which we will transfer our data from one
[01:21:40] end to another end. What are these ends?
[01:21:43] We have discussed this already. Either
[01:21:45] we are giving some data from front end
[01:21:47] to back end or vice versa. It is also
[01:21:49] possible that one application needs to
[01:21:52] get some data from some other
[01:21:53] application. So, in that case also, APIs
[01:21:56] are used and REST specifically is used
[01:21:59] to transfer some data from one end to
[01:22:01] another end. So, basically, it is a way
[01:22:04] of how our applications are going to
[01:22:06] communicate with each other. Now, before
[01:22:08] starting, let me tell you that in REST,
[01:22:10] we normally use JSON. JSON is a standard
[01:22:14] way of sharing the data.
[01:22:16] In JSON, we can have array, we can have
[01:22:19] object and with these two combinations,
[01:22:22] we can share our data in the form of key
[01:22:24] and value. So, let me create a simple
[01:22:26] JSON. Let's say this is a start of an
[01:22:28] object and here we have a key, let's say
[01:22:32] name. For value, I'm writing my name.
[01:22:34] With comma, we separate different
[01:22:36] values. So, after comma, I have to write
[01:22:38] some other key. So, let it be age. And
[01:22:41] with age, I can write any numeric value
[01:22:43] as well. So, as we can see, this is
[01:22:45] string value and this is a numeric
[01:22:47] value. There are more values who are
[01:22:50] accepted as a form of value, which is We
[01:22:53] have already seen string and then
[01:22:55] number. We can also use boolean, even a
[01:22:57] nested object, arrays, and a null. Null
[01:23:01] can also be used because if we don't
[01:23:03] have any value for that particular field
[01:23:04] directly, it is easy to say it is a null
[01:23:07] value. And the application which is
[01:23:09] using that value can take care of it.
[01:23:11] So, this is all about the JSON which we
[01:23:13] need to know. We need to know that it is
[01:23:14] in the form of key-value pair and what
[01:23:17] are the values which we can use. Now,
[01:23:19] let's move forward to the next part,
[01:23:21] which is endpoint. In order to
[01:23:23] understand endpoint, we have to get two
[01:23:25] things. One is method and the other
[01:23:28] thing is path. So, in order to access
[01:23:30] any data, we have to have some URL on
[01:23:34] which we will hit with that particular
[01:23:36] method and based on the method selection
[01:23:38] and the path, we are going to either get
[01:23:41] or pass some data to our server. Let me
[01:23:43] start this with an example. Suppose we
[01:23:45] are using HTTP as uh any site, my site
[01:23:50] .com. So, this is our main site and
[01:23:52] after that, we can put a slash and use a
[01:23:55] different URL. Let's say we are
[01:23:57] separating all the APIs in the API
[01:24:00] subdomain. So, APIs is there and then we
[01:24:03] can also segregate the APIs using
[01:24:06] version. So, this is version one and
[01:24:08] here we are going to write resource.
[01:24:10] Now, resource can be anything. If I talk
[01:24:12] about any e-commerce application, it can
[01:24:14] be a product, it can be coupon, can be
[01:24:17] user, can be anything, basically. A
[01:24:19] resource is an entity through which we
[01:24:21] are navigating and getting and passing
[01:24:23] the data to the database. So, this is
[01:24:25] the URL. The URL is called the path
[01:24:28] through which we are going to either get
[01:24:30] or pass some data. And with this, we
[01:24:33] need to have a method. So, for method,
[01:24:36] we can have a get basically. So, get
[01:24:38] method with this path combinedly creates
[01:24:41] an endpoint and through which now we can
[01:24:43] get some data. We expect this path to
[01:24:46] retrieve some data because we are using
[01:24:49] get. Now, there can be multiple ways of
[01:24:52] creating this URL. So, normally, we hide
[01:24:55] the domain part of it. We don't use them
[01:24:58] in the explanations. We only use the
[01:25:01] resource part. Also, we can remove the
[01:25:03] version also. With that, API can also be
[01:25:05] removed in order to understand the
[01:25:07] resource part directly.
[01:25:09] So, from now on, if I create any path,
[01:25:12] let's say users, it is expected to have
[01:25:15] all this domain name API versioning if
[01:25:18] it is there beforehand. So, I'm not
[01:25:20] writing that again and again. Cool. So,
[01:25:22] with that, if I write users here and use
[01:25:25] get method, now I'm expecting some
[01:25:28] response from our server. I'm expecting
[01:25:31] either a list or a response from our
[01:25:33] server. We'll come back to responses in
[01:25:35] a while, but this is how we can get some
[01:25:37] user information from our server. Now,
[01:25:40] let's move to the second part. In this,
[01:25:42] we don't want all the users, we want a
[01:25:44] specific users. So, to find a specific
[01:25:46] user, we have to provide them an ID.
[01:25:48] Normally, we provide them in the URL
[01:25:50] itself. So, it is get users and here we
[01:25:54] can include the ID. So, in real time, it
[01:25:57] can be used as users/1.
[01:26:00] So, if we write one, the user with the
[01:26:02] ID one will be retrieved. Now, with
[01:26:05] this, we can also add any user. So, the
[01:26:07] third part is
[01:26:09] adding a user. So, again, the URL will
[01:26:12] be same users and now we are adding the
[01:26:14] user, so we are using the method post
[01:26:17] here. So, in this with post, we are
[01:26:20] going to give some body, and in body, we
[01:26:23] will have some JSON which will store the
[01:26:25] user information which we are trying to
[01:26:27] create. And based on our request, our
[01:26:29] user will be created in our database.
[01:26:31] Now, once we have all the user details
[01:26:33] in our table, we may choose to update
[01:26:35] any user information, correct? So, for
[01:26:38] that, we use another method which is
[01:26:41] put. Again, the URL will be same, users.
[01:26:45] And with this users, we will send the ID
[01:26:47] of the user of which information we are
[01:26:50] trying to update. So, with put, we also
[01:26:53] have another method which is patch,
[01:26:55] which can also be used in a similar way
[01:26:57] to update the user information. Now,
[01:27:00] what is the difference between put and
[01:27:02] patch? It is simply that if we use put,
[01:27:05] our entire user object will be replaced
[01:27:08] with the new data. So, this is going to
[01:27:10] replace the user data. And if we don't
[01:27:13] want to update all the fields, we want
[01:27:16] to update a specific field or particular
[01:27:17] field, suppose username, name, age, or
[01:27:20] anything, so we can use patch. It can be
[01:27:23] used to partially update the user
[01:27:25] record. Let's understand this with an
[01:27:27] example. Let's say we have any user
[01:27:30] information which have ID and have a
[01:27:33] name and have a username, maybe age.
[01:27:36] This is all. So, these are all the
[01:27:38] values which are
[01:27:40] user currently have. Let's we put some
[01:27:42] values. So, if our user table or user
[01:27:45] entity have these all four values, if we
[01:27:49] use put to update a particular change
[01:27:51] only, let's say I'm going to change my
[01:27:55] username from Akshay to AK something.
[01:28:00] So, now this change will only be done if
[01:28:02] we again send the entire body into the
[01:28:05] put request. If we only send username
[01:28:09] like this, then all the other values of
[01:28:12] our entity will be updated with the
[01:28:13] default value. So, if we send this kind
[01:28:16] of data in a put request, it is going to
[01:28:18] replace our entire entity. So, that
[01:28:20] means the name, the age will be replaced
[01:28:24] by the default or null value. So, it is
[01:28:26] not recommended to use put entirely if
[01:28:29] you want to update your entity
[01:28:30] partially. In those cases, always try to
[01:28:33] use patch. In patch, we're going to
[01:28:36] again update the particular information.
[01:28:38] So, this is perfectly valid for a patch
[01:28:41] request. So, with this, let's move to
[01:28:43] the next part. The next kind of method
[01:28:46] which we use is delete. In delete also,
[01:28:48] normally we pass the ID like this. So,
[01:28:52] if we write users and with {slash} we
[01:28:55] write one, so that means the user with
[01:28:58] the ID one will be deleted. Now, this is
[01:29:00] the usual stuff. You will get this
[01:29:02] information anywhere. Now, let me talk
[01:29:04] about something which is nested data.
[01:29:07] Let's understand nested data with an
[01:29:08] example. Suppose you're creating a blog
[01:29:11] site. So, in blog site, we normally have
[01:29:14] our users who are going to read our
[01:29:16] blogs. Then, we have blog, the actual
[01:29:18] content on the site. And on blog, the
[01:29:21] user can comment. So, we have clearly
[01:29:23] three entities: users, blogs, and then
[01:29:27] comments. So, these three entities are
[01:29:29] interrelated. So, a user is going to
[01:29:32] give comment on a particular blog. Users
[01:29:36] can't comment if there is no blog,
[01:29:38] correct? So, this is the way. Now, in
[01:29:41] order to create APIs for this, we can
[01:29:44] create a users API for all the users'
[01:29:47] activity. So, all the users' activity
[01:29:49] means we can use it for get, put, push,
[01:29:54] delete, and patch also. Now, this is
[01:29:56] simple because a single entity is there,
[01:29:58] users, and all the operations are on
[01:30:01] that users only. Now, let's say we want
[01:30:04] to create an API on which user can add a
[01:30:09] comment. Okay? So, for that, what we can
[01:30:11] do, we can either go from the blogs
[01:30:14] perspective. So, every blog have a
[01:30:16] particular comment section, right? So,
[01:30:18] blogs, then here we can write ID. So,
[01:30:21] this ID is basically belong to the blog,
[01:30:23] and with blog, we can write comments.
[01:30:26] And if we write get here, what it is
[01:30:28] going to do, it is going to give us all
[01:30:30] the comments which are associated with
[01:30:32] the blogs with ID this. Correct? So,
[01:30:36] this is a nested relationship where
[01:30:38] we're trying to access comments, but we
[01:30:41] are going via blogs. We can also do like
[01:30:44] this. Suppose we are on the user's page,
[01:30:46] and we want to see all the comments that
[01:30:48] user have created. So, we can again
[01:30:50] create a get query
[01:30:52] via users, where this is the user ID
[01:30:55] here, and we can see comments. So, we
[01:30:58] are dealing with two different entities
[01:31:01] by creating the relationships between
[01:31:02] them. So, by this, we are going to get
[01:31:05] all the comments which are created by
[01:31:07] the user with this ID. So, we can go to
[01:31:10] comments via blogs, as well, and via
[01:31:12] users, as well. So, this is nested.
[01:31:15] Again, if you want to update any
[01:31:17] comment, delete any comment, we can use
[01:31:20] simply the comments path
[01:31:22] where the user can enter the ID here of
[01:31:25] the comment.
[01:31:26] And they can use it to update or delete
[01:31:30] that particular comment. So, here you
[01:31:32] can also ask me that why are we using
[01:31:34] this kind of nesting in URL? Why are we
[01:31:36] not sending the data in the request? So,
[01:31:39] that is also possible. We can do like
[01:31:41] this. We can
[01:31:42] go to this comments, and we can pass the
[01:31:45] request body, in which we'll pass
[01:31:48] the post ID to get all the comments
[01:31:50] associated with this post. This is also
[01:31:52] possible, but this is not recommended.
[01:31:54] As there is a direct relationship
[01:31:56] between two entities, we don't normally
[01:31:58] go for this body approach. We go for the
[01:32:01] URL approach because it is easy to
[01:32:04] understand also. So, when do we go for
[01:32:06] the body approach? So, the body approach
[01:32:09] is used when we are trying to filter any
[01:32:12] data. So, we understood two concepts
[01:32:14] here. First is the nesting data versus
[01:32:17] filtering. So, when to use which one? If
[01:32:20] you have a clear relationship between
[01:32:22] two entities and it is clean, so you can
[01:32:25] go for nesting. And also in filtering,
[01:32:28] apart from sending the data like this in
[01:32:31] post ID, you can also use
[01:32:33] the URLs like this, comments, and then
[01:32:36] in query parameter, you use post ID.
[01:32:39] Now, this is again not recommended
[01:32:41] because there is a direct relationship
[01:32:43] between comments and post. So, it should
[01:32:45] be a nested type of URL. So, if there
[01:32:48] are clear relationship, we can use
[01:32:50] nesting. And if the relationship is
[01:32:52] complex, we can go for filtering. Also,
[01:32:56] the filtering will be used whenever we
[01:32:58] are trying to do pagination or we are
[01:33:00] trying to filter particular records
[01:33:03] based on multiple ways like we can go
[01:33:05] for any e-commerce page where we are
[01:33:07] seeing different products and we can
[01:33:09] filter our product based on our color,
[01:33:11] price range, and all these things. So,
[01:33:14] those things normally go for query
[01:33:16] parameters as a URL, right? And we don't
[01:33:19] go for nesting there because it will be
[01:33:21] complex to handle a long path with
[01:33:22] nesting data. So, the crux is if the
[01:33:25] relationship is pretty straightforward
[01:33:27] and we will go with respect to the other
[01:33:29] entity, we'll go for nesting kind of
[01:33:31] URLs. And if there are complex
[01:33:34] relationships or the filtering is used,
[01:33:37] we'll go for the query parameters. Now,
[01:33:41] let's move to the next part. How do we
[01:33:43] pass the actual data to the endpoint?
[01:33:45] So, there are three ways. Either we can
[01:33:47] use path, so we can integrate the IDs in
[01:33:50] the path, or we can use some query
[01:33:53] parameter, or we can use body. I have
[01:33:56] given you glimpse of these all three in
[01:33:58] the previous section, but now let's talk
[01:34:00] about this specifically. So for path, it
[01:34:03] is very specific that we will only pass
[01:34:06] the recommended IDs or maybe slugs or
[01:34:09] maybe that particular unique identifier
[01:34:12] only. So this is unique identifier. It
[01:34:16] can be ID or slug. Slug is basically a
[01:34:19] short form of that particular post. If
[01:34:22] you are using any blog site, so let's
[01:34:24] say the blog site the blog is about what
[01:34:27] is Java and in slug you can see
[01:34:30] something like blog /what is Java like
[01:34:34] this. So this is our slug. Again, this
[01:34:37] slug will be unique throughout our
[01:34:39] blogs. So the name of the URL I have
[01:34:42] also written blogs, it is wrong.
[01:34:44] Normally we address the URL in the form
[01:34:47] of plurals. So it is going to access in
[01:34:50] multiple areas, multiple scenarios. So
[01:34:53] normally we don't go for blog, we go for
[01:34:56] blogs like this. Cool. Now for query
[01:34:59] parameters, whenever we are filtering or
[01:35:02] maybe sorting, we can go for query
[01:35:04] parameter. Suppose we are again
[01:35:06] scrolling through our blogs and in blogs
[01:35:09] we can write like sort ASC or we can
[01:35:13] assign some numbers also. So ascending
[01:35:15] means sort ascending maybe by date. So
[01:35:18] whichever date they are created, they
[01:35:20] will be sorted by that. Or maybe we can
[01:35:22] use DESC for decreasing order. So that
[01:35:26] the latest post will be pop up first.
[01:35:28] With this again we can use the query
[01:35:30] parameter for filtering. So maybe we can
[01:35:33] use blogs again here and with that we'll
[01:35:36] pass query parameter. So this is Q for
[01:35:39] maybe query search or search step. So
[01:35:42] anyone with is searching for Java and it
[01:35:45] will give us a list of blogs for Java or
[01:35:49] which have Java in their name or their
[01:35:51] content or their category. So, this is
[01:35:53] all about query parameters. Now,
[01:35:56] whenever we pass any information in
[01:35:58] query parameter and path, those
[01:36:00] informations are going to be exposed,
[01:36:02] right? So, that means we can't pass any
[01:36:05] sensitive information into query
[01:36:07] parameters or path. So, for that we have
[01:36:10] body. So, let's say we have a login
[01:36:12] path, and now we can pass username and
[01:36:15] password in the body, which is not
[01:36:17] exposed at all.
[01:36:18] So, it is safe. So, the rules are pretty
[01:36:21] clear when we use path, query params,
[01:36:24] and body. Now, with this let's see a
[01:36:25] full request in action. The first thing
[01:36:28] is we will have our method. So, this is
[01:36:30] maybe a post method, and we are using
[01:36:33] some API of version three, maybe.
[01:36:37] For version three, we are using users,
[01:36:40] and then we can also pass the metadata.
[01:36:42] Suppose content type we can pass, which
[01:36:46] is application/json
[01:36:49] here, because we are passing the
[01:36:50] information in the form of JSON. We can
[01:36:52] also use XML, or if you have latest
[01:36:55] information, we also have a new format
[01:36:58] in town, which is
[01:36:59] tone. So, we can also use various kind
[01:37:02] of information, but because currently we
[01:37:04] are using JSON, so we can pass it like
[01:37:06] this, and with this we have our body. In
[01:37:09] body, we can pass anything, maybe some
[01:37:11] data we are trying to add, and then
[01:37:13] maybe username. So, like this we can
[01:37:16] pass the entire request or the data to
[01:37:19] our server. So, this is what? This is
[01:37:21] our method. This is the path. This again
[01:37:25] is metadata, and this is our body. Now,
[01:37:28] once we have understood the request
[01:37:30] correctly, it is time to understand the
[01:37:32] responses. So, in order to understand
[01:37:34] the response, first we need to
[01:37:36] understand the response code. So, there
[01:37:38] are specific codes assigned to a
[01:37:41] specific type of response, which if the
[01:37:43] user gives will clearly understand what
[01:37:45] they want to tell us. So, let me start
[01:37:48] with those status codes and then we will
[01:37:50] move forward. So, these are all the
[01:37:52] response codes which we have to know.
[01:37:54] 200 stands for okay. So, this means
[01:37:57] everything is working as expected. Don't
[01:37:59] worry about it. Then we have 201. 201 is
[01:38:03] basically used when there is a new
[01:38:05] entity created in the database. So, this
[01:38:07] is created. Then we have 204. 204 is
[01:38:11] again saying that everything is working
[01:38:13] fine, but I don't have anything to
[01:38:15] provide to you. Let's say we are
[01:38:17] deleting any entity, so it is
[01:38:19] successfully deleted, but they don't
[01:38:21] have any response body to give to us.
[01:38:23] So, that means there is no content to
[01:38:25] give to us, but the request is working
[01:38:28] fine. Then we have 301. 301 is basically
[01:38:32] used for redirects and 301 indicates
[01:38:35] that it is a permanent redirect. And if
[01:38:38] the redirect is not permanent, then we
[01:38:40] use 302. That is temporary redirect.
[01:38:44] Then we will come to the 400 series. So,
[01:38:47] all the 400 series basically says that
[01:38:49] there is some issue with the request we
[01:38:52] are having. So, the 400 stands for bad
[01:38:56] request. That means some or the other
[01:38:58] data is not correctly mentioned in the
[01:39:01] body. Either they have some validation
[01:39:03] issue, either either they are missing
[01:39:05] when they are required. Either they have
[01:39:07] some other issues, but request which we
[01:39:10] are getting, the body doesn't have the
[01:39:13] correct information. So, in that case,
[01:39:15] we normally give 400 bad request as a
[01:39:18] response. Then we have 401. 401 is given
[01:39:22] when someone is trying to access some
[01:39:24] information for which they are not
[01:39:26] basically authorized. So, 401 is
[01:39:30] unauthorized. With that we have 403,
[01:39:33] which is used for forbidden. Suppose on
[01:39:35] an LMS, you have not enrolled for a
[01:39:37] course and you want to access a
[01:39:39] particular video or lesson part of that
[01:39:41] course which is not publicly accessible.
[01:39:44] So, in that case, you will receive 403
[01:39:46] forbidden because you are not allowed to
[01:39:48] see that particular resource. With this,
[01:39:51] we have 404 page not found. This is
[01:39:53] basically used whenever the URL is
[01:39:56] incorrect or trying to access some or
[01:39:58] the other resource which is not there
[01:40:00] into our system. And at last, we have
[01:40:03] 500. So, 500 is the response which is
[01:40:07] given to a front end when there is
[01:40:09] something wrong with the back end. So,
[01:40:12] this is related to back end. Some or the
[01:40:14] other error is there in the back end.
[01:40:16] Maybe some syntax error, maybe some
[01:40:18] other error, some logic is missing, some
[01:40:21] data is missing, something is wrong with
[01:40:23] back end. So, this is internal server
[01:40:26] error. There are many errors which we
[01:40:28] don't want users to see. So, those all
[01:40:32] are handled by 500 because we don't want
[01:40:35] the user to understand what is the issue
[01:40:37] we are facing with our database
[01:40:38] connection or anything. So, we will
[01:40:40] create logs into our system and through
[01:40:43] which we'll resolve the 500 error
[01:40:45] issues. So, these are all the most
[01:40:47] commonly used response codes which we
[01:40:49] have to understand. So, now whenever we
[01:40:51] are creating any APIs, if the response
[01:40:54] is completely fine, we will provide 200.
[01:40:57] If we are creating any entity, we will
[01:40:59] provide 201. If we are deleting or
[01:41:02] performing some operations where we
[01:41:04] don't have to give any content or any
[01:41:06] data or any body in the response, we
[01:41:09] will use 204. Then, if the permanent
[01:41:13] redirection is there, we will use 301.
[01:41:15] If the redirection is for temporary
[01:41:17] basis, we will use 302. For any bad
[01:41:21] request in the body, we will use 400.
[01:41:24] For authorization, we will use 401.
[01:41:28] For forbidden or the content which
[01:41:30] requires some special access, we will
[01:41:33] give 403. 404 we will give when they are
[01:41:37] trying to access any resource which is
[01:41:39] not there and 500 we will give when
[01:41:42] there is any issue in the internal
[01:41:44] server. So with this, let's move to the
[01:41:46] next part which is response body. So
[01:41:49] normally in response body, what is
[01:41:51] allowed first we start with that. So we
[01:41:54] can return an array, right? Also, we can
[01:41:57] return an object. With this also we can
[01:42:00] return data as nested objects. Now in
[01:42:04] most of the applications whenever you
[01:42:06] are going through any YouTube tutorial
[01:42:08] or any course also sometimes when you
[01:42:10] are dealing with multiple responses,
[01:42:13] let's say the responses for this is
[01:42:16] normally an array, right? But it is not
[01:42:19] recommended to handle the response as
[01:42:22] array. It should always be wrapped in
[01:42:25] the form of an object. And if you want,
[01:42:27] you can use any other key for this users
[01:42:31] and in the value you will give these
[01:42:34] responses. Now these can also be string
[01:42:38] or an object. Normally an object only of
[01:42:40] all the users, but it should be handled
[01:42:42] like this. So this is the correct or I
[01:42:45] would say recommended way. So every
[01:42:47] response body should be an object. And
[01:42:50] even if we're trying to give an array,
[01:42:53] we have to wrap it up into an object and
[01:42:56] give us in the key value form. So this
[01:42:58] is a good practice and through this
[01:42:59] we'll achieve a more long-lasting code.
[01:43:02] Why? Let's say today we are passing the
[01:43:05] user details only and tomorrow we
[01:43:07] understand that okay, we have to add
[01:43:09] more fields. So we don't have to change
[01:43:12] much on the front end side or the
[01:43:14] receiving side, but we will simply
[01:43:17] update our response, change the object
[01:43:20] here
[01:43:21] and maybe add some other field user
[01:43:24] count and pass that information maybe
[01:43:27] 29. And with this we can end our object
[01:43:30] here. So we can pass as many
[01:43:32] informations as we want, but if we have
[01:43:35] used a single array
[01:43:37] as a response, then we have to struggle
[01:43:39] with it and we have to change the entire
[01:43:41] architecture of our response. So, it is
[01:43:44] always recommended to pass the response
[01:43:47] always in the form of an object. So, let
[01:43:49] me write returning as array not
[01:43:52] recommended. Let me know in the comments
[01:43:54] if you already knew about this or you
[01:43:56] are hearing this for the first time. So,
[01:43:58] with this, let me create a map of
[01:44:00] request type and responses. So, let's
[01:44:03] say here
[01:44:04] we have request. Here are the responses
[01:44:07] which we are going to receive. So, if
[01:44:09] the request type is get and we are
[01:44:12] trying to access many records, so maybe
[01:44:14] we are trying to access users, it is
[01:44:18] going to give an array of records,
[01:44:19] right? So, it is normally going to give
[01:44:23] 200 as a response code and going to give
[01:44:26] an array. Now, we understand that we
[01:44:28] have to not give array directly, so it
[01:44:30] will be wrapped in the form of an
[01:44:32] object. Now, the next request is also a
[01:44:36] get request where we want to access a
[01:44:39] particular object. Let's say one. Now,
[01:44:43] you can think that we will give the user
[01:44:45] information directly, but again, it is
[01:44:48] not recommended to give that directly.
[01:44:50] We will use the nested object for the
[01:44:52] same reason. So, in this object, we will
[01:44:54] use the user as key and pass on the user
[01:44:58] information into this object. So, this
[01:45:01] is the actual user object, but we are
[01:45:04] wrapping it into an another object
[01:45:06] because it will give us flexibility to
[01:45:09] pass some more information if we want
[01:45:11] to. So, let me clear this up for now.
[01:45:14] So, normally, we are going to get 200
[01:45:16] response with this kind of nested
[01:45:19] objects. Also, it is possible that this
[01:45:22] ID is not there in our DB. In that case,
[01:45:26] we can also give 404 response. Now, if
[01:45:29] we are adding anything, we will use post
[01:45:31] with the same URL, and normally it is
[01:45:34] going to give 201 response, which means
[01:45:38] the entity is created. And also, we can
[01:45:41] use 200 response if you want. But, if we
[01:45:44] are using 201, normally we give the ID
[01:45:48] or the new object as response. Now, here
[01:45:53] with post request, we are also giving
[01:45:55] the body, so it can also have 400
[01:45:58] issues, right? 400 bad request issue.
[01:46:01] And also, if the format doesn't sync in,
[01:46:03] it can also give 500 issue. If the data
[01:46:06] is coming properly and there is some
[01:46:08] issue in the back end, it can also give
[01:46:10] 500 easily. So, these are most common
[01:46:13] response codes which you can have while
[01:46:16] working with post. Now, let's talk about
[01:46:18] delete. In delete also, we will pass
[01:46:21] this
[01:46:22] URL with some ID, and this can also give
[01:46:26] 200 as a response. And also, if it is
[01:46:29] deleted correctly and we don't want to
[01:46:31] give anybody in the response, we can go
[01:46:34] for 204. If this entity is not present,
[01:46:37] maybe the ID they are using is one and
[01:46:40] we don't have any record with the ID
[01:46:41] one, we can have 404 or we can have 500
[01:46:46] if there are any dependencies
[01:46:48] and which is not handled correctly by
[01:46:50] our back end. With this, you can also
[01:46:52] see 401 here if you are unau- prized
[01:46:55] person to delete that particular record
[01:46:57] or you are not allowed to delete that
[01:46:59] particular entity, you can also get 401.
[01:47:02] So, these are the most common request
[01:47:04] responses, and with that we have also
[01:47:07] discussed what can be there in the
[01:47:08] response body. So, with this we have
[01:47:10] covered the entire request section and
[01:47:13] the response part of the REST APIs, and
[01:47:16] I hope the information which you get
[01:47:18] from this video is going to help you in
[01:47:20] your entire development career. Whenever
[01:47:22] you are dealing with REST APIs. In order
[01:47:25] to build any application, we have client
[01:47:27] on this side, right? Who is going to
[01:47:30] interact with either a web application
[01:47:32] or a mobile device to interact with our
[01:47:35] application. Now, with this we will have
[01:47:38] our server in this side. So, this is
[01:47:40] maybe our server. And if we keep the
[01:47:42] model like this only, that means every
[01:47:46] time we restart our server, all the data
[01:47:49] which user is trying to access will be
[01:47:51] lost. Because when server restarts, it
[01:47:54] clears all the data. But, the thing is
[01:47:57] we need to store that data somewhere,
[01:47:59] right? So, for that we use database in
[01:48:02] order to store the information which the
[01:48:04] user may require next time when they log
[01:48:07] in or see our application. Now, one
[01:48:09] thing is very clear that most of the
[01:48:11] application can't live without
[01:48:13] databases. Now, in order to understand
[01:48:16] how do we store data, we have two
[01:48:18] approaches. First is the SQL approach,
[01:48:22] and the other one is no SQL approach.
[01:48:25] So, SQL basically consists of RDBMS,
[01:48:29] which is relational database model, in
[01:48:31] which we will have tables, rows,
[01:48:33] columns, and we will connect those
[01:48:35] tables based on different joins and
[01:48:38] everything. And in no SQL, we have other
[01:48:41] methods. See, saying SQL and no SQL is
[01:48:44] like saying Java and no Java. That means
[01:48:47] there are various options in no SQL. We
[01:48:49] can have our data as in the form of key
[01:48:52] value. Also, we can have column. We can
[01:48:55] also have the data in the form of nodes,
[01:48:57] maybe. And we can store them in the form
[01:49:00] of graphs. Also, we can store the data
[01:49:03] in the form of document. And here, if we
[01:49:05] talk about SQL, we have our tables in
[01:49:09] place, who is going to hold our data in
[01:49:11] the form of entities. And there will be
[01:49:13] different relationships between
[01:49:15] different tables. Also, in order to do
[01:49:18] in SQL manner, we have various softwares
[01:49:20] like post dress or we can go for MySQL.
[01:49:24] Right? Like this, we can have multiple
[01:49:26] options here. For here also, we have
[01:49:28] multiple options like Cassandra or we
[01:49:31] can go for MongoDB. And based on this
[01:49:34] selection, where we are going to do it
[01:49:36] SQL way or no SQL way, we are going to
[01:49:38] build the entire foundation of our work.
[01:49:41] Like how our data, our important data is
[01:49:44] going to store in our database. So, in
[01:49:47] today's video, let's focus on SQL. And
[01:49:50] in next video, we will focus the ways of
[01:49:52] no SQL. So, let's start. So, SQL
[01:49:56] basically stands for structured query
[01:49:58] language. And SQL comes under the
[01:50:01] category of relational DB. Now, in
[01:50:03] relational DB, we are going to have
[01:50:05] multiple entities and we are going to
[01:50:07] establish different type of
[01:50:08] relationships between those entities, if
[01:50:10] required. So, we are going to store our
[01:50:13] data in the form of tables.
[01:50:16] So, we can loosely say that every table
[01:50:19] is loosely an entity.
[01:50:22] It can either be a user entity or it can
[01:50:25] be comments or it can be post, if we are
[01:50:28] building anything like blog site or
[01:50:30] something or it can be videos, if we are
[01:50:32] building YouTube. So, like this, we
[01:50:34] segregate our different entities and
[01:50:37] then we will build the relationship
[01:50:38] between them. Now, if I draw one of
[01:50:40] those tables, let's say we are building
[01:50:42] a user table. A user table can have
[01:50:45] multiple fields. That is equivalent to a
[01:50:48] user entity can have multiple
[01:50:49] properties. For example, a user can have
[01:50:52] their unique ID. A user can also have
[01:50:55] their first name
[01:50:57] and L name and maybe we also have their
[01:51:00] phone number. So, this is how a table is
[01:51:02] formed, where we have multiple
[01:51:04] attributes of a table. These attributes
[01:51:07] are stored in columns and when we have a
[01:51:10] complete record, let's say in this
[01:51:12] table, we can add a new record where I
[01:51:15] can add any record, let's say the ID is
[01:51:18] one, the name is Akshay, last name is
[01:51:21] Agarwal, and phone number is, let's say,
[01:51:24] 987654
[01:51:27] 321. So, this is my number, this is a
[01:51:30] complete record. Now, this record is
[01:51:33] called as a row.
[01:51:35] So, by getting any row from our table,
[01:51:37] we can get the entire information of
[01:51:39] that particular entity or of that
[01:51:42] particular user. Normally, for the name
[01:51:44] of entities, we don't go for singular
[01:51:46] words because it will contain multiple
[01:51:48] records. So, we will go for plural
[01:51:51] things, users. So, this is the standard,
[01:51:54] this is a constraint, this is not a
[01:51:56] particular rule, but it is safer to go
[01:51:58] into plural things. So, for comments, we
[01:52:02] can go for comments, for post, we will
[01:52:04] go for posts, for videos, also, we will
[01:52:06] go for videos. So, all these things are
[01:52:09] in plural. Why? Because a single table
[01:52:12] will contain multiple records. It will
[01:52:14] be easier for us to fetch the data with
[01:52:17] that plural name because then we will
[01:52:19] know that multiple entries are there and
[01:52:21] it is a convention to use plural things.
[01:52:23] So, with this, let's move to our next
[01:52:25] topic, which is constraints. If we are
[01:52:27] building any application, we can have
[01:52:29] multiple users who are coming with
[01:52:31] different backgrounds, different
[01:52:32] geography, and everything. So, it is our
[01:52:35] responsibility to make them enter the
[01:52:38] data correctly. We will use validations
[01:52:40] in form, and in database, we can handle
[01:52:43] them with the use of constraints.
[01:52:45] Because every wrong data and every
[01:52:46] faulty data is of no use. So, for that,
[01:52:49] let's dive into the constraints. So, the
[01:52:51] first constraint is unique. Unique
[01:52:54] basically stands for a unique value
[01:52:57] throughout the table. For example, in
[01:53:00] the user field, let's create the user
[01:53:02] table again. So, this was our user
[01:53:04] table, let's add one more column or one
[01:53:07] more attribute, which is username. Now,
[01:53:09] we don't want two users to share the
[01:53:11] same username. This is a common thing
[01:53:13] which we can see on Instagram also. If
[01:53:16] you're trying to create a new username
[01:53:18] and if that username is already taken,
[01:53:20] you may get some suggestions with some
[01:53:22] extra characters or you can change the
[01:53:24] name entirely. Similarly, for Gmail
[01:53:26] also, if the username is taken, they
[01:53:28] suggest you some more usernames with the
[01:53:30] extra characters. So, that means we can
[01:53:32] say that the username is unique. Every
[01:53:35] user will have their unique usernames.
[01:53:37] So, in order to maintain that username
[01:53:39] uniqueness, what we will do, either
[01:53:41] while creating the table or while adding
[01:53:44] the username field like we did, what we
[01:53:46] do, we add the constraint unique to that
[01:53:49] particular username. So, that when any
[01:53:52] user comes to this entry and if they
[01:53:55] write ABC, no other user can write ABC.
[01:53:59] If they want to use the same username
[01:54:01] again, they will not be added into our
[01:54:03] databases. Why? Because this username
[01:54:06] field is unique. The next constraint is
[01:54:10] not null. So, not null basically
[01:54:11] represent a value which can't be null.
[01:54:14] Null is the default value for any
[01:54:16] entity, right? So, whenever we want a
[01:54:19] field to have a particular value either
[01:54:21] given by a system or server or given by
[01:54:25] our user, we want to have that value.
[01:54:27] So, we can't have null in that. If we
[01:54:30] see in users table, the first name can
[01:54:33] easily come under the not null category.
[01:54:35] So, we don't want our first name to be
[01:54:37] null because we are going to address our
[01:54:39] user with their first name. So, this is
[01:54:41] a required field. The next constraint is
[01:54:43] primary key. So, our primary key acts as
[01:54:46] a unique identifier for that particular
[01:54:48] entity. In our whole user table, there
[01:54:51] is no record which can share that
[01:54:53] particular value. So, if we find any
[01:54:56] record with ID, let's say ID is equal to
[01:54:58] three, so only one record will come out
[01:55:01] of this. Okay? It can't give two records
[01:55:04] because the ID cannot be shared between
[01:55:06] two records. So, it will give a unique
[01:55:09] record out of our users table. So, our
[01:55:11] primary key basically helps us to track
[01:55:13] down to that particular record. And
[01:55:15] also, it helps us when we deal with
[01:55:18] multiple tables because there we might
[01:55:21] need some ID to put into some other
[01:55:23] table as a foreign key. So, in that
[01:55:25] concept also, primary key is used. With
[01:55:28] this, we can have a fourth option here,
[01:55:31] which is check. Check is basically used
[01:55:33] in order to maintain the authenticity of
[01:55:36] any record. Let's say we are using a
[01:55:38] password. So, while creating a password
[01:55:41] or while having a password, we might
[01:55:43] want our user to use certain constraints
[01:55:46] like the length should be greater than
[01:55:48] eight or maybe it should have any
[01:55:51] numeric values or it can have one or two
[01:55:54] special characters also. So, all these
[01:55:56] rules which we apply are applied in the
[01:55:59] DB for that particular column through
[01:56:02] the check constraint. Also, the other
[01:56:04] example of this can be a mobile number
[01:56:07] or a phone number. So, a phone number
[01:56:10] will only contain numeric values. It
[01:56:12] can't have any characters apart from
[01:56:14] that. So, this is also a check which we
[01:56:17] can apply for our phone number field.
[01:56:20] Also, the checks can be applied to any
[01:56:22] field. Let's say for first name, we
[01:56:24] can't have any name whose length is less
[01:56:27] than maybe two because A B C D, this
[01:56:30] can't be stored as a name. The shortest
[01:56:32] name I know is Om, right? It is also two
[01:56:35] characters long. So, we want to have
[01:56:38] that check. So, all the checks are
[01:56:39] covered with the check constraint. Now,
[01:56:42] with this,
[01:56:43] let's move to the other constraint,
[01:56:45] which is foreign key. So, let's
[01:56:47] understand foreign key through an
[01:56:48] example. Let's say we are creating a
[01:56:50] blog site where we have users table
[01:56:52] again. So, the users table is basically
[01:56:55] the authors table. Or let me rename it
[01:56:58] to author then.
[01:56:59] So this contains the list of all the
[01:57:01] authors who are going to publish some or
[01:57:03] the other blogs. So there we have this
[01:57:06] ID and then from this ID, let's say we
[01:57:09] only have two fields, first name
[01:57:11] and last name. We can have multiple
[01:57:14] fields if you want. For the sake of this
[01:57:16] example, I'm creating this smaller. So
[01:57:19] let's say we have one and the author is
[01:57:21] Akshat Agarwal.
[01:57:23] Let's say I have two authors. Okay. Now
[01:57:26] these two authors are not going to write
[01:57:29] only single post. They are going to
[01:57:31] write multiple posts. So we will have to
[01:57:33] create a separate table for posts and in
[01:57:36] that post we will have some ID. I'll
[01:57:39] have data or maybe content is the better
[01:57:42] word. So I'll change the name data to
[01:57:44] content. And that content is provided by
[01:57:48] some or the other author. So here we
[01:57:50] will have author ID also. So now let's
[01:57:52] say our post, first post, have some data
[01:57:55] about HTML and who wrote that post?
[01:57:59] Maybe Akshat. So for Akshat, I'm not
[01:58:01] going to write the entire details about
[01:58:04] the author again into this table. So for
[01:58:06] that, what I will use, I'll use the
[01:58:08] common identifier which is our ID. So
[01:58:11] our ID is our primary key here and which
[01:58:14] will be used as the foreign key here. So
[01:58:16] this is our foreign key and we will
[01:58:18] simply write one. With this particular
[01:58:20] information, we are going to get that
[01:58:22] okay, this author ID is one that means
[01:58:25] it is written by Akshat. Similarly, if
[01:58:28] we have multiple fields like this, let's
[01:58:30] say post two is on AI maybe and it is
[01:58:34] created by Gaurav.
[01:58:36] So we don't have to write the entire
[01:58:38] fields or entire information about
[01:58:40] Gaurav. Only the primary key will do.
[01:58:44] So from this two, we are going to again
[01:58:46] recognize that it is written by our
[01:58:48] second author who is Gaurav. So this is
[01:58:50] the role of our foreign key to establish
[01:58:53] the connections between two entities.
[01:58:55] With this, we also have a next
[01:58:58] constraint, which is default. So,
[01:59:00] default basically stands for the area or
[01:59:02] the field where we can't have null. So,
[01:59:05] null is not an option. And we don't want
[01:59:08] our user also to have that entry as a
[01:59:10] mandatory field. We can fill in for
[01:59:13] them. Let's say we are building anything
[01:59:15] for subscription. And if user have not
[01:59:18] paid anything to get a subscription,
[01:59:20] they might be having free as the value
[01:59:23] because they are currently using our
[01:59:25] free subscription. So, this is one case.
[01:59:27] The other case can be, let's say you are
[01:59:30] into our learn.telesco.com, right? So,
[01:59:33] this is our LMS and we are creating
[01:59:34] them. So, in this, every new user or the
[01:59:38] more number of users are going to be
[01:59:40] students only. And only few users are
[01:59:43] going to be managers or trainers or
[01:59:45] maybe admin. So, those are few
[01:59:48] categories and most of them are going to
[01:59:51] be students. So, the default value of
[01:59:54] role for every user here is student.
[01:59:58] Student/learner.
[02:00:00] So, either student or learner, we can
[02:00:02] have as a default role. And with time,
[02:00:04] let's say one or the other student or
[02:00:06] learner got hired into Telesco only to
[02:00:08] maintain the notes or maybe to teach,
[02:00:11] then we will update their role to
[02:00:13] trainer. This is how the system works
[02:00:16] with default. So, these are all the
[02:00:18] constraints which we have in our
[02:00:19] databases. Now comes the next part of
[02:00:22] our relational databases. One of the
[02:00:24] most important part is join. Join is
[02:00:27] basically used to associate two tables.
[02:00:30] That means to manage relationships
[02:00:32] between multiple tables. And why do we
[02:00:34] do that? To basically maintain
[02:00:36] relationships between different
[02:00:37] entities. So, let's see how many joins
[02:00:40] options do we have. The first and the
[02:00:42] most common join option is one to many.
[02:00:46] So, we have a users table. We have ID
[02:00:49] here, and we have F name only.
[02:00:52] Again, I'm going to use the same entry,
[02:00:54] one and two. And here, I can write any
[02:00:56] name. So, here are the two names, Akshay
[02:00:59] and Gaurav. Two entries basically for
[02:01:01] this users table. And again, we are
[02:01:03] creating a blog site. So, that means
[02:01:05] both Akshay can write multiple blogs,
[02:01:08] and Gaurav can also write multiple
[02:01:10] blogs. So, we will create another table
[02:01:13] to maintain our blogs, which will have
[02:01:16] ID, the content, and the author ID. So,
[02:01:19] maybe the first blog, which is on HTML
[02:01:23] again, is written by Akshay. The second
[02:01:25] blog is on AI, which is written by
[02:01:28] Gaurav. And then, there is third blog,
[02:01:31] which is on system design, which is
[02:01:33] created by Akshay. So, here we have one
[02:01:36] to many relationships.
[02:01:38] Because for a single record here, we
[02:01:40] have multiple options or multiple rows
[02:01:43] associated with that particular row. So,
[02:01:45] this is one to many relationship. With
[02:01:47] this, if we reverse this, we can also
[02:01:49] have many to one relationship. So, what
[02:01:52] we will do? Here, we were talking about
[02:01:54] users to blogs relationship. And here,
[02:01:57] we are talking about blogs relationship
[02:01:59] with users. So, here we can safely say
[02:02:02] that multiple blogs are associated with
[02:02:05] the same user. So, here we can have
[02:02:07] multiple blogs associated with the
[02:02:10] single user. So, this is many to one
[02:02:12] relationship. Now, let's move forward
[02:02:15] for our third relationship, which is
[02:02:17] many to many. So, in order to understand
[02:02:19] many to many, let's again go to our LMS.
[02:02:22] So, in LMS, we can have students.
[02:02:25] And we have courses here, right?
[02:02:27] Students also, we have ID maybe, and
[02:02:30] only F name is here right now.
[02:02:33] And in course, we have ID, and then we
[02:02:36] can have the course name here. Now,
[02:02:38] let's fill in some entries here. So,
[02:02:41] here we have students as Akshaya and
[02:02:43] Gaurav. And our courses are Master Java,
[02:02:45] Master AI. Now, Akshaya as a student can
[02:02:49] enroll into multiple courses. So, we can
[02:02:51] sense that from students, we can have
[02:02:54] multiple relationship for courses. And
[02:02:58] also, one course can have multiple
[02:03:01] students. And it is also possible that
[02:03:03] in Master Java, we have both Akshaya and
[02:03:06] Gaurav. So, that means our students
[02:03:09] can enroll into same course. So,
[02:03:12] whenever we see a situation like this
[02:03:15] where we can have many students or many
[02:03:17] records from single table associated
[02:03:19] with the single record of another table,
[02:03:22] and vice versa is also true, we are
[02:03:24] going to get a many-to-many
[02:03:26] relationship. So, in order to maintain
[02:03:27] multiple relationships, we have to have
[02:03:30] a
[02:03:31] junction table in between. So, this is
[02:03:33] our students-courses
[02:03:35] table. And here, we will have a unique
[02:03:38] ID of this particular record. Maybe this
[02:03:41] is required, maybe this is not, based on
[02:03:44] your queries and use cases. Here, we
[02:03:47] will have students ID. And here, we will
[02:03:50] have course ID. And now, while entering
[02:03:52] the data, we can simply say the record
[02:03:54] one, we have Akshaya enrolled in Master
[02:03:57] Java.
[02:03:58] Now, record number two, we have Akshaya
[02:04:01] again enrolled in Master AI. Then, for
[02:04:04] the third record, we have Gaurav
[02:04:06] enrolled in Master Java. And the fourth
[02:04:08] record, Gaurav enrolled in Master AI as
[02:04:11] well. So, with this junction table, we
[02:04:13] are going to figure out how many
[02:04:15] students are enrolled in how many
[02:04:17] courses, and how many courses have how
[02:04:21] many students. I hope this makes sense.
[02:04:23] This is a little confusing if you are
[02:04:25] starting, but this is how we maintain
[02:04:27] many-to-many relationships. With this,
[02:04:29] we can have one more relationship, which
[02:04:31] is one-to-one. Suppose we are building a
[02:04:35] platform like YouTube or blog site which
[02:04:38] also have podcast, which also have maybe
[02:04:42] video section. So, we have three kind of
[02:04:45] content, right? The first content is
[02:04:47] text for blogs. The second content is
[02:04:51] audio, and the third kind of content can
[02:04:53] be video.
[02:04:54] Now, the processing of all these
[02:04:56] contents are different. We can handle
[02:04:58] these multiple options by two ways.
[02:05:01] Either create a common table
[02:05:04] named as contents. So, in content now we
[02:05:07] have three types. For video, we are
[02:05:09] going to store MP4. For audio, we're
[02:05:12] going to store MP3 maybe. And for text,
[02:05:15] we're going to use the text which is
[02:05:16] there in database. We can use varchar,
[02:05:19] long text, short text, maybe text. Now,
[02:05:21] there are three kind of content. We can
[02:05:23] basically divide them by using a field
[02:05:26] which is type. So, in type we will have
[02:05:29] options like text, audio, or video. So,
[02:05:32] here the first record can be on again
[02:05:35] HTML, which is a blog type text type.
[02:05:38] So, we will type one here or text
[02:05:40] directly here. For the next content, it
[02:05:42] can be anything. Let's say the content
[02:05:45] is on improve focus, and in order to
[02:05:47] make that content, we don't have a
[02:05:49] video. So, we have something like audio
[02:05:52] here. And for the third thing, we have
[02:05:54] any video, let's say
[02:05:56] system design.
[02:05:58] And for this video, we have the type as
[02:06:00] video. Now, if you have worked into
[02:06:03] systems with these type of content, the
[02:06:05] processing of each type is very
[02:06:07] different. And if we curate all these
[02:06:09] data into a single table, it is going to
[02:06:12] be a really heavy one. Now, what are the
[02:06:14] drawbacks of having a heavy table? That
[02:06:16] is, whenever we are trying to filter, we
[02:06:19] have to basically filter through each
[02:06:21] and every content type and each and
[02:06:23] every record as well. So, instead of
[02:06:26] having all these kind of data into
[02:06:28] single table, what we can do is we can
[02:06:30] segregate the data already into multiple
[02:06:33] tables and have those IDs as a foreign
[02:06:35] key.
[02:06:36] So, the other approach is we will create
[02:06:39] a simple contents table where we will
[02:06:42] have ID here again and maybe the content
[02:06:46] name.
[02:06:47] And then we will not have the entire
[02:06:49] video or audio. What we will have, we
[02:06:52] will have the ID of that particular
[02:06:54] content. So, that means we are going to
[02:06:55] create multiple tables, one for videos
[02:06:59] and one for audios and one for maybe
[02:07:02] blogs. They all will have a common ID.
[02:07:06] With common ID, I mean their primary key
[02:07:09] and we will use the ID from videos, from
[02:07:11] audios and from blogs into this
[02:07:14] particular table. So, we will not have
[02:07:16] all the data here. Here we will only
[02:07:19] have content ID maybe. And with this, we
[02:07:22] can also have content type. So, this
[02:07:24] type will determine where we need to
[02:07:26] follow. So, this content table will only
[02:07:29] contain all the fields which user can
[02:07:31] search. They can search for name, they
[02:07:33] can search for type, they can search for
[02:07:35] maybe some keywords, some slugs. So, all
[02:07:38] these details will be there in our
[02:07:40] content field. And the actual data, the
[02:07:43] actual content will not be in the
[02:07:44] contents field but in their respective
[02:07:47] tables. So, all the blogs will contain
[02:07:50] all the blogs, all the audios will
[02:07:52] contain all the audio files, all the
[02:07:54] videos will contain all the video files.
[02:07:56] So, now if we have one and type as
[02:08:00] video, we know that one is going to
[02:08:03] fetch some data
[02:08:05] from this videos table where the ID is
[02:08:08] equal to one.
[02:08:09] So, this is one to one relationship.
[02:08:13] Where we know that we are using a
[02:08:15] different entity to our entity and the
[02:08:19] relation between us is one to one.
[02:08:21] Whenever we write one here,
[02:08:23] we are not going to fetch any other data
[02:08:26] and also we are not going to use the one
[02:08:29] again in this table. So, this is
[02:08:31] one-to-one relationship. So, we have
[02:08:32] understood that in relational DB, we
[02:08:35] have entities, right? And we join
[02:08:38] multiple entities through relations.
[02:08:41] That means every entity will have
[02:08:42] particular set of properties, and then
[02:08:45] they will be joined, and we will get the
[02:08:47] data accordingly. Let's understand the
[02:08:49] same thing with the example of posts and
[02:08:51] comments. So, suppose we are building a
[02:08:54] blog site, and in blog site, we have
[02:08:56] some post, and then we have some
[02:08:58] comments. The post table will have some
[02:09:01] ID, unique identifier, then some content
[02:09:05] associated with the post. Now, content
[02:09:07] can be anything, right? It can be
[02:09:08] images, it can again be text, or
[02:09:13] sometimes it can be video, also. So,
[02:09:15] these all are the category of post. Now,
[02:09:18] we have different type of posts, but we
[02:09:21] have to somehow pass those IDs and
[02:09:23] manage three tables for image, text, and
[02:09:28] videos. We can manage them in the same
[02:09:30] table, as well, but that will increase
[02:09:32] our latency, because different kind of
[02:09:34] formats are curated into a single table.
[02:09:37] That will increase the size, right? With
[02:09:39] content, we can also have content type,
[02:09:42] through which we will basically apply
[02:09:43] some filters, if we want to. Now, if we
[02:09:45] talk about it, we already have four
[02:09:48] tables. One for images, one for videos,
[02:09:51] one for text, and one for content. Now,
[02:09:54] we will have comments, as well. So, in
[02:09:57] order to have comments, we will have
[02:09:58] some comment ID, and then we will have
[02:10:00] comment. Now, comment can also be a sub
[02:10:03] comment of a parent comment. So, that
[02:10:05] means we can have a parent kind of
[02:10:08] comment ID, as well. Now, in order to
[02:10:10] handle comments, we have to handle
[02:10:12] users, also. Now, in order to handle
[02:10:14] user, we need one more table. We will
[02:10:16] have ID, maybe name here. So, our number
[02:10:19] again got increased to six. Now, in with
[02:10:22] this PID, we will also have user ID who
[02:10:25] is commenting on our post. So, in order
[02:10:28] to maintain a simple post and comment
[02:10:31] section, we will have to have
[02:10:34] four to five to six tables, right? And
[02:10:37] then we have to maintain the
[02:10:38] relationships as well. So, that means
[02:10:40] even for a small blog site, we will have
[02:10:43] to maintain so much data. And when the
[02:10:45] size of the blogs increase, with that I
[02:10:48] mean this will get hard to scale. Now,
[02:10:51] why I'm saying it is hard to scale?
[02:10:53] First, understand how can we scale any
[02:10:55] database? We have two options only,
[02:10:57] right? First is by scaling them
[02:11:00] vertically, and the second option is by
[02:11:02] scaling them horizontally. In vertical
[02:11:05] scaling, what do we do? We add the
[02:11:07] capacity to a single server. So, that
[02:11:10] means if we are using 4 GB data, we will
[02:11:12] add more space into our server to have
[02:11:15] more data. We can only expand this kind
[02:11:19] of vertical scaling to a extent. After
[02:11:22] that, we will have to use horizontal
[02:11:25] scaling. That means having different
[02:11:26] servers across different places. So, in
[02:11:29] this case, we will have to maintain
[02:11:31] relationships between the different
[02:11:33] entities
[02:11:35] in all of these databases.
[02:11:37] And this will be a tedious task. So, in
[02:11:40] order to avoid this, we can use NoSQL.
[02:11:43] So, we can say the first advantage of
[02:11:45] using NoSQL databases is it is easy to
[02:11:48] scale both vertically and horizontally.
[02:11:52] Because we will have to maintain a
[02:11:54] single document, and we can replicate it
[02:11:57] on different servers or even split them
[02:11:59] into different partitions and pass it to
[02:12:02] different servers. We will understand
[02:12:03] about that also in a bit. Now, what is
[02:12:06] the next issue? The next issue is
[02:12:09] if we are maintaining a table, we can't
[02:12:13] change the table again and again. We
[02:12:15] have some fixed columns, right? We have
[02:12:18] some fixed attributes or columns. We
[02:12:21] can't add or remove different column
[02:12:23] types in order to maintain different
[02:12:25] kind of data. Now, let's say we are
[02:12:28] going to handle the blog site, but this
[02:12:30] time we are going for NoSQL database. In
[02:12:33] this, what we can do now, we can create
[02:12:35] again and content entity and we can
[02:12:39] basically use any kind of content which
[02:12:41] we want. So, we'll create the first
[02:12:43] object and maybe we'll write something.
[02:12:46] Let's say user ID is one, then we will
[02:12:48] write the content. Here, the content is
[02:12:51] an image, so let me pass some URL. https
[02:12:55] maybe something something.jpg.
[02:12:58] Now, when we are adding next content,
[02:13:00] let's we can add it directly into the
[02:13:02] same content document. So, what we'll
[02:13:05] do, we'll again use some user ID. Maybe
[02:13:08] this time it is two and in form of
[02:13:10] content, now we have some textual data
[02:13:13] and we can have some text. Also, if you
[02:13:15] want to use it in a more refined way, if
[02:13:18] you want to add some rows, we can use
[02:13:20] that, right? We can use user ID as
[02:13:23] three, then maybe heading as anything,
[02:13:27] let's say Java, and then maybe we can
[02:13:29] have some description. This is
[02:13:32] description. And like this, we can have
[02:13:35] as many fields as we want. So, that
[02:13:37] means in a single entity content, we can
[02:13:40] have different fields and also we can
[02:13:43] have different number of fields in the
[02:13:45] same document. And if we go about
[02:13:48] relational database, we can't do that
[02:13:50] there, right? So, in these kind of
[02:13:52] scenarios where the document structure
[02:13:53] is not fixed, this is basically called
[02:13:56] schema-less, we need to go for NoSQL
[02:13:59] options because in SQL we don't have
[02:14:01] this option. So, that comes to our
[02:14:03] second advantage of using NoSQL, that is
[02:14:06] we can handle schema-less objects as
[02:14:09] well. So, now let's discuss about third
[02:14:11] point. So, in NoSQL up to now we have
[02:14:14] seen it is easy to scale, then it is
[02:14:17] schema-less and what makes NoSQL more
[02:14:21] feasible is when we don't have to handle
[02:14:24] a lot of linking between different
[02:14:26] entities. That is we don't have to
[02:14:28] maintain a lot of relationships between
[02:14:30] different entities and also every entity
[02:14:33] in a NoSQL database stands on its own.
[02:14:36] Think of this as a key-value pairs.
[02:14:38] Let's say a course ID. ID is the key
[02:14:42] here and in the course content we can
[02:14:45] have anything. We can have only name or
[02:14:49] we can have entire object. Or in third
[02:14:51] place we can have entire course with
[02:14:55] lesson. Of course there are going to be
[02:14:57] nested lessons in a course structure.
[02:14:59] Again with lessons in fourth place we
[02:15:02] can have course which will contain some
[02:15:04] lessons as a nested object and those
[02:15:06] lessons can also contain some comments.
[02:15:09] Now all these things are possible in
[02:15:11] NoSQL which were not there in SQL. If we
[02:15:14] want to have similar structure in SQL we
[02:15:16] have to maintain different entities and
[02:15:18] we have to maintain different
[02:15:19] relationships between them. Here we
[02:15:21] don't have that struggle. So that makes
[02:15:23] our NoSQL work easy. So this is why we
[02:15:26] use NoSQL over SQL and with time it is
[02:15:29] gaining popularity. For example in
[02:15:31] Netflix we use Apache Cassandra in order
[02:15:34] to maintain user activities. In Amazon
[02:15:36] they use DynamoDB in order to scale
[02:15:38] their application. In Facebook or Meta
[02:15:41] they use HBase in order to maintain user
[02:15:44] messaging and large-scale storage. In
[02:15:46] Uber they use MongoDB in order to handle
[02:15:49] flexible and real-time data. And with
[02:15:51] that Twitter or X use Redis for caching
[02:15:55] and timeline purposes. So the conclusion
[02:15:58] is that NoSQL is also being used in
[02:16:00] variety of systems nowadays. Let's
[02:16:03] distinguish it for a bit now. So when we
[02:16:06] should go for SQL and when we should go
[02:16:09] for NoSQL. Whenever we are handling
[02:16:11] payments, we don't have so much variety
[02:16:14] there. So, payments can be easily
[02:16:16] managed through SQL. So, with payments,
[02:16:19] we can also think about transactions or
[02:16:22] any other feature which needs
[02:16:24] consistency where the data is not
[02:16:26] changing, the schema is not changing,
[02:16:27] and also we need to handle those
[02:16:30] relationships perfectly. In all those
[02:16:32] areas where we need consistency, we can
[02:16:35] easily pick SQL. Now, when do we pick
[02:16:38] NoSQL? When we are talking about scaling
[02:16:41] and also we can talk about speed because
[02:16:44] as in NoSQL, we have a single document
[02:16:47] to search from whether in SQL, we have
[02:16:49] different entities or tables who are
[02:16:51] joined through one or more
[02:16:52] relationships. So, we have to traverse
[02:16:54] multiple tables in a SQL database and in
[02:16:57] NoSQL, we don't have to do that. So, by
[02:16:59] that nature, the speed of NoSQL database
[02:17:02] is faster than the speed of SQL one. And
[02:17:05] also, one of the core reasons to use
[02:17:07] NoSQL is
[02:17:08] unstructured data. So, in other words,
[02:17:11] whenever the consistency is on more
[02:17:13] priority than availability, we can
[02:17:16] easily pick SQL. And when availability
[02:17:19] and scalability is on more priority than
[02:17:22] strict consistency, we can choose NoSQL.
[02:17:25] With this, I hope you all get why we use
[02:17:28] NoSQL databases also with SQL and in
[02:17:31] what areas will we pick SQL over NoSQL
[02:17:34] and vice versa. Now that we have
[02:17:36] understood what NoSQL database is and
[02:17:38] why do we use that, let's see some
[02:17:40] examples and application areas of NoSQL
[02:17:43] database. Now, the thing is in SQL, we
[02:17:46] have only considered all the databases
[02:17:49] which will have tables, similar
[02:17:51] relationships, and in NoSQL, there can
[02:17:54] be various ways in which we can store
[02:17:56] data because it is like saying Java and
[02:17:58] NoJava. In Java, we have Java and in no
[02:18:02] Java, we can have many applications,
[02:18:04] right? So, like that, let's start by our
[02:18:07] first example, which is key-value pair.
[02:18:10] Now, if you are a developer or
[02:18:12] developing front-end, back-end, or
[02:18:14] anything, you must have used cache. We
[02:18:17] use the format of key and value whenever
[02:18:19] we are trying to insert some value in
[02:18:20] cache or maybe cookies or in data
[02:18:23] storage. We use this kind of data. So,
[02:18:26] if we talk about key, the only feature
[02:18:29] which a key should have is that a key
[02:18:31] should be unique. And for value, we can
[02:18:34] use any kind of value. We can use
[02:18:36] basically JSON or a string or maybe a
[02:18:41] number. Maybe if you want to add blob,
[02:18:44] we can use that. We can also store it as
[02:18:48] byte array or any array for that matter.
[02:18:51] We can also obviously have objects as
[02:18:53] well and we can also have the
[02:18:55] combinations of them. Like a list of
[02:18:57] object can be stored in an array or an
[02:19:00] object can also have nested objects. And
[02:19:02] with that, obviously, it will be having
[02:19:04] some strings, numbers, blob, byte array,
[02:19:07] or any of that values. Now, the two
[02:19:10] important points here are we don't have
[02:19:12] to follow any structure because the
[02:19:15] NoSQL database follows schema-less
[02:19:17] structure. So, we don't have to follow
[02:19:21] any structure. With that, we also don't
[02:19:24] have to maintain any relationships.
[02:19:26] Suppose, if you want to add post and
[02:19:28] comments, we can simply use any key.
[02:19:31] Let's say post is the key here, post one
[02:19:33] maybe. And in order to have that object,
[02:19:36] we can have any ID, post ID, or any
[02:19:40] content. So, these all things are key
[02:19:42] basically of this object. Post ID can be
[02:19:45] a number. Post content can be anything.
[02:19:47] And with that, we can have comments and
[02:19:51] we can have array of objects in
[02:19:54] comments. We can have multiple comments
[02:19:56] field also.
[02:19:57] Let's say it can have a comment ID and
[02:20:00] the actual content of the comment. Like
[02:20:03] this, it can have multiple objects and
[02:20:05] this all can be done without any
[02:20:07] relationships. So, this is a good
[02:20:09] example of key-value pair, which we
[02:20:10] normally use in our cache, cookies, or
[02:20:13] any other places where we don't need to
[02:20:15] maintain any structure. Now, let's move
[02:20:17] to the second one, columnar DB. So, the
[02:20:19] thing is whenever we are having any
[02:20:21] table, let's say we have student table,
[02:20:23] which have typical ID, a unique
[02:20:25] identifier, the name, and then the
[02:20:28] marks. Maybe total marks of all the
[02:20:30] students. So, ID is one, name is Akshat,
[02:20:35] and marks is maybe 90. With that, let's
[02:20:37] have one more record. The ID is two,
[02:20:40] name is Gaurav, and the marks maybe is
[02:20:44] 95. Now, what we have to do is we have
[02:20:46] to get the average marks of class. So,
[02:20:50] the students is basically maintaining a
[02:20:52] class, we are assuming that, and all the
[02:20:54] marks, if we sum them, we will get the
[02:20:56] total marks, and if we divide them with
[02:20:58] the total number of students, we will
[02:20:59] get the aggregated marks. Now, in order
[02:21:01] to do that, if we do it in a SQL manner,
[02:21:04] the SQL manner basically reads the data
[02:21:07] from left to right. So, even if we don't
[02:21:10] require any name in our data, we have to
[02:21:13] still read our table from left to right
[02:21:16] for each and every row. This is a heavy
[02:21:18] task, right? Because we don't need those
[02:21:20] values. Here, we have only three
[02:21:22] columns. What if we have 17 columns?
[02:21:25] Then also we have to read all the rows
[02:21:26] from left to right, and which is not
[02:21:28] mandatory.
[02:21:29] So, in order to fix this issue, we have
[02:21:31] columnar DB. What columnar DB does is it
[02:21:35] gives us the flexibility to read the
[02:21:37] data column-wise. So, instead of reading
[02:21:40] it row-wise, now we can read the data
[02:21:42] column-wise. That means if you want to
[02:21:45] deal with only marks, we can read only
[02:21:48] marks data column-wise. And then we can
[02:21:51] aggregate all the marks. And if we want
[02:21:53] some other column, those can be also
[02:21:55] read by column-wise. And how we can link
[02:21:59] them? We can link them with the common
[02:22:00] IDs. So, the common IDs will be there
[02:22:03] whenever we are reading column-wise, and
[02:22:05] then it will be easier and faster
[02:22:08] through our unique identifier that is ID
[02:22:10] here. Where we are reading the data, but
[02:22:13] column-wise instead of row-wise. The
[02:22:15] common examples of columnar DB are
[02:22:18] Google BigQuery, Amazon Redshift, and
[02:22:20] Snowflake.
[02:22:22] So, all in all, if we have to read a lot
[02:22:24] of data, we can go for columnar DB. So,
[02:22:26] it is good for analysis. And imagine
[02:22:30] writing the data into columnar DB, that
[02:22:32] is going to take again a lot of time
[02:22:34] because we have to write also
[02:22:35] column-wise. So, that means we have to
[02:22:37] first maintain an ID, and then the name
[02:22:40] will be written, and then the marks will
[02:22:42] be written, and then the other values if
[02:22:44] we have them. Those will be also
[02:22:46] written. So, in order to read the value,
[02:22:49] it is useful. And when it comes to
[02:22:51] write, it is going to take more time
[02:22:54] than a SQL database. The third kind of
[02:22:56] NoSQL database is graph DB. Imagine, we
[02:23:00] have all seen those movies where
[02:23:02] detectives basically pinpoint many
[02:23:04] photos and join them with some thread or
[02:23:07] something, right? So, like this only, we
[02:23:10] have graph DB where we have different
[02:23:13] nodes, and they are joined by the
[02:23:15] threads which are called edge. So, every
[02:23:18] edge basically represent a common
[02:23:20] relationships between two nodes. Two
[02:23:22] nodes are basically the entities, and
[02:23:25] edge signifies the relationship between
[02:23:28] them. Now, what is different in graph DB
[02:23:31] is both nodes and edges can have
[02:23:35] properties. Suppose we are creating any
[02:23:38] node which is student, maybe, and which
[02:23:41] contain all the student information.
[02:23:43] Now, we have another node for course,
[02:23:45] maybe, and we can name the relationship
[02:23:48] anything. Maybe it is enrolled. Now, the
[02:23:50] enrolled can also have properties in it.
[02:23:53] It can contain year, it can contain
[02:23:55] marks. It can contain year of passing
[02:23:58] maybe. And all of these things the edge
[02:24:01] or the relationship can also have. So,
[02:24:03] this is what makes our system unique.
[02:24:05] Graph DBs are often used by data
[02:24:07] scientists to find patterns between
[02:24:10] different scenarios. It works basically
[02:24:12] in the same level which we see in any
[02:24:14] detective movie as well. So, if you want
[02:24:16] to work with graph DB, we can learn
[02:24:19] Gremlin or we can go for
[02:24:22] SparkQL. Also, we can use Cypher in
[02:24:25] order to work with graph DB. As I said,
[02:24:28] it is used in huge companies whenever we
[02:24:30] are dealing with a huge amount of data
[02:24:32] in order to face some patterns or
[02:24:34] basically analyze the customer behavior
[02:24:37] on our site. So, as we can see the two
[02:24:39] entities are going to have some
[02:24:41] properties and also the relationship
[02:24:44] between them will also have some
[02:24:46] properties. Also, two entities can have
[02:24:49] different relationships. And also it can
[02:24:51] be linked via different entities as
[02:24:53] well. So, student basically studies in
[02:24:56] this college. We can write all the
[02:24:58] parameters of the studies edge also. And
[02:25:01] college provides the course. So, in this
[02:25:05] provide relationship also we can have
[02:25:07] multiple properties. So, which makes our
[02:25:10] graph DB complex. And also since we are
[02:25:13] dealing with multiple entities with
[02:25:15] properties and also multiple
[02:25:16] relationship with different properties,
[02:25:19] it is going to be a bit slow. With this,
[02:25:21] let's move to our final and the most
[02:25:23] famous NoSQL database which is document
[02:25:28] DB. So, in document DB we will have some
[02:25:31] document and in that document we can
[02:25:34] write JSON and can store data with any
[02:25:37] length. We don't have to follow any
[02:25:38] structure, we don't have to follow any
[02:25:40] schema. So, that is flexible in nature.
[02:25:43] Also, it is schema-less. So, similarly,
[02:25:46] document DB also don't have to follow
[02:25:48] any relationship. At this point, if we
[02:25:50] think about this, the graph QL is kind
[02:25:52] of an exception on the borderline there
[02:25:54] because we do have relationships between
[02:25:57] them and with relationships, we also
[02:25:59] have properties of those relationships,
[02:26:01] which makes it entirely unique and
[02:26:03] different from no sequel and sequel
[02:26:05] both. But on a large level, it comes
[02:26:07] under the category of no sequel only.
[02:26:09] The common examples of document DB is
[02:26:11] CouchDB and also MongoDB is widely used.
[02:26:15] So, that is also an example of our
[02:26:17] document DB only. Our document DB is
[02:26:20] highly used in logging the systems
[02:26:22] because we need flexible log structures.
[02:26:25] So, it is highly used in logging,
[02:26:27] logging the error, maybe logging the
[02:26:28] warn messages, logging any kind of
[02:26:30] stuff. Also, it can be used to handle
[02:26:33] profile section because the profile
[02:26:35] section can also contain different
[02:26:37] values for different users. Suppose some
[02:26:39] have given all the values, some have
[02:26:41] given less values. So, that can be
[02:26:42] easily maintained through profile. And
[02:26:45] with that, if we talk about content like
[02:26:47] content on any application, let's say
[02:26:50] Instagram, we have different kind of
[02:26:52] content. We can have image, we can have
[02:26:55] video, or we can have some text. If we
[02:26:58] talk about Facebook here. Now, these
[02:27:01] different kind of posts or content don't
[02:27:04] have to go to different tables. In
[02:27:06] document DB, we can basically create a
[02:27:08] single document and curate all of these
[02:27:11] content into the same document,
[02:27:13] obviously with different attributes and
[02:27:15] values. So, again, as it is a no sequel
[02:27:18] DB, it is going to be complex and the
[02:27:20] retrieval of any information will be
[02:27:22] faster. Easily, any no sequel databases
[02:27:25] can be used for any kind of analysis.
[02:27:28] So, this is all about the types of no
[02:27:29] sequel databases. After understanding
[02:27:31] about databases, one thing is very sure
[02:27:34] that each and every important
[02:27:35] information needs to be stored in
[02:27:37] databases and will be retrieved from
[02:27:39] there itself. That means if we have any
[02:27:42] user here who is trying to access, let's
[02:27:45] say telesco.com only from their mobile
[02:27:47] application, the request eventually go
[02:27:50] to our backend and from backend if we
[02:27:54] are showing any information, it will be
[02:27:56] retrieved from the database and will be
[02:27:58] shown to our user. Now, the thing is for
[02:28:01] every information we need to hit our
[02:28:03] database. So,
[02:28:05] even if we have a homepage which have,
[02:28:08] let's say, three most popular courses
[02:28:12] aligned like this. This is our course
[02:28:13] one, course two, and course three. Maybe
[02:28:17] the details of each course are visible.
[02:28:20] One, a thumbnail is visible. Then, with
[02:28:22] that the name is visible. Maybe the
[02:28:25] price is also visible. And with price,
[02:28:29] the discounted price is also visible.
[02:28:32] Also, let's say we are showing some of
[02:28:34] the important sections. So, yeah. These
[02:28:38] are all the details of every course
[02:28:40] which is visible on our homepage. Now,
[02:28:43] this maybe is coming from any DNS
[02:28:46] because that's where we are saving any
[02:28:48] static files, remember? The name will be
[02:28:51] stored in a table. Let's say the table
[02:28:53] name is course or courses. For price, we
[02:28:57] may have the prices in the courses table
[02:28:59] itself, but according to area, according
[02:29:02] to the currency, the price keeps on
[02:29:04] changing. So, we will create a separate
[02:29:07] tables for prices. So, the price is
[02:29:10] coming from price. Then, the discount
[02:29:12] price also based on the locality. So,
[02:29:15] these both details are coming from the
[02:29:16] same place, prices table. And then, the
[02:29:19] important section. Important section may
[02:29:21] have some criteria or some course
[02:29:23] content which we need to show. So, this
[02:29:26] maybe it is coming from courses section
[02:29:28] only, but courses section normally have
[02:29:30] the course main course detail and then
[02:29:33] accordingly we can have different
[02:29:35] sections. So this is maybe courses table
[02:29:37] and we can create some other table which
[02:29:40] will have all the information for
[02:29:42] courses. We can name it as course info.
[02:29:45] So here also the things are coming from
[02:29:48] course info table.
[02:29:50] So that means in order to show these
[02:29:52] three courses we are hitting 1 2 3 and 4
[02:29:57] resources, three tables and one DNS. And
[02:30:00] that means that for every user who is
[02:30:03] trying to access our site telesco.com,
[02:30:05] it is going to hit all of these four
[02:30:07] resources again and again. So if the
[02:30:10] count increases to 10,000 maybe
[02:30:14] daily active users that means we are
[02:30:17] going to hit the database and the DNS
[02:30:20] 10,000 times for each and every user.
[02:30:23] Also don't forget that the courses are
[02:30:25] three.
[02:30:26] Maybe in future we will increase the
[02:30:28] number to six. So that means 10,000
[02:30:31] requests multiplied by six
[02:30:34] that is 60,000 requests. In short, for
[02:30:37] every view we are hitting six courses
[02:30:41] and from those six courses we are
[02:30:43] hitting these four sections. So for
[02:30:46] every user we are hitting 24 requests.
[02:30:49] This is totally going to break our
[02:30:51] system because 24 requests means it will
[02:30:54] add latency to our home page. And in
[02:30:57] these fast times where nobody wants to
[02:30:59] wait for any resources, these latency
[02:31:02] are eventually going to affect our
[02:31:04] business.
[02:31:06] Also the more the latency the poor the
[02:31:08] performance. So this is clearly not a
[02:31:11] good sign. We can't keep hitting our
[02:31:13] databases again and again in order to
[02:31:15] fetch the same information for each
[02:31:17] user. We need some other mechanism. So
[02:31:19] this is where cache comes into the
[02:31:22] picture.
[02:31:23] Now let's understand what cache is.
[02:31:26] Cache is nothing but a memory storage,
[02:31:30] which is away from databases and it can
[02:31:33] either be in our backend or into our
[02:31:35] front end in order to load the resources
[02:31:37] faster. Now, how does it work? Let's
[02:31:39] take the same example. Our user is
[02:31:41] trying to access telesco.com and is
[02:31:45] hitting backend
[02:31:46] to get the information and backend
[02:31:48] eventually is hitting database to get
[02:31:50] the information. Now, once we understand
[02:31:53] that these six courses are going to be
[02:31:55] static on our home page, right? So, that
[02:31:58] means we don't want to fetch this
[02:31:59] information again and again from our
[02:32:01] databases. So, what will we do?
[02:32:04] We will eventually get that particular
[02:32:07] information and put it onto our backend
[02:32:11] either or we can also put the same
[02:32:13] information on our frontend storage as
[02:32:16] well. So, when the user again comes on
[02:32:18] telesco.com, we don't have to hit the
[02:32:20] entire database again and again. We have
[02:32:23] that information handy on our backend or
[02:32:26] frontend or in both the areas. So,
[02:32:29] whenever we hit our home page again, we
[02:32:31] can get those information directly
[02:32:33] through our cache, which is stored
[02:32:36] either on our frontend or on our
[02:32:38] backend. Here, we are saying that our
[02:32:40] user is accessing mobile device. Maybe
[02:32:43] it is accessing our site through any web
[02:32:45] application.
[02:32:46] So, there also we can handle cache,
[02:32:48] okay? These caches, which are on client
[02:32:51] side, are normally referred as client
[02:32:53] side cache. And the data, which we
[02:32:56] stored in backend systems, are referred
[02:32:58] as server side cache. In databases also,
[02:33:02] there is some mechanisms where they can
[02:33:05] also store the information ahead of
[02:33:07] time, that is known as well. And we can
[02:33:10] get the most requested information from
[02:33:12] this data only. We don't need to hit our
[02:33:16] database tables. Also, we can have cache
[02:33:19] in DB as well, which is known as
[02:33:20] database cache. Up to this point, we
[02:33:23] have understand why do we need cache
[02:33:25] from a very high level point. Now, let's
[02:33:27] understand how can we implement the
[02:33:29] caches in the real system. In order to
[02:33:31] understand them, first we have to make
[02:33:33] sure that we know some of the terms.
[02:33:35] The first term which we need to know is
[02:33:37] cache hit. Now, what is cache hit? Cache
[02:33:40] hit basically means let's say we have
[02:33:43] any request which is coming from our
[02:33:46] front end to back end. Let's say we have
[02:33:48] cache installed here and here is our
[02:33:51] final DB. Now, whenever we are hitting
[02:33:54] the request and we found the data in the
[02:33:56] cache, that is known as a cache hit
[02:33:59] scenario where the data is present in
[02:34:01] the cache and we don't need to hit our
[02:34:03] database. But, if the data which we are
[02:34:06] trying to get is not in cache and we
[02:34:08] have to hit our database, that is known
[02:34:10] as cache miss. So, what is cache miss
[02:34:13] here? Cache miss is again we are trying
[02:34:15] to access some data
[02:34:17] from our back end and we don't find the
[02:34:20] data in our cache. Instead, we have to
[02:34:23] get to our database to fetch that
[02:34:25] particular data. So, from where we are
[02:34:27] getting the data in cache miss? We are
[02:34:29] getting it from database. And from where
[02:34:32] we are getting the data in cache hit
[02:34:34] situation? We are getting it from the
[02:34:36] cache itself. So, whenever we hit a
[02:34:38] cache hit kind of situation, our
[02:34:40] responses will be faster. And similarly,
[02:34:42] in cache miss, our responses are going
[02:34:45] to be slower. With this, the next term
[02:34:47] which we need to know is TTL.
[02:34:50] TTL basically means time to live. Time
[02:34:53] to live basically specifies for how long
[02:34:56] the data is going to be in the cache. In
[02:34:58] other words, we can also say after how
[02:35:01] much time our data is going to expire
[02:35:03] from cache. Up to now, I hope we have
[02:35:06] understood what cache really is.
[02:35:08] So, how do we store data in cache? We
[02:35:11] store the data in cache in normally a
[02:35:14] key value form. And we get these data by
[02:35:17] using the keys, obviously, and by value,
[02:35:20] we also have TTL with them.
[02:35:22] In order to check whether the time is
[02:35:25] expired for that particular key-value
[02:35:27] pair or not. If it is expired, this
[02:35:29] key-value pair will be eliminated from
[02:35:32] our cache so that it makes room for
[02:35:34] having more data. So, at this point, we
[02:35:36] understand that the cache works faster
[02:35:39] than our databases. Then, why don't we
[02:35:41] get all the data from our databases and
[02:35:44] put it in cache so that every request
[02:35:46] which we make will be faster. If you
[02:35:48] understand software development, you
[02:35:50] understand that I'm asking a silly
[02:35:52] question. But, if you are new, just hear
[02:35:54] me out. Now, this is those kind of
[02:35:56] question where the answer lies in the
[02:35:58] question itself. We are saying that
[02:36:01] cache is faster. Now, let's understand
[02:36:03] why it is faster. Because we are only
[02:36:06] collecting the information which is
[02:36:09] frequently used. Okay, so that's why the
[02:36:12] size of our cache is very smaller than
[02:36:16] our DB. Because DB have all the
[02:36:19] information which our site needs. So,
[02:36:21] that means the size of cache is limited.
[02:36:24] And we have to keep refreshing the data
[02:36:26] in cache so that it performs well.
[02:36:30] Why do we need to refresh? Let's say
[02:36:32] today we have some campaign of maybe
[02:36:34] selling our most sellable course, maybe
[02:36:37] Java we are selling on the let's go. We
[02:36:39] are saying mastering Java. So, you can
[02:36:42] master Java. This is our most prominent
[02:36:44] course today. But, tomorrow we change
[02:36:46] our focus from Java to maybe AI. Let's
[02:36:49] say most students are not interested to
[02:36:52] learn Java at that time. But, are
[02:36:54] interested to learn AI. At that time, we
[02:36:57] have to replace the content of Java to
[02:37:00] AI.
[02:37:01] So that we can get this information
[02:37:03] faster. Why it is faster? Because it is
[02:37:06] easy to find something in a limited
[02:37:09] space than in the entire database. That
[02:37:12] is why cache is faster. And the second
[02:37:14] point is if let's say somehow we managed
[02:37:17] to create a large size of cache itself
[02:37:20] and we managed to save our entire
[02:37:22] database into cache, in that case, every
[02:37:25] search query or everything which we are
[02:37:26] trying to find is going to take a longer
[02:37:28] time into our cache itself. So, it
[02:37:31] defeats the whole purpose of having a
[02:37:33] cache. That is to reduce the latency and
[02:37:36] to get the performance better. So, with
[02:37:38] this two points are very clear. First is
[02:37:41] the size of our cache needs to be way
[02:37:44] smaller than the size of our DB so that
[02:37:47] we can get the responses very faster.
[02:37:50] And now that we have size constraint, we
[02:37:52] need to keep updating the cache data in
[02:37:55] order to get the values which are
[02:37:57] relevant to our users. Now, I think we
[02:37:59] are very sure what cache is, why the
[02:38:02] size is limited, why do we need to
[02:38:04] refresh the content again and again.
[02:38:06] Now, it's time to go a bit deeper. Let's
[02:38:09] go into the strategies through which we
[02:38:11] can update the cache data. The first
[02:38:14] strategy is read through cache. As the
[02:38:18] name suggests, read through cache
[02:38:20] strategy is designed to handle the reads
[02:38:23] from the cache only, not the rights. So,
[02:38:26] let me create a diagram. Let's say this
[02:38:27] is our server. Here we have our back end
[02:38:30] and our cache and with this we have our
[02:38:33] actual database here. So, read through
[02:38:35] the query suggests that every time we
[02:38:38] have a request of getting any
[02:38:40] information, we are only going to read
[02:38:44] through cache. We are not going to hit
[02:38:46] database. We are only going to read the
[02:38:49] information from cache. And if and only
[02:38:53] if the data is not present in our cache,
[02:38:55] then only we will need to hit our
[02:38:57] database.
[02:38:59] Again, for right, we are not going to
[02:39:01] write any value in our cache. We are
[02:39:03] directly going to write our data into
[02:39:06] our database. So, in order to read, we
[02:39:08] are going to hit our cache, and in order
[02:39:11] to write, we are going to hit our
[02:39:12] databases. Here, clearly, we can have
[02:39:15] two cases. The first case is
[02:39:18] cache hit. In case of cache hit, that
[02:39:20] means we are trying to get some
[02:39:22] information, the back end is going to
[02:39:24] hit our cache, and cache have that
[02:39:26] value, right? Cache returns that value
[02:39:29] to our back end system. So, this is
[02:39:31] good. This means that we are going to
[02:39:33] have a faster retrieval. Then, we have
[02:39:36] our case two for cache miss. What
[02:39:39] happens here is our back end is again
[02:39:42] going to ask our cache whether they have
[02:39:44] the information or not. And in this
[02:39:46] case, as this is cache miss, that means
[02:39:49] we don't have that information into our
[02:39:50] cache. So, here, cache itself is going
[02:39:53] to ask to our database
[02:39:56] and fetch that particular data. So,
[02:39:58] database is going to give that
[02:40:00] information to our cache, and then cache
[02:40:02] will return the data again to BE. So,
[02:40:05] clearly, it adds a next level step to
[02:40:08] get the data from database, which is
[02:40:10] going to make this request call slower.
[02:40:13] So, that means whenever we are reading
[02:40:15] any data, we are not going to go to
[02:40:18] database directly. Our cache will be
[02:40:20] connecting to database and getting the
[02:40:22] value which is required for our back
[02:40:24] end. And from cache, we are going to
[02:40:27] give that value again to back end in
[02:40:29] order to process it. So, here, if you
[02:40:31] see what we are doing, we are not adding
[02:40:33] any recently added data directly to our
[02:40:35] cache. We are adding data directly to
[02:40:38] our databases, and only the data which
[02:40:40] is getting retrieved from our users are
[02:40:43] going to be in our cache. Let's say,
[02:40:45] from our back end, we are making an
[02:40:47] order placement, and that data we are
[02:40:50] not seeing that again. So, that means
[02:40:52] that data is never going to come to our
[02:40:54] cache because no one is accessing that.
[02:40:57] Only the data which user is accessing
[02:40:59] are going to come to our cache, which
[02:41:02] makes our cache always ready with the
[02:41:04] information which user wants. So, this
[02:41:06] is all about RTC. Let's move to the
[02:41:08] second strategy, which is WTC. WTC
[02:41:12] stands for write through cache. As in
[02:41:16] RTC, the strategy is only for reading,
[02:41:18] here this strategy is only for writing.
[02:41:21] So, that means we have again our client
[02:41:24] application. Here we have our backend
[02:41:26] and our cache with our database. Now,
[02:41:29] whenever we are going to write any data,
[02:41:31] we're going to write it into cache and
[02:41:34] then eventually from cache, the data is
[02:41:36] going to be there into our databases.
[02:41:39] So, this means whenever we are writing
[02:41:41] any data, we're going to write it into
[02:41:43] our cache first and from cache, the data
[02:41:46] is going to be written into databases
[02:41:47] finally. So, by doing this, our cache
[02:41:50] data is always going to be updated with
[02:41:53] the latest value. Where it can be used?
[02:41:55] It can be used if we talk about stock
[02:41:57] values, where we always want to see the
[02:42:00] latest data. And with this, it can be
[02:42:02] used to any other application where we
[02:42:03] want to see the latest data first. With
[02:42:06] this, let's move to the third strategy,
[02:42:08] which is WAC. WAC basically stands for
[02:42:12] write around cache. So, up to now, we
[02:42:15] have only talked about either read or
[02:42:17] write. With WAC, we're going to talk
[02:42:20] about read and write both into one
[02:42:22] strategy. So, read around cache. So,
[02:42:26] when it comes to write, we are going to
[02:42:28] write the data from any query from our
[02:42:30] client, it is going to call our backend
[02:42:32] services and from backend, we are
[02:42:34] directly going to write the data into
[02:42:37] our databases. No cache is in between.
[02:42:40] So, that means all the writes will be
[02:42:42] directly dumped into our database. And
[02:42:45] we haven't updated any cache here. So,
[02:42:48] this is about write. And with read, what
[02:42:50] we are doing, whenever we are reading
[02:42:52] any data, we are going to read it always
[02:42:55] from cache. If the data is there in our
[02:42:58] cache, that is a cache hit situation,
[02:43:02] then we're going to get this information
[02:43:04] directly. So, this is good. If we get
[02:43:06] any cache miss kind of situation, where
[02:43:09] the data is not there in our cache, the
[02:43:11] cache is going to call database and
[02:43:13] update the value in the cache first and
[02:43:16] then will give the value to our backend.
[02:43:19] So, this is how WAC works. You may think
[02:43:22] that it is a combination of RTC and WDC,
[02:43:25] which is correct. So, in RTC and WDC, we
[02:43:28] are only talking about read and write
[02:43:31] respectively. But, in WAC, we are
[02:43:33] talking about the entire flow of data.
[02:43:36] So, it is heavily used in applications
[02:43:39] like Twitter. Now, it is called X. So,
[02:43:42] here the scenario is we have a lot of
[02:43:45] users who are going to create tweets.
[02:43:49] But, we can't directly create those
[02:43:51] tweets and save them in our cache,
[02:43:52] right? And whenever the users are trying
[02:43:56] to access any tweet, at this point it is
[02:43:58] decided to keep this tweet in cache
[02:44:01] memory because now it can be used by
[02:44:04] some other users as well. So, we don't
[02:44:07] decide the importance of any tweet at
[02:44:10] the time of its creation. We decide the
[02:44:13] importance at the time of reading those
[02:44:14] tweets, right? So, with WAC, we also
[02:44:17] have one more strategy, which is WBC.
[02:44:21] WBC basically stands for write back
[02:44:25] cache, which basically means whenever we
[02:44:27] are trying to write any data, it is
[02:44:30] going to be written into our cache and
[02:44:32] at this point our write operation is
[02:44:34] completed. We are going to write this
[02:44:36] data into our database, but this is an
[02:44:39] async process. So, that means while
[02:44:42] writing our data, we don't care about
[02:44:45] consistency much, but we care about
[02:44:47] speed. We want to get the update faster.
[02:44:51] So, whenever we write any data into our
[02:44:52] cache, it is going to give us the okay
[02:44:56] response, maybe.
[02:44:57] And after that, the data will be dropped
[02:45:00] into our databases eventually. Now, as
[02:45:03] this is async process, it is very
[02:45:06] possible that we may get some or other
[02:45:09] error here.
[02:45:11] So, we have to handle this kind of
[02:45:12] scenario or strategy very carefully. And
[02:45:15] now, let's talk about read. While
[02:45:17] reading the data, again, we are going to
[02:45:19] read the entire data from our cache
[02:45:21] itself, right? That is the whole point
[02:45:23] of having a cache. So, as most of our
[02:45:26] data is directly written into cache, it
[02:45:29] is most likely to have the most updated
[02:45:31] values. So, normally, it is going to
[02:45:33] give cache hit. And if we get cache miss
[02:45:37] kind of situation, so we are again going
[02:45:39] to call our database, update our cache,
[02:45:42] and from cache, we are again going to
[02:45:45] read the value from our application. So,
[02:45:47] as you can see the WAC and WBC are
[02:45:50] pretty common, but here we are using
[02:45:53] async to write the data. That means we
[02:45:56] are trading off between speed and
[02:46:00] consistency. So, even if our data is not
[02:46:03] consistent, we are making sure that the
[02:46:05] speed of application remains fast. Now,
[02:46:08] WBCs are basically used where we have a
[02:46:11] high write traffic. The most common
[02:46:14] example of this can be any food delivery
[02:46:17] application. Let's say Swiggy or Zomato.
[02:46:20] So, in Zomato or Swiggy kind of
[02:46:22] application, what normally happens is at
[02:46:25] a particular time, we may be handling
[02:46:27] multiple orders with multiple status.
[02:46:30] And the status keeps on changing. So,
[02:46:32] instead of saving all the data changes
[02:46:35] into our database, we choose to save
[02:46:38] them into cache. Because we know that
[02:46:41] the status of this particular order will
[02:46:43] change very fast. So, we use WAL here
[02:46:47] because we need to update the
[02:46:49] information fast and also the user who
[02:46:52] have created the order are also going to
[02:46:55] see the latest information through this
[02:46:56] cache only. And in the back process or
[02:46:59] in the backend or async manner, we are
[02:47:02] going to keep updating our databases.
[02:47:04] So, this way it is going to handle
[02:47:06] million of request and status updates at
[02:47:09] a particular time. So, up to now we have
[02:47:11] understood that how do we handle the
[02:47:13] data into our cache? But, we have only
[02:47:16] added the data. We haven't deleted the
[02:47:18] data. So, now let's understand the cache
[02:47:21] eviction policies through which we are
[02:47:23] going to remove the data which is not
[02:47:25] used by our cache. Here I'm writing
[02:47:28] policies here. We can easily use
[02:47:30] strategies. I just wanted to sound
[02:47:32] little different. So, that's why I added
[02:47:33] policies.
[02:47:35] Um just for fun, you may say. So, the
[02:47:37] first policy basically is LRU. LRU
[02:47:42] basically stands for least recent used.
[02:47:47] So, as the name suggest, least recent
[02:47:50] used.
[02:47:51] That means the data which is not used
[02:47:54] recently will be evicted from our cache.
[02:47:57] Suppose Apple launches a new iPhone
[02:48:00] which is 17 Pro
[02:48:03] Max updated something something very
[02:48:07] acronym synonyms of Pro Max Ultra
[02:48:09] something. And now everyone is keep
[02:48:12] looking for 17 Pro. No one is in today's
[02:48:15] time looking for 11. So, that means 11
[02:48:19] is a stale data which was used earlier
[02:48:22] by our cache maybe. But, in today's time
[02:48:25] we don't need to store that information
[02:48:27] into our cache because a very few clicks
[02:48:30] were there who were still searching for
[02:48:32] 11. Now, with this let's talk about the
[02:48:35] second policy which is MRU, the exact
[02:48:39] opposite of LRU.
[02:48:40] There we were saying least here we will
[02:48:43] say most recent used. So here we are
[02:48:46] going to delete the data which is most
[02:48:48] recently used. This sound a bit strange,
[02:48:51] right? Why do we delete something which
[02:48:52] is most recently used?
[02:48:54] But if you think about it, let's say you
[02:48:57] are surfing through an e-commerce
[02:48:58] application and you already apply a
[02:49:00] particular coupon. So in that case we
[02:49:03] don't need that particular coupon into
[02:49:05] our cache, right? So we will directly
[02:49:07] remove that. Also, if you think about
[02:49:10] it, we have streaming applications. For
[02:49:12] example, let's say this YouTube only. So
[02:49:14] in YouTube's the streaming normally
[02:49:17] happens in sections. When you are
[02:49:19] watching any video, let's say you have
[02:49:21] watched the video till here. At this
[02:49:23] point this data gets loaded.
[02:49:26] And you may see a white line moving
[02:49:29] forward which denotes that the data up
[02:49:32] to that point is loaded right now. Let's
[02:49:35] say currently we are at this point and
[02:49:37] this data is already loaded. Now at this
[02:49:39] point we don't need the previous video
[02:49:41] information. This can easily be deleted
[02:49:44] from our cache at least.
[02:49:47] Because in this case the chances of me
[02:49:50] going back into the video is very slow.
[02:49:52] So that's where we remove the most
[02:49:54] recently used data. So I hope you are
[02:49:57] getting all the points. The next part,
[02:49:59] the next eviction policy is LFU. LFU
[02:50:03] basically stands for least frequently
[02:50:07] used. So LFU basically means the data
[02:50:09] which is not frequently used will be
[02:50:12] evicted from our cache. What does that
[02:50:14] mean? Let's say today I opened any e-com
[02:50:18] application and search for plant. Also,
[02:50:21] I am a gadget guy. I basically purchase
[02:50:24] a lot of gadgets. So suppose I have a
[02:50:27] history of seeing any secondary screen
[02:50:31] also. With that I also purchase a lot of
[02:50:33] clothes. So clothes section is also
[02:50:36] there. Now, between these three, I keep
[02:50:39] on seeing about the secondary screen and
[02:50:41] I keep on seeing the clothes in one or
[02:50:44] the other manner, but the plant search I
[02:50:47] only did once. Maybe I saw some YouTube
[02:50:50] video or liked some plant into some
[02:50:53] Instagram story of others. Only at that
[02:50:55] time I thought of purchasing a plant and
[02:50:58] after that I didn't think about it
[02:51:00] again.
[02:51:01] So, that means the plant is the least
[02:51:04] frequently used terms for my history of
[02:51:07] that e-commerce applications. So, now
[02:51:09] whenever we are going to evict any data,
[02:51:11] it is going to be this. So, this is
[02:51:13] another strategy where we remove the
[02:51:16] least frequently used data from our
[02:51:19] cache. After LFU, we have two standard
[02:51:22] ways of handling cache data or removing
[02:51:25] the cache data. The first strategy is
[02:51:27] FIFO. We all know about it. FIFO
[02:51:30] basically stands for
[02:51:32] first in, first out. Suppose we have
[02:51:34] assigned 180 MB to our cache and we
[02:51:37] don't want to exceed this limit.
[02:51:40] Now, whenever we are trying to add any
[02:51:42] value and and if we have reached our
[02:51:44] limit, first data which we are going to
[02:51:47] remove is the first data which we
[02:51:49] entered into the cache without thinking
[02:51:51] about anything, without thinking about
[02:51:52] frequency, without thinking about how
[02:51:55] recently they are being used. We will
[02:51:57] simply remove the first added data from
[02:52:00] our cache. And with this we have the
[02:52:02] last eviction policy which is LIFO. LIFO
[02:52:05] basically stands for last in, first out.
[02:52:08] You may think of a stack kind of
[02:52:10] situation here, right? Where the last
[02:52:12] object which is inserted will be evicted
[02:52:15] first.
[02:52:16] So, this is how LIFO works. So, in this
[02:52:19] what we will do, again we have 180 MB
[02:52:21] memory and here we I have written bytes.
[02:52:24] Here it is bits. Don't worry about that.
[02:52:26] It doesn't matter. Now, in that 180 MB
[02:52:30] memory, I don't want to store any other
[02:52:32] information. So, what information will I
[02:52:35] remove? I'll remove the most recent
[02:52:37] information which I added. Okay? So,
[02:52:40] maybe this information which is added
[02:52:42] first
[02:52:44] will be there for the longest time, and
[02:52:47] we will keep on removing this or this or
[02:52:49] this information in order to have more
[02:52:52] space for the added information. So,
[02:52:54] this is about LIFO and FIFO. I have not
[02:52:57] added any application areas for LIFO and
[02:52:59] FIFO both. I want you to explore this a
[02:53:02] bit and tell me in the comments. And
[02:53:05] with this, we have understood about
[02:53:06] caches, their eviction policies, and how
[02:53:09] do we add the data into our cache. I
[02:53:12] hope you all get it. Up to now, we have
[02:53:14] understood how our request basically
[02:53:16] flows through different components of
[02:53:18] our system and ultimately provide some
[02:53:20] information to our user. Right? We have
[02:53:23] seen who our customer is. They're going
[02:53:26] to interact with either some web
[02:53:28] application or maybe some mobile
[02:53:30] application.
[02:53:31] From where the request will flow to a
[02:53:34] server where our back-end code is, and
[02:53:36] through the server, we will hit some or
[02:53:39] the other database in order to retrieve
[02:53:41] that information and provide it back to
[02:53:43] the user. With this, we have also
[02:53:45] discussed about DNS through which our
[02:53:48] clients are going to get the address of
[02:53:50] our server. And then, the cycle repeats.
[02:53:53] So, this is all we know up to now. This
[02:53:55] all looks very good, works very
[02:53:57] efficiently up to a single point. Why?
[02:54:00] Because here we are using only single
[02:54:03] server, and a single server can scale
[02:54:05] only up to certain limits.
[02:54:07] Suppose we are already using 128 GB of
[02:54:12] our server, and somehow our processes
[02:54:15] are consuming this much resources. That
[02:54:17] means we are getting more requests than
[02:54:19] we were expecting. Maybe our app is
[02:54:22] tracking attraction now from across the
[02:54:24] globe. And at that time, we have no
[02:54:26] choice but to scale our system. In order
[02:54:29] to scale the system, this is the first
[02:54:31] step which you can think of.
[02:54:33] So, instead of having a single server,
[02:54:35] we need to have multiple servers. Let's
[02:54:39] name them server one and server two.
[02:54:42] So, we have two servers. That means our
[02:54:44] client need to give the call to either
[02:54:47] server one or server two. But, how our
[02:54:50] client is going to decide where to give
[02:54:52] information to? This is where we need to
[02:54:54] discuss one more component which is load
[02:54:56] balancer. Now, let's make the diagram
[02:54:58] again with load balancer. Now, what
[02:55:00] happens? Our client or the user is going
[02:55:04] to access the same information from any
[02:55:06] mobile application or website, and they
[02:55:09] are going to hit DNS in order to get the
[02:55:13] IP address of server. Up to now, things
[02:55:16] are not changing. Everything is pretty
[02:55:17] straightforward. But, now our DNS is not
[02:55:21] going to give the IP address of the
[02:55:22] actual server, but it is going to give
[02:55:24] the IP address of load balancer. And
[02:55:27] then, the load balancer is connected to
[02:55:30] multiple servers. Suppose this is server
[02:55:32] one,
[02:55:33] this is server two, this is server
[02:55:35] three. And then, the load balancer
[02:55:37] basically decides to which server our
[02:55:40] request should go to, whether it should
[02:55:41] go to S1, S2, or S3. And if it goes to
[02:55:46] S1, S2, and S3, they are basically going
[02:55:48] to connect to a database. Maybe they are
[02:55:50] connected to same database, or there can
[02:55:53] be a possibility that S3 is managing the
[02:55:56] data in some other database, and through
[02:55:58] migration, replication, or partitioning,
[02:56:00] we are handling the data between those
[02:56:02] databases as well. So, this is what the
[02:56:05] actual picture of a microservice
[02:56:07] applications looks like. Where the load
[02:56:10] balancer is going to play a huge role in
[02:56:13] order to pass those requests from client
[02:56:16] to server. Now, if we talk about load
[02:56:18] balancer in brief, our load balancer
[02:56:21] mainly is going to perform two tasks.
[02:56:23] The first task is how do it give
[02:56:26] responses to the perfect server from
[02:56:28] which it can get the response faster,
[02:56:31] right? So, the first thing is choosing
[02:56:34] the server. Also, if we are giving the
[02:56:36] responsibility of choosing the server to
[02:56:38] load balancer, that means load balancer
[02:56:40] should know how our servers are
[02:56:42] performing in the current situation. So
[02:56:44] that no server will be overheated and no
[02:56:47] server will be underutilized. So, the
[02:56:50] second thing
[02:56:51] which load balancers are going to do is
[02:56:54] maintaining the health checks of our
[02:56:57] server. So that whenever any new request
[02:56:59] comes to load balancer, they are the one
[02:57:02] who is going to decide whichever server
[02:57:04] is working in a fine condition plus can
[02:57:07] handle that request pretty well.
[02:57:09] So now, let's discuss these both points
[02:57:11] one by one. So, in order to choose a
[02:57:14] server, we need some algorithms, right?
[02:57:16] So, there are various algorithms and
[02:57:18] hybrids also from which our load server
[02:57:21] decides where the request should go. So,
[02:57:25] let's discuss those algorithms. The
[02:57:27] first algorithm here is round robin.
[02:57:30] Round robin is the most simplistic
[02:57:32] approach in order to pick the web server
[02:57:34] for the next request. So, in round
[02:57:36] robin, what do we do? Suppose this is
[02:57:38] our load balancer and we have our server
[02:57:41] one here, server two here, and server
[02:57:43] three here. Load balancer is now going
[02:57:46] to pick server one for the first
[02:57:49] request. For second request, it is going
[02:57:51] to pick server two. For third request,
[02:57:53] it is going to pick server three. And
[02:57:55] where will the fourth request go? It
[02:57:57] will again go to server one. Then five
[02:58:00] for server two and six for server three.
[02:58:02] And this is how every request will keep
[02:58:05] generating and going to the next server
[02:58:07] which is in the list. So, there is no
[02:58:09] much calculation needed here. We only
[02:58:11] need to know that we are following the
[02:58:13] sequence of S1, S2, and S3. And if the
[02:58:16] current request is being processed by
[02:58:18] S2, the next request is going to be on
[02:58:21] S3. This is how round robin works. So,
[02:58:24] that means round robin send request one
[02:58:27] by one, right? Apart from this, it
[02:58:30] doesn't check anything, which makes the
[02:58:32] round robin very easy to implement. That
[02:58:35] means if you are using round robin
[02:58:37] algorithm, each server are going to
[02:58:40] handle almost equal number of requests.
[02:58:42] So, we can say the distribution of
[02:58:45] requests are equal. And as in this
[02:58:48] algorithm, we are not managing any state
[02:58:50] of any server, basically, we'll manage
[02:58:53] only a single counter from which we are
[02:58:56] going to decide where the next request
[02:58:58] is going to be. And also, we need to
[02:59:00] manage where the current request is. So,
[02:59:04] with simple implementation, we can
[02:59:05] easily set up round robin into a load
[02:59:08] balancer. But, there are some demerits
[02:59:10] to it. What if server one, server two,
[02:59:13] server three doesn't have equal
[02:59:15] configurations? What if the RAM
[02:59:17] configuration between them is different?
[02:59:20] What if the storage is different? What
[02:59:23] if the CPU power is different? Let's say
[02:59:26] for S1, RAM is 4GB.
[02:59:29] For S2, it is 8GB.
[02:59:32] For S3, it is 16GB.
[02:59:35] Again, the storage, let's say for server
[02:59:38] one, we are using maybe 100GB storage.
[02:59:42] For server two, we are using 200GB
[02:59:44] storage. And for server three, we are
[02:59:46] using 500GB of storage. Also, the CPU,
[02:59:50] let's say it is 16 core, it is 32, it is
[02:59:53] 64 core. So, the configurations are
[02:59:56] entirely different. And what we are
[02:59:57] doing in round robin, we are not
[02:59:59] checking any of these matrixes, but we
[03:00:02] are simply following the next counter.
[03:00:04] So, that means even if with uneven
[03:00:07] configurations,
[03:00:08] the load on server one, server two, and
[03:00:11] server three are going to be same. And
[03:00:13] this is unfair because the server three
[03:00:16] may do all the task very frequently and
[03:00:18] can sit idle. Whereas server one will
[03:00:21] struggle to complete the task and it
[03:00:24] will be overloaded, maybe heat up, maybe
[03:00:26] stop working. So, this is the demerits
[03:00:29] of using round robin. Now, let's jump to
[03:00:31] the second algorithm, which is
[03:00:33] geo-based, which basically states that
[03:00:37] suppose this is our load balancer and we
[03:00:39] have our server one again and server two
[03:00:42] again. This is in India and this is in
[03:00:46] US. So, if the majority of users are
[03:00:50] from India and some users are from US,
[03:00:53] that means they need to hit their
[03:00:55] respective servers in order to process
[03:00:57] the information. That way,
[03:01:00] they will get the response faster
[03:01:03] because if I'm sitting in India and I'm
[03:01:05] requesting any information from the
[03:01:06] Indian server, it will be faster to
[03:01:09] process those information in the Indian
[03:01:10] server as well with respect to
[03:01:12] processing the same information through
[03:01:14] US servers because the connections are
[03:01:16] going to take time and which will
[03:01:18] increase the latency of the application,
[03:01:20] which the user doesn't want, right? So,
[03:01:22] this is what our second algorithm
[03:01:24] implies. It is based on geo addresses of
[03:01:28] the particular user. So, here also we
[03:01:30] are not maintaining any matrices for
[03:01:32] server specifications. We are only
[03:01:34] maintaining two matrices. The number one
[03:01:37] matrix is where the server is and the
[03:01:40] second matrix is from where are we
[03:01:42] getting the request or we can say where
[03:01:45] the user is. Now, this algorithm is used
[03:01:48] by many applications across the world
[03:01:50] whichever have the global appearance.
[03:01:53] Whenever we are trying to hit google.com
[03:01:55] or facebook.com or any other global
[03:01:57] applications, our request basically
[03:02:00] moves to the server whichever is closest
[03:02:03] to us. Maybe we are residing in this
[03:02:05] area. Here we have some server and also
[03:02:08] here we have some server. Maybe this is
[03:02:10] US server, this is Indian server.
[03:02:13] So, our server needs to be situated near
[03:02:16] us so that we get the response faster
[03:02:19] and all the requests are maintained
[03:02:21] through the same server. So, whenever
[03:02:23] I'm trying to access any information,
[03:02:25] they are going to be addressed through
[03:02:27] the same server. So, that means our
[03:02:29] session and other informations are also
[03:02:32] will be in sync for this particular
[03:02:34] user. In this algorithm, there are some
[03:02:37] disadvantages as well, right? Because
[03:02:39] now our load server needs to manage more
[03:02:42] information.
[03:02:43] Now, it needs to know from where the
[03:02:46] requests are coming and it needs to know
[03:02:48] where each and every server is located.
[03:02:51] So, this is a lot of information to be
[03:02:54] seen by load balancer. And now as our
[03:02:56] servers are distributed across the
[03:02:58] globe, we also need to maintain
[03:03:01] databases accordingly. So, every region
[03:03:04] may have their own databases for faster
[03:03:06] retrieval. So, that will include the
[03:03:08] computation power of replication and
[03:03:10] partitioning, which we will be covering
[03:03:12] in further series. Also, let's say
[03:03:16] if we are using Indian server or this
[03:03:18] server particularly, maybe there are two
[03:03:20] servers in India. This is India B
[03:03:22] server, this is India A server. For some
[03:03:25] reason, this server breaks down.
[03:03:28] Then we need to reroute our request to
[03:03:30] this particular server, which is again
[03:03:33] needs all the information which we are
[03:03:34] accessing through this server. That
[03:03:36] means the data or the application on
[03:03:38] which we are working on should transfer
[03:03:40] the data immediately to this server as
[03:03:43] well. Even if the server A doesn't
[03:03:45] crash, then we need all the information
[03:03:47] which is being tracked by server A. But
[03:03:50] this is a necessity in geo-based
[03:03:52] location algorithm. Now, the third point
[03:03:54] here is if any user is using VPN or
[03:03:58] other proxy servers to change their
[03:04:00] location, that means VPN or proxies can
[03:04:03] mislead the traffic. With this, let's
[03:04:05] move to our next algorithm, which is
[03:04:07] least connection algorithm. So, in this,
[03:04:10] what happens is we have our load
[03:04:12] balancer in place.
[03:04:14] And suppose we have two servers, server
[03:04:16] one and server two. And server one and
[03:04:19] server two at current times are managing
[03:04:22] multiple requests, right? Suppose S1 is
[03:04:26] maintaining
[03:04:27] 30 requests or 30 connections at this
[03:04:29] particular time and S2 is maintaining 50
[03:04:32] connections.
[03:04:33] Now, whenever we get a new request, it
[03:04:36] is going to be addressed by S1. Why?
[03:04:39] Because S1 currently is having least
[03:04:41] connections.
[03:04:43] So, this is how our least connection
[03:04:45] algorithm works. Whichever server have
[03:04:48] the least connections, our next request
[03:04:50] is going to that particular server. In
[03:04:52] this algorithm also, we are not
[03:04:54] considering any of the matrices of
[03:04:57] server. We are also not maintaining any
[03:04:59] of the requests or response time. We are
[03:05:02] only maintaining the number of
[03:05:04] connections. Let's say if these 30
[03:05:07] requests are heavy request and these 50
[03:05:10] are lightweight, then also the next
[03:05:13] request is going to be taken care by S1,
[03:05:16] which is wrong and it is going to take
[03:05:18] time, but this is how our least
[03:05:20] connections work. Then why do we use
[03:05:22] this? Basically, the least connection
[03:05:24] algos works very well when there are
[03:05:26] sticky sessions. Now, what is sticky
[03:05:29] session? Where we have to maintain a
[03:05:32] proper channel for a particular
[03:05:33] communication. Let's say we are using
[03:05:35] web sockets for maintaining any kind of
[03:05:38] application. Let's say we are
[03:05:39] maintaining a chat application or a
[03:05:41] video streaming application or maybe we
[03:05:44] are handling some gaming kind of setup.
[03:05:47] In all of these cases, we needs the
[03:05:49] request and response to be faster, so we
[03:05:52] will pass our request to those servers
[03:05:55] who are having least connections
[03:05:57] currently so that we can get the
[03:06:00] response faster. Now, if we talk to
[03:06:03] disadvantages, the first disadvantage is
[03:06:05] this only heavy and lightweight. Maybe
[03:06:07] these calls are for AI calls which are
[03:06:09] going to take time and these calls are
[03:06:12] basically chat calls or maybe some web
[03:06:14] CTR calls or maybe some REST API calls
[03:06:17] which are lightweighted normally. So,
[03:06:19] they are working faster then also we
[03:06:22] will send the next request to 30 until
[03:06:24] the number of connections drops from 50
[03:06:26] to maybe 29. Then only we will consider
[03:06:29] S2. So, this is how we are going to
[03:06:31] work. Now, if we talk about
[03:06:33] disadvantages of least connections, the
[03:06:35] first we already discussed. The second
[03:06:38] disadvantage is that our load balancer
[03:06:40] basically needs to maintain the number
[03:06:42] of connections for each web server. So,
[03:06:45] if S1 is maintaining 50 connections at
[03:06:48] that time and it give response to one of
[03:06:50] them, that means currently it is
[03:06:52] maintaining 49 connections. It needs to
[03:06:55] be updated to load balancer. So, our
[03:06:58] node balancer will keep updating the
[03:07:01] number of connections again and again
[03:07:03] which is of course a tedious task. The
[03:07:05] third disadvantage is we are only
[03:07:07] considering least number of connections.
[03:07:10] What if our server one is of very low
[03:07:13] configuration than server two
[03:07:15] and it is maintaining eight connections
[03:07:17] at that time or request at that time and
[03:07:20] this is maintaining 16.
[03:07:22] It is easy for S2 to maintain 16
[03:07:24] connections or maybe 100 connections and
[03:07:26] it is hard to maintain 10 connections
[03:07:28] for S1. Then also we will send the next
[03:07:31] request to S1 because we are not
[03:07:33] checking anything apart from number of
[03:07:35] connections. So, this is how our least
[03:07:37] connection algorithm is going to work.
[03:07:40] After least connections come least time.
[03:07:43] So, it is our fourth algorithm least
[03:07:46] time algo. Suppose load balancer is
[03:07:50] maintaining two web servers S1
[03:07:53] and S2. The response time of S1 is
[03:07:57] nearly about 50 ms. The average response
[03:08:01] time, basically. It is handling some
[03:08:03] thousand requests, and for server two,
[03:08:05] it is currently 10 ms. So, in this
[03:08:08] scenario, the next request is going to
[03:08:10] be handled by server two. Because the
[03:08:13] average response time of server two is
[03:08:15] lesser than the average response time of
[03:08:18] server one. Now, if we talk about
[03:08:20] response time, if any server is having
[03:08:22] less response time, that means the
[03:08:24] configurations of those servers are
[03:08:27] high. Right? That's why the response
[03:08:29] time is low. So, this algorithm
[03:08:32] basically takes care of the actual
[03:08:33] matrices of the server by taking the
[03:08:35] response time into measure. Now, the
[03:08:37] least time algorithm is used in those
[03:08:39] applications where we can't handle more
[03:08:42] latency. That can be our real-time
[03:08:44] applications, like the trading app or
[03:08:47] even our search engines. In both of
[03:08:50] these areas, we want the responses to be
[03:08:52] very fast, and that's why we use least
[03:08:54] time algorithms there. And now, if we
[03:08:56] talk about least time algo's
[03:08:58] disadvantage, that is our load balancer
[03:09:02] needs to calculate the average response
[03:09:04] time. So, with each request they are
[03:09:06] sending to server, also the average
[03:09:09] response time will be calculated. And
[03:09:11] based on this, our load balancer needs
[03:09:14] to manage where the next request is
[03:09:16] going to be. So, calculating these
[03:09:18] things can be really complex because if
[03:09:20] we are calculating average time, that
[03:09:22] means we need to know number of maybe
[03:09:24] requests, and also the response time of
[03:09:28] each and every response. Then only our
[03:09:32] load balancer is going to calculate the
[03:09:33] average response time. So, this is for
[03:09:36] sure complex. Now, in this scenario, if
[03:09:39] our web servers maintain any kind of
[03:09:41] spike, it is going to affect the
[03:09:43] calculations of our load balancer. So,
[03:09:45] we need to be very careful there. Now,
[03:09:47] let's talk about the fifth algorithm,
[03:09:49] which is IP hash. Here, as the name
[03:09:52] suggests, the IP of every request is
[03:09:56] going to be processed by our load
[03:09:58] balancer and will be given a unique
[03:10:00] number.
[03:10:02] And according to those numbers, our
[03:10:04] servers are going to decide. Let's say
[03:10:06] our server one is maintaining the hash
[03:10:08] values from one to 10. So, that means
[03:10:10] all the IPs which results between this
[03:10:13] range are going to be addressed by S1
[03:10:15] and maybe from 11 to 20 are addressed by
[03:10:18] S2.
[03:10:19] So, this is how IP hash algorithm works.
[03:10:23] Every request is associated with some of
[03:10:25] the other IP. They are going to process
[03:10:27] through a hash function, and suppose the
[03:10:29] result is five, then it is going to be
[03:10:32] addressed by S1 because S1 is
[03:10:34] maintaining one to 10. As we all know,
[03:10:36] the IP of any user normally doesn't
[03:10:39] change. That means this user for at
[03:10:41] least one session is going to be
[03:10:43] addressed through the same server. And
[03:10:45] it will help. Basically, if we are
[03:10:47] maintaining any session data, it is
[03:10:49] going to help because we don't need to
[03:10:50] replicate this data to other servers. We
[03:10:52] are only handling these requests through
[03:10:55] the same server. So, it is very easy.
[03:10:57] Now, if the connection breaks in between
[03:11:00] the session, then we are in problem. In
[03:11:03] that case, this next request will go to
[03:11:06] S2, and we need all the session data
[03:11:08] here. And if that data is not
[03:11:10] maintained, our user may need to address
[03:11:13] or add the same data again into server
[03:11:15] two, which is a loss case, which is not
[03:11:17] recommended at all. So, for this to work
[03:11:19] efficiently, our server basically needs
[03:11:21] to be healthy enough to maintain a
[03:11:23] proper session. Plus, even if the
[03:11:26] session breaks due to any reason, due to
[03:11:28] any server crash, it is very important
[03:11:31] to replicate those data to other server
[03:11:33] as well. The major disadvantage of this
[03:11:36] is, as we are basically focused on IP
[03:11:39] functions and hash functions, so scaling
[03:11:42] is challenging here. Let's say we are
[03:11:43] adding S3 here, then we again needs to
[03:11:47] reconfigure our hash function. So, that
[03:11:50] it consider S3 as well. And also, we
[03:11:52] need to reassign these values also.
[03:11:55] Maybe next time it is only handling 1 to
[03:11:58] 8, and maybe it is handling
[03:12:00] uh
[03:12:01] 9 to 12 maybe, and this one is handling
[03:12:04] 12 to 20. So, whenever any server is
[03:12:07] down or we are adding any new server,
[03:12:10] basically the function will get affected
[03:12:12] and it will reassign all the values to
[03:12:14] the entire server. This is hard to scale
[03:12:16] in this manner. And that's why it is not
[03:12:19] recommended for most of the
[03:12:21] microservices architecture we have
[03:12:23] today. It is basically used where the
[03:12:25] data was used in the old kind of
[03:12:27] applications where the applications were
[03:12:30] monolithic and mostly were legacy apps.
[03:12:34] Like in today's scenario, if you want to
[03:12:35] maintain a session of a particular user,
[03:12:37] we don't only stick for that particular
[03:12:39] session. We use many other tools like
[03:12:42] JWT token we use, right? So, this is how
[03:12:45] we are going to maintain an entire
[03:12:47] connection through a server and a
[03:12:48] client. We don't only rely on giving the
[03:12:51] request to the same server again and
[03:12:53] again. Even if the server changes, it is
[03:12:55] going to recognize us through our JWT
[03:12:57] token. And this is going to work
[03:12:59] excellently with our distributed
[03:13:01] systems,
[03:13:02] microservices, and also if we use Redis.
[03:13:06] In all these scenarios, we now don't
[03:13:08] need IP hash functions. We don't need
[03:13:11] our request to be handled through same
[03:13:13] server. Even if the server changes, our
[03:13:16] request or our session should be
[03:13:18] consistent. Also, there is another
[03:13:20] algorithm which is extension of round
[03:13:22] robin, which is called weighted round
[03:13:24] robin. So, in which the round robin, as
[03:13:27] it was discussed, is working same, but
[03:13:30] we added weight. So, that means
[03:13:33] let's say this is S1, this is S2, and
[03:13:36] this is S3. Let's say the RAM capacity
[03:13:39] of S1 is 8 GB, for S2 it is 16, and for
[03:13:43] S3 it is 32 GB. Now, what we are doing,
[03:13:47] we are adding a weight to our request.
[03:13:50] So, more the configuration,
[03:13:52] more is going to be the weight. So, if
[03:13:55] our load balancer basically keeps track
[03:13:58] of this, so it knows that the S3 may
[03:14:01] have weight three, S2 may have weight
[03:14:03] two, and S1 may have weight one. So,
[03:14:06] whenever a new request arrives at load
[03:14:09] balancer, it is going to be addressed by
[03:14:12] the one which have the most weight. So,
[03:14:15] here the weight of S3 is maximum, so it
[03:14:17] is going to be addressed by our S3
[03:14:19] server. And then, based on the weight
[03:14:21] and round robin fashion, our request are
[03:14:24] going to be answered. So, with weighted
[03:14:26] round robin algorithm also added in the
[03:14:28] list, we have now covered all the
[03:14:29] algorithms, major algorithms basically,
[03:14:32] which we needs to know when we talk
[03:14:34] about load balancers. Also, in real
[03:14:37] base, no one algorithm basically works.
[03:14:39] We always work with hybrid approach.
[03:14:42] And load balancer basically balances
[03:14:45] multiple algorithms. It is very possible
[03:14:48] that we are using maybe IP hash with the
[03:14:51] combination of round robin. And also,
[03:14:54] other combinations are also possible.
[03:14:55] Maybe we are combining two, maybe we are
[03:14:58] combining all six at the same time. Like
[03:15:00] here, we were talking about least time
[03:15:03] algorithm and least connection
[03:15:05] algorithm. We can combine these two
[03:15:07] algorithms in order to get a better
[03:15:08] algorithm. So, in order to fulfill our
[03:15:11] requirement, we normally don't rely on a
[03:15:13] single algorithm, we rely on multiple
[03:15:16] hybrid algorithms. So, after discussing
[03:15:19] all the algorithms, we know now how the
[03:15:21] load balancer basically chooses a server
[03:15:23] for the next request. The second thing
[03:15:25] which load balancer does is doing the
[03:15:28] health checks. Let's understand how load
[03:15:30] balancer basically manages the health
[03:15:32] checks. Here the thing is we have two
[03:15:34] approaches how a load balancer can check
[03:15:37] the health checks of entire servers.
[03:15:39] Let's say we have a load balancer here
[03:15:41] again and we have server one
[03:15:45] and server two. The first way how we can
[03:15:47] check any performance is by simply
[03:15:49] seeing how server one and server two are
[03:15:52] performing. We are not adding any new
[03:15:54] request in server one or server two. We
[03:15:56] are just observing how they are
[03:15:58] responding to the actual requests. This
[03:16:01] is the passive way of checking the
[03:16:02] health. By this, we don't add any new
[03:16:05] request to the servers. We don't
[03:16:07] basically increase the load of any
[03:16:09] server, but we simply observe. By we, I
[03:16:13] mean load balancer. The load balancer
[03:16:15] simply observe how the server one is
[03:16:18] responding to request and maintain that
[03:16:21] track. And let's say at a particular
[03:16:23] point, if server one breaks or stops
[03:16:25] responding, at that time the load
[03:16:27] balancer knows about this by again
[03:16:30] tracking the actual request. It doesn't
[03:16:33] add any new request to server one. So,
[03:16:35] this is what the passive way is. Now,
[03:16:38] there is another way which is active
[03:16:40] way. In active way, what a load balancer
[03:16:42] does is it adds additional request to
[03:16:45] our servers. And based on the responses
[03:16:48] on those requests, it checks the actual
[03:16:51] health of the server. So, these are the
[03:16:53] two ways of checking the health of
[03:16:56] servers. One by simply observing the
[03:16:59] request and second by actively adding
[03:17:01] the request to the servers. It is very
[03:17:03] important to check the health of every
[03:17:06] server. Why? Because it gives us the
[03:17:08] pattern to take decisions. Like when to
[03:17:11] scale or when to scale down. Both of
[03:17:14] these cases are very usual by working on
[03:17:16] any application on a day-to-day basis.
[03:17:18] Let's suppose if we are maintaining our
[03:17:20] application only for India region, in
[03:17:23] that case also we know that in day time
[03:17:25] the requests are going to be heavy.
[03:17:28] Maybe in evening time it will be
[03:17:29] heavier. And in night time it is going
[03:17:31] to be little or lesser in count. So, at
[03:17:35] that time we can maybe scale down our
[03:17:37] server in the night time in order to
[03:17:39] save some cost. So, let's see what are
[03:17:41] the other parameters of health checks.
[03:17:44] The first parameter of health check is
[03:17:47] interval. This means how often do we
[03:17:49] check our server? For example, it can be
[03:17:52] maybe 5 seconds. So, if the case is
[03:17:54] active, every 5 seconds I'll monitor all
[03:17:57] the requests I've sent to the server and
[03:18:00] see how the performance is going. And
[03:18:02] also, in the passive case we'll see the
[03:18:05] responses and calculate the matrices
[03:18:07] every 5 seconds. The second params can
[03:18:10] be time out. So, time out basically
[03:18:12] means for how long do we wait to get the
[03:18:15] response? Suppose there is any server
[03:18:18] who normally takes from maybe 50
[03:18:20] milliseconds
[03:18:21] to the maximum of maybe 5 seconds
[03:18:25] in order to process any request from a
[03:18:28] long time. And now suddenly it is taking
[03:18:31] 10 seconds. So, this should be an
[03:18:33] alarming case and we should immediately
[03:18:35] check what went wrong. Okay, with that
[03:18:37] particular web server. What is that
[03:18:39] particular request which is taking 10
[03:18:41] seconds? Is there any issue with the
[03:18:43] code? Is there any issue with the
[03:18:44] request? Does Do we change any
[03:18:47] configuration? Or does our server is
[03:18:49] managing some other task because of
[03:18:51] which our this request is being
[03:18:53] affected? We need to know the answers of
[03:18:56] all of these questions in order to make
[03:18:57] a better decision. We also need to know
[03:18:59] about the threshold. Threshold can be
[03:19:02] like healthy and unhealthy both, right?
[03:19:04] In unhealthy, we basically take care of
[03:19:06] the failed calls. So, we will basically
[03:19:09] maybe set an alarm after 20 failed
[03:19:13] calls. Okay? We can configure them based
[03:19:16] on a particular region, based on a
[03:19:18] particular area of our code, maybe a
[03:19:21] route, particular subdomain of a route,
[03:19:24] or maybe randomly. At a particular time,
[03:19:26] if 20 calls fail, that is an alarming
[03:19:29] situation for us. In normal scenario,
[03:19:32] many application may give a faulty
[03:19:34] response based on various factors. It
[03:19:36] happens on a day-to-day basis, but after
[03:19:38] that n threshold, after that count of
[03:19:41] threshold, we should start investigating
[03:19:44] the cause. And similarly, we have our
[03:19:47] healthy threshold, where we should put
[03:19:49] our marker maybe after every some calls.
[03:19:53] So, maybe after every 100 calls, 100
[03:19:56] positive calls, we need to check is
[03:19:58] everything fine with those calls. The
[03:20:00] response was expected, and the system is
[03:20:02] working the way it should work. So,
[03:20:04] these are the three health parameters of
[03:20:07] our web servers which our load balancer
[03:20:09] needs to check end over time in order to
[03:20:11] make sure that our web servers are
[03:20:13] working fine. And with this, we now
[03:20:15] understand the two major factors of load
[03:20:17] balancer, how it gives request to the
[03:20:20] other server, and plus, how do it check
[03:20:23] the health of every server. Now that we
[03:20:25] have understood load balancer, it is
[03:20:27] very important to know that in terms of
[03:20:29] scaling, we also need to scale our
[03:20:31] databases, right? So, in databases, what
[03:20:34] normally happens is, suppose we have 100
[03:20:36] GB of data, and we have a storage of
[03:20:38] maybe 200 GB. This is still fine, right?
[03:20:41] Maybe we have 1 TB of data, maybe 100 TB
[03:20:44] of data, it doesn't matter. The thing
[03:20:46] which matter is this data will
[03:20:48] eventually get full.
[03:20:50] And there will come a stage where you
[03:20:53] can't expand your databases vertically.
[03:20:56] You have to add more databases into our
[03:20:59] system
[03:21:00] whenever it comes to scaling. Also, now
[03:21:03] that we know about load balancers, we
[03:21:05] know that our server
[03:21:06] can be placed into different regions of
[03:21:09] our world, right? This can be placed
[03:21:10] into US region, this can be placed into
[03:21:13] India region only. And what we were
[03:21:15] doing is we were adding both of these
[03:21:17] data into single database. This is
[03:21:19] effective if the user count is one, the
[03:21:21] request we are getting are minimal. But
[03:21:24] if the user increases, the traffic
[03:21:26] increases, the data increases, it will
[03:21:28] be hard to cater both of these servers
[03:21:30] from the single database.
[03:21:32] This is where we need to segregate this
[03:21:34] data into multiple databases. One may be
[03:21:38] catering Indian server and the other
[03:21:40] might be catering the US server. Now,
[03:21:42] this way we segregated our data into two
[03:21:44] databases so that the requests can be
[03:21:46] faster and also with that the data will
[03:21:49] be segregated in such a manner that it
[03:21:51] will be easy to maintain. Now, this can
[03:21:53] be one of the case where we don't need
[03:21:56] to have same data into two databases. In
[03:21:59] this case, what we are doing, we are
[03:22:00] assuming that the data in this data
[03:22:02] table will be different from the data
[03:22:05] into this database. Normally, this is
[03:22:07] not the case, right? Normally, what can
[03:22:09] happen is suppose we have multiple
[03:22:12] servers for Indian region only. So, this
[03:22:14] is also Indian region, this is also
[03:22:16] Indian region. And we can have multiple
[03:22:18] databases to cater the same server. Why?
[03:22:21] Because if we have a single database and
[03:22:23] if that fails, we don't have anywhere to
[03:22:25] go and recover the data from. That's why
[03:22:27] we manage multiple databases in order to
[03:22:30] recover the data, maybe maintain the
[03:22:32] data, and also it increase the
[03:22:34] efficiency of our system by reducing the
[03:22:36] latency. And also we may have some
[03:22:38] portion of data here and some portion of
[03:22:40] data here.
[03:22:41] Both of these things are possible. These
[03:22:44] things are basically
[03:22:46] replication and partitioning. In
[03:22:49] replication, what we do, we basically
[03:22:51] copy the data from one database to other
[03:22:54] database so that even if anything
[03:22:56] happens to database one, we are able to
[03:22:59] retrieve the data from database two.
[03:23:00] Also, if database one is handling so
[03:23:03] much calls, we can redirect those
[03:23:05] requests to database two as well. And in
[03:23:07] partitioning, what we do is we basically
[03:23:09] divide the data into single database and
[03:23:12] put one part here into other database
[03:23:15] and the other part anywhere else. So
[03:23:17] that if they are getting different
[03:23:19] requests, it will be easier to cater
[03:23:21] each and every request with their
[03:23:22] specific database. We are going to cover
[03:23:24] both of these topics, but for now let's
[03:23:26] talk about replication. So we have
[03:23:28] understood that replication basically
[03:23:30] means keeping the copy of data. And why
[03:23:33] are we doing this? Why are we making
[03:23:35] copies? The first point is we are
[03:23:37] avoiding or improving our single point
[03:23:40] of failure issue. We don't want our
[03:23:41] database to fail and our system to
[03:23:43] collapse. We want some other database at
[03:23:45] that time so that our system will be
[03:23:47] working. The other reason of this is
[03:23:50] availability. By having data into
[03:23:52] multiple databases, our availability as
[03:23:54] a system can increase. We can have
[03:23:56] different data centers and it will
[03:23:58] increase our performance. Also, as we
[03:24:01] discussed, if we talk about different
[03:24:02] localities or different regions of area,
[03:24:05] we are increasing the performance by
[03:24:07] adding particular database into that
[03:24:09] site. So that will keep the data close
[03:24:11] to our server and will be retrieved
[03:24:13] faster. And also with all this, we are
[03:24:15] eventually increasing our read
[03:24:17] throughput. So suppose with a single
[03:24:20] database, we were catering maybe 10,000
[03:24:23] requests per second. Now with two
[03:24:25] databases of same storage and data, we
[03:24:27] can cater two times of the previous one.
[03:24:29] So this is how the three throughput will
[03:24:31] also increase. So after understanding
[03:24:33] what replication is and why do we use
[03:24:36] it, let's talk about how can we achieve
[03:24:38] replication. So we are going to talk
[03:24:40] about three algorithms. The first
[03:24:42] algorithm is single leader replication.
[03:24:46] That means there will be a database
[03:24:49] which will be our leader and from the
[03:24:52] leader only we will replicate the data
[03:24:54] to other follower nodes or follower data
[03:24:56] centers.
[03:24:57] Suppose there is any user who is maybe
[03:25:00] updating their profile picture. And when
[03:25:03] they are updating their profile picture,
[03:25:04] the request from our client basically
[03:25:07] moves to a server and from server we are
[03:25:10] only sending that request to our leader
[03:25:12] only. We don't directly communicate to
[03:25:15] our followers because it is the leader
[03:25:18] who is going to then replicate our data
[03:25:19] to followers. So every request will go
[03:25:22] to our leader. To be specific, every
[03:25:24] write request will go to our leader and
[03:25:26] then the data will be replicated to our
[03:25:28] followers. This is how a single leader
[03:25:31] approach works. Let's understand this
[03:25:33] through an another diagram. This is our
[03:25:35] user. Maybe this is our leader and we
[03:25:39] have our F1 follower database and
[03:25:42] follower two. Assume this as a timeline,
[03:25:45] okay? Now what we are going to do,
[03:25:46] suppose at this point the user is
[03:25:49] requesting to update the profile
[03:25:51] picture. And this request will
[03:25:53] eventually go to our leader node and
[03:25:56] once the request is taken care by
[03:25:58] leader,
[03:25:59] they will send the same request to our
[03:26:01] follower nodes as well.
[03:26:03] Follower node one, maybe it is taking
[03:26:05] longer time because it is far. So at
[03:26:07] this point the request went to follower
[03:26:10] one and follower two. At this point two
[03:26:12] things can happen.
[03:26:14] First thing is if the calls from leader
[03:26:16] node to follower node are async, in that
[03:26:20] case leader will do its work and update
[03:26:22] the user that the task is done. And in
[03:26:25] the back processes, the follower nodes
[03:26:27] can continue updating the profile
[03:26:29] picture and will eventually update our
[03:26:32] leader that the task is done. This type
[03:26:34] of request where leader updates the user
[03:26:37] directly after updating the data without
[03:26:39] getting the acknowledgement from these
[03:26:40] follower nodes is called async
[03:26:43] operation. Async basically means once
[03:26:46] the request is catered by a leader, it
[03:26:48] will directly update our user. And in
[03:26:51] the back end, it will also share the
[03:26:53] same request for follower one and
[03:26:55] follower two node to perform the same
[03:26:57] task and update our leader in the back
[03:26:59] end. In this case, even if our F1 fails
[03:27:02] to update, F2 fails to update, or
[03:27:04] anything went wrong with these other
[03:27:05] nodes, the leader have already given the
[03:27:07] confirmation to our user. So, the task
[03:27:10] is done. And eventually, when the nodes
[03:27:12] are recovered, these operations will be
[03:27:15] performed again on F1 and F2 to keep the
[03:27:18] sync alive. After async, let's also talk
[03:27:20] about sync approach, where the user
[03:27:22] updates the profile picture.
[03:27:24] The request basically carried by our
[03:27:26] leader,
[03:27:27] and it sends the update request to our
[03:27:30] follower nodes as well,
[03:27:31] F1 and F2. And the leader in this case
[03:27:35] will not give any confirmation until it
[03:27:37] get the okay response from both of our
[03:27:41] followers. So, this gives okay,
[03:27:44] and again, this gives okay. Once it get
[03:27:47] confirmation from both of these follower
[03:27:49] nodes, then only our database is going
[03:27:52] to update our server, and eventually,
[03:27:54] our user that the task is done. So, this
[03:27:56] kind of approach is called sync
[03:27:58] approach, where the leader will provide
[03:28:00] the same operations to be performed by
[03:28:02] F1 and F2. It will wait for the
[03:28:05] responses, and once the response is
[03:28:08] taken, then only it will update the
[03:28:10] user. So, this is going to take a lot of
[03:28:12] time, because our databases can be
[03:28:14] placed into multiple places. There can
[03:28:17] be two follower nodes, as we have
[03:28:18] mentioned here, or more. So, in that
[03:28:20] case, our time will increase, and
[03:28:22] eventually, it will update the user
[03:28:25] after getting the confirmation from each
[03:28:27] and every follower. Now, let's talk
[03:28:29] about advantages and disadvantages of
[03:28:31] both of these approaches. If we talk
[03:28:33] about synchronized approach, sync
[03:28:35] approach, the advantage is all of the
[03:28:38] followers will always have the updated
[03:28:39] values. The other advantage of sync can
[03:28:42] be, even if our leader fails, it will be
[03:28:45] easier to select another leader, because
[03:28:47] every node we know have the current
[03:28:50] updated data. So, it will be easy to
[03:28:52] migrate our leader to any of the
[03:28:54] follower nodes, maybe follower one,
[03:28:56] maybe follower two. The disadvantages
[03:28:59] will be it is going to take a longer
[03:29:01] time and also after getting any request,
[03:29:04] our leader is waiting for the responses
[03:29:07] from other follower nodes. It is going
[03:29:09] to block that particular resource and
[03:29:11] other operations on that particular
[03:29:13] resource is also be blocked because of
[03:29:15] our asset principles, right? And because
[03:29:18] of these two disadvantages, we can say
[03:29:21] that the sync operation here while
[03:29:23] replication is an imprac- tical
[03:29:25] approach. Any leader can't wait for all
[03:29:27] the followers to update them first and
[03:29:30] then they will update the user.
[03:29:32] So, we always prefer async approach
[03:29:34] here. In async approach, as we can see
[03:29:36] clearly, no resources are blocked,
[03:29:39] right? And the responses will also be
[03:29:41] faster. And if we talk about
[03:29:43] disadvantages,
[03:29:44] we are basically trading off our
[03:29:47] consistency. That means our data will be
[03:29:50] mismatched. Suppose if a user is
[03:29:53] updating any data to leader node and
[03:29:55] leader provides the response to user,
[03:29:57] our user will assume that the task is
[03:29:59] done. So, even if they read from any
[03:30:02] other follower nodes, the data should be
[03:30:04] reflected. And in the async approach, it
[03:30:07] is very possible that if user is trying
[03:30:09] to access the data and it get connected
[03:30:11] to any follower nodes, it will see the
[03:30:14] stale data, which is eventually going to
[03:30:16] update by our leader, but currently they
[03:30:18] are seeing the stale data. So, this is
[03:30:20] the issue in our async approach. Now,
[03:30:23] before moving to the other algorithms,
[03:30:25] let's first talk about how can we add a
[03:30:27] new follower?
[03:30:28] So, let's say we already have a system
[03:30:31] where we have a leader and we have maybe
[03:30:33] follower one and follower two already in
[03:30:36] our system. Now, we need to add our
[03:30:38] follower three. How can we add it? Now,
[03:30:41] in order to add a new node into our
[03:30:43] system, we need to perform some
[03:30:45] operations. Our follower three will also
[03:30:48] need to have all the data which our
[03:30:50] leader have.
[03:30:52] So, for that, what we do, we create
[03:30:54] snapshot of the data from leader or
[03:30:57] maybe we can create it from follower as
[03:30:59] well. But, we need to make sure that if
[03:31:02] we are picking follower two in order to
[03:31:04] do the replication, we will again need
[03:31:06] to use F2 only to update the data. Let's
[03:31:09] say the current time is 12:55 p.m. and
[03:31:13] we are taking the snapshot of F1 or F2
[03:31:16] at this point. So, that means whatever
[03:31:19] the state of our F2 is at this 12:55
[03:31:23] p.m., we are only capturing the current
[03:31:25] state of that particular database and we
[03:31:29] are that dumping it into new node, which
[03:31:31] is F3. Now, this process is going to
[03:31:35] take time for sure. So, this is our
[03:31:37] snapshot one, which is at 2:55. So, this
[03:31:41] will contain the entire state of our F2
[03:31:45] node. Now, what will happen again is
[03:31:47] suppose the replication process took 2
[03:31:50] hours or 3 hours, maybe, because the
[03:31:53] data is huge and everything.
[03:31:55] Now, we need to know what changes did
[03:31:57] the F2 went through in this 2 and 3
[03:32:00] hours. So, in that case, what we will
[03:32:02] do, we will again take the snapshot, but
[03:32:04] this time we don't have to capture the
[03:32:06] entire state. We only need to capture
[03:32:08] the difference between the snapshot and
[03:32:11] the current time. So, we will create
[03:32:13] another snapshot, which will include the
[03:32:15] changes from 12:55 to current time. And
[03:32:19] finally, we are going to dump this data
[03:32:21] also in F3. Once we get to know that the
[03:32:24] F3 is completely in sync with F2 and F2
[03:32:27] is already in sync with leader, we will
[03:32:30] make the connections of leader to our F3
[03:32:33] also. And with this, we will have a new
[03:32:35] follower node into our system with all
[03:32:38] the updated data. After this, what
[03:32:40] happens if the leader only fails? Let's
[03:32:42] say we are having this topology again,
[03:32:45] leader, F1, and F2.
[03:32:48] Again, we have some databases linking.
[03:32:51] The replication process is working fine,
[03:32:53] then suddenly our leader fails.
[03:32:56] In this case, we need to elect a new
[03:32:58] leader. Now, how will we elect?
[03:33:00] Basically, we will take care of two
[03:33:02] factors. The first factor is which of
[03:33:06] these F1 and F2 have the latest
[03:33:08] information. So, we can take care of
[03:33:10] that by seeing the timestamp of the
[03:33:12] latest update. So, whichever we will
[03:33:14] see, we will pick from F1 and F2, and we
[03:33:18] will see which one is
[03:33:20] updated recently. And the second step is
[03:33:23] we need to update F1 to become a leader,
[03:33:26] and our F2 to see F1 as a leader now.
[03:33:30] So, this is the process of electing a
[03:33:32] new leader when the leader goes down.
[03:33:34] With this, you may have also heard these
[03:33:36] terms like FS image or maybe added logs.
[03:33:40] These things are highly used in the
[03:33:42] replication process. FS image basically
[03:33:44] con- tains the full metadata snapshot,
[03:33:47] and added logs is used to update the
[03:33:49] current changes. So, these both are also
[03:33:52] used while doing the replication. And
[03:33:55] while choosing the new leader or adding
[03:33:57] a new follower, these two things are
[03:33:59] also helpful. Now that we understand how
[03:34:02] to add new leader, how to add new
[03:34:03] follower, how to take care of things,
[03:34:06] let's move to our second algorithm,
[03:34:08] which is multi-leader algorithm. So, as
[03:34:10] the name suggests, it is having multiple
[03:34:12] leaders instead of one. So, that means
[03:34:14] there is a possibility that every data
[03:34:16] center, be it DS1 and DS2, will have
[03:34:20] their bunch of leaders and followers.
[03:34:23] So, maybe for DS1, we have this leader,
[03:34:26] and we have follower like F1 here. Also,
[03:34:29] here we have another leader and
[03:34:32] follower. So, for DS2, the leader is
[03:34:35] L2, and for DS1, the leader is L. Now,
[03:34:38] what is going to happen? Let's say the
[03:34:40] user is maintaining their records
[03:34:43] through DS1. So, every record which DS1
[03:34:46] handles will eventually first go to
[03:34:48] their leader, and then the leader will
[03:34:50] update their nodes. With this, now
[03:34:53] leader also needs to update the other
[03:34:55] leader into other data centers. And then
[03:34:58] this leader is going to update these
[03:35:00] nodes. This is how the process flows.
[03:35:02] And similarly, if any request is being
[03:35:04] made to this data center two, our leader
[03:35:07] two is going to update their followers,
[03:35:10] and also will send some query to other
[03:35:12] leader to update the leader as well as
[03:35:15] their followers. So, this is how a
[03:35:17] multi-leader replication works, where
[03:35:19] the leader will not communicate to each
[03:35:22] and every nodes, but it will communicate
[03:35:24] to leader nodes, and maybe their
[03:35:26] follower nodes. So, this is going to
[03:35:29] increase our performance. Also, we have
[03:35:32] multiple leaders, that means even if a
[03:35:34] leader node breaks, we can use the other
[03:35:37] leaders to update the other nodes. So,
[03:35:39] we have more tolerance to threats. Now,
[03:35:42] since we have two leaders, we can also
[03:35:43] perform collaborative operations, like
[03:35:46] they can be working on the same file.
[03:35:49] Now, we can work on the same Google
[03:35:51] file, same Google sheet, those kind of
[03:35:53] operation also we can perform, because
[03:35:55] one request will not block that
[03:35:57] resource, and the two requests can
[03:35:59] eventually work simultaneously. Now,
[03:36:00] when we are saying that both of these
[03:36:03] resources are going to perform actions
[03:36:04] on a similar table or single data, that
[03:36:07] is going to increase our chances of
[03:36:09] conflicts. Let me explain it through
[03:36:11] another diagram. Let's say this is user
[03:36:13] one, this is leader one. Here we have
[03:36:16] leader two, and then we have another
[03:36:18] user. Let me create the timelines again.
[03:36:20] Let's say, user one and user two both
[03:36:22] working on the same file, which is named
[03:36:25] as A. Now, user one wants to rename that
[03:36:28] file to B, and user two want to rename
[03:36:32] that file to maybe C. Now, these both
[03:36:35] will eventually hit their request to
[03:36:38] their particular leaders. And based on
[03:36:40] the async approaches we have seen, our
[03:36:42] leaders can eventually give the okay
[03:36:45] response to our users, right? That okay,
[03:36:47] it is renamed. And here also, it can
[03:36:50] give the response that okay, it is
[03:36:52] renamed. So, these two users will see
[03:36:55] two different data. This is not
[03:36:56] possible, right? And also, our leader is
[03:36:59] going to communicate with each other.
[03:37:00] So, this will send the request to update
[03:37:03] the data with C. And also, this leader
[03:37:06] will also send the same request to
[03:37:08] update it to B. Now, this is the
[03:37:11] conflict, and how do we resolve it?
[03:37:12] Basically, there are three ways of
[03:37:14] resolving it. The first way of resolving
[03:37:17] is the last right win. So, that is this
[03:37:20] right is performed, let's say, at this
[03:37:23] point, and this right is performed at
[03:37:25] this point. So, as this operation is
[03:37:28] performed later, so that means our L2
[03:37:31] needs to update our file to C. So,
[03:37:35] eventually, the file name will be C.
[03:37:37] This is our first approach. The second
[03:37:39] approach here is while working with
[03:37:41] different leaders, we assign some IDs to
[03:37:43] each and every leader. Suppose, leader
[03:37:46] one have ID 10, and leader two have ID
[03:37:49] 11. Now, based on the ID, we can decide
[03:37:52] which leader is more powerful, and which
[03:37:55] leader we have to follow. Ultimately, if
[03:37:58] leader two is of higher ID, that means
[03:38:00] we have to follow leader two. And now,
[03:38:02] it doesn't matter if the last right was
[03:38:04] performed by L1 or L2. It is going to
[03:38:07] update it with the value of L2 only. So,
[03:38:10] here, instead of the last right, we are
[03:38:12] going to focus on the ID. So, we can say
[03:38:15] replica with higher ID wins. Replica is
[03:38:19] nothing but a replication. Like, every
[03:38:22] node which have the replica of content
[03:38:24] can be called replica. So, we can write
[03:38:26] leader also here. Okay, no issues. The
[03:38:29] third approach basically is the approach
[03:38:31] which we also see sometimes on Git when
[03:38:33] we try to solve merge requests. So, the
[03:38:35] same approach is used by the replication
[03:38:37] process as well. So, whenever there are
[03:38:39] conflicting situations, our leaders or
[03:38:42] any other nodes are not going to solve
[03:38:44] it. In this case, we will prompt our
[03:38:46] user directly that the file name has
[03:38:49] been changed to C and the last change
[03:38:52] which you have made was B. So, do you
[03:38:54] want to keep the current changes or do
[03:38:56] you want to update it to C? It is up to
[03:38:59] user. So, in this case, we need to add
[03:39:01] the application logic to basically pass
[03:39:04] our conflict to the users and eventually
[03:39:06] user will update it.
[03:39:09] After this, the third algorithm is
[03:39:11] leaderless replication. So, in this
[03:39:14] replication, we don't assign a specific
[03:39:16] leader to any data center or to any
[03:39:19] other node. We don't have any kind of
[03:39:21] leader in this leaderless replication.
[03:39:24] As the name suggests correctly, so here,
[03:39:26] what do we do? Here, let's say we have
[03:39:29] any client there. So, he is our user and
[03:39:32] now we have some databases. Let's say
[03:39:34] this is our node one, this is our node
[03:39:36] two, this is our node three. So, these
[03:39:39] are the three databases onto which our
[03:39:42] data needs to be replicated. So, this
[03:39:44] time whenever our user request for any
[03:39:47] update, let's say again this user is
[03:39:49] updating the profile picture, but this
[03:39:52] time the request basically goes to all
[03:39:54] of the nodes and eventually all will
[03:39:57] update the data and provides a response
[03:40:01] to the user. Here, the thing is in other
[03:40:03] applications where we had a leader, we
[03:40:06] can basically rely on that leader
[03:40:08] replica and based on the response which
[03:40:10] we get from leader, we can eventually
[03:40:11] decide that whether the operation is
[03:40:13] performed correctly or not. But here, we
[03:40:15] don't have any leader. So, what can we
[03:40:17] do? Do we wait for all the replicas to
[03:40:20] answer us and at this point we update
[03:40:22] our user or there is some other method?
[03:40:25] Let's talk about that in a bit, but
[03:40:26] before that, let's jot down some points.
[03:40:29] So, the first point here is we don't
[03:40:31] have any leader here. So, here we are
[03:40:34] bound to send our queries to more than
[03:40:37] one replicas, right? More than one
[03:40:40] nodes. So, every query, when I say every
[03:40:43] query, I mean both read as well as write
[03:40:46] queries, will go to multiple nodes and
[03:40:49] then collaboratively we'll get the
[03:40:51] response. When I say read also, that
[03:40:54] means let's say in this database only,
[03:40:57] if there is some other user who is also
[03:40:58] trying to access some values, and while
[03:41:01] accessing some values, the user can use
[03:41:04] this replica at this point or this
[03:41:06] replica at this point or this replica at
[03:41:08] this point. In all of these three
[03:41:11] scenarios, the user is going to get
[03:41:13] different values. So, here the user will
[03:41:16] get updated profile, and from here they
[03:41:18] will get the stale data. So, based on
[03:41:20] multiple entries, we have to decide
[03:41:22] whether to give this user updated data
[03:41:24] or the stale data. So, this is our
[03:41:26] struggle with this kind of replication.
[03:41:28] But, apart from the struggles which we
[03:41:29] see here, most of the applications in
[03:41:32] databases use this setup. It is used by
[03:41:34] various applications like Amazon Dynamo,
[03:41:37] Riak, Cassandra, VM. All of these use
[03:41:40] leaderless application. So, now the only
[03:41:42] issue is should we wait for each and
[03:41:44] every node to give us confirmation so
[03:41:46] that we can proceed to tell any user any
[03:41:49] response or is there any other way? So,
[03:41:52] as you may have guessed, definitely we
[03:41:53] can't wait for this long. There is a
[03:41:56] way. That way is basically termed as
[03:41:58] quorum. So, in quorum, what do we do?
[03:42:00] Suppose we have total number of nodes as
[03:42:02] three. We denote them by N, and for
[03:42:06] reading, we have to use more than half
[03:42:09] of the total nodes. So, it should be
[03:42:11] more than N by 2. Again, for writing, we
[03:42:14] should get the confirmation from more
[03:42:16] than the half nodes. This way we
[03:42:18] maintain the quorum and we will get the
[03:42:21] responses which we want for. So, in the
[03:42:23] same example, if I redraw it, suppose
[03:42:26] the user is again going to update any
[03:42:28] information, so updating profile picture
[03:42:31] again maybe, and the request went like
[03:42:33] this for first node, for second node
[03:42:35] maybe the network is faster here, and
[03:42:38] for the third node. Now, this is the
[03:42:40] time each node took in order to perform
[03:42:43] the operation. So, here we don't have to
[03:42:45] wait for this response because we
[03:42:48] already got the responses from more than
[03:42:50] the half of the nodes. So, we can easily
[03:42:53] say that profile picture is updated. So,
[03:42:55] here we can confirm that the operation
[03:42:57] of updating profile picture is done.
[03:43:00] Again, if a new user appears here, and
[03:43:03] the user is trying to access the value,
[03:43:05] so it can basically sends a read
[03:43:07] operation from these all nodes. Maybe at
[03:43:10] this point, maybe at this point. Suppose
[03:43:13] this point gives a result here, then
[03:43:15] this point also gives a result here. So,
[03:43:17] in these two responses, the user is
[03:43:19] getting different values because this is
[03:43:21] giving them stale data, and this is
[03:43:23] giving them updated data because the
[03:43:25] update is already done here, right? So,
[03:43:27] in this case, there are various other
[03:43:29] mechanisms also. You can go for
[03:43:30] timestamp, or they can go for any other
[03:43:33] mechanisms. But, let's say they don't go
[03:43:35] for any other mechanism. There is one
[03:43:37] more mechanism here where that is if the
[03:43:39] requests are equal, and we are still
[03:43:41] getting the different data, we will
[03:43:43] consider the third request and response,
[03:43:46] and then again calculate the results.
[03:43:48] So, here we are getting updated from two
[03:43:51] of the nodes, and we are getting stale
[03:43:53] value from one of them. So, we will move
[03:43:56] ahead with the updated value, and this
[03:43:58] user will get the updated profile
[03:44:01] picture. So, there can be various ways
[03:44:03] of solving this conflicts, but the thing
[03:44:05] is ultimately the user don't have to
[03:44:08] wait for each and every response. This
[03:44:10] is a special case where half of the
[03:44:12] nodes are saying that things are done,
[03:44:14] and half are saying things are not done.
[03:44:15] We don't have three servers also. We
[03:44:17] have more than 10 or 12 servers in a
[03:44:20] large system. So, this case becomes a
[03:44:22] rare case. So, yeah, this is all about
[03:44:24] the replication which we needs to know
[03:44:26] at this point. So, after replication,
[03:44:28] the other way of segregating our data
[03:44:29] into multiple nodes in order to scale
[03:44:32] them properly is partition. Now, before
[03:44:35] moving to partition, first see what can
[03:44:37] be the issue with replication.
[03:44:39] Replication basically suggests that we
[03:44:41] will copy entire data to other node.
[03:44:43] What if the data is so huge that we
[03:44:45] can't have them in one node? With this,
[03:44:47] the second concern is what if the data
[03:44:50] is so huge that even with secondary
[03:44:52] indexes, our time of searching any
[03:44:55] element is getting worse and worse. So,
[03:44:58] with these two concerns, we can't really
[03:45:00] have all of the data in one database and
[03:45:03] same data in other database. What can we
[03:45:06] do then? We can easily or through some
[03:45:09] logic break the system. We will do the
[03:45:12] partitioning of data and maybe place
[03:45:14] some amount of data here and other
[03:45:16] amount of data in some other node. And
[03:45:19] then, we can replicate this partition
[03:45:21] data. Why? Because this data is
[03:45:23] comparatively smaller and it will be
[03:45:26] easier to manage. Let's say, in a
[03:45:28] particular node, we are only saying that
[03:45:31] we will store up to 10,000 records. And
[03:45:35] then, once we hit this point, we will
[03:45:37] again create a new partition and will
[03:45:40] add the new records there. Or maybe
[03:45:42] divide these records into 5,000. So,
[03:45:45] these all things can be done only when
[03:45:47] we have a new way of partitioning the
[03:45:50] data. So, this is what partition really
[03:45:52] is. While partitioning the data, there
[03:45:54] is only a single rule. That is, if we
[03:45:58] are doing the partitions
[03:46:00] like this, then if we combine them, it
[03:46:03] should give us the entire data set. This
[03:46:06] is the only condition which is required
[03:46:08] for partition. And And makes sense, too.
[03:46:11] We don't want to lose any data, right?
[03:46:13] So, this is our first condition and the
[03:46:15] second condition is that let's say we
[03:46:18] have again two partitions. Now, we want
[03:46:20] our data to be equally distributed among
[03:46:23] them. We don't want any nodes to get
[03:46:25] let's say consumed by 90% of data and
[03:46:28] here we only have 10% of data because
[03:46:31] this basically beats the reasoning of
[03:46:33] partitioning. We are doing partitioning
[03:46:34] so that every node will be able to
[03:46:37] access some data and will be able to
[03:46:39] work frequently. So, basically we are
[03:46:41] saying that the data should be evenly
[03:46:44] distributed. So, these are the two major
[03:46:47] conditions of partitioning. Apart from
[03:46:50] this, everything works fine. So, the
[03:46:51] first condition makes sense. It will
[03:46:53] take care of itself and in order to
[03:46:55] fulfill second condition, we have to
[03:46:56] basically maintain some system where we
[03:46:59] will protect the database to get
[03:47:01] overloaded or to get underutilized like
[03:47:04] this. So, now let's talk about those
[03:47:06] solutions. So, the first thing here is
[03:47:09] we will partition using key. Let's say
[03:47:12] we have some table, maybe user table. We
[03:47:14] are handling these entities and then we
[03:47:17] have some ID here, user one or user two
[03:47:21] and the series goes like this. So, what
[03:47:23] we will do? We will basically in the
[03:47:25] partitioning based on the keys will
[03:47:28] insert the values. Let's say this user
[03:47:30] entity can hold up to 10,000
[03:47:34] or maybe 100,000 values. So, what we
[03:47:36] will do? We will divide these 100,000 to
[03:47:39] 50,000 here and 50,000 here. So, that
[03:47:41] means from user one to user 50,000,
[03:47:44] these data will go to the node one or we
[03:47:47] can say partition one and the users from
[03:47:51] user ID maybe 50,000 one to user ID
[03:47:55] 100,000 will go into partition two.
[03:47:59] So, this is how we will segregate our
[03:48:01] data so that it will be easier to
[03:48:03] retrieve the data afterwards as well.
[03:48:05] This may looks fair on the surface
[03:48:07] value, but it is quite messy. What if
[03:48:10] these users are from different regions?
[03:48:13] What if half of them from 1 to 50,000
[03:48:17] are from India and half of them are from
[03:48:19] US? Maybe here also they are distributed
[03:48:22] like this only. So, half of them are
[03:48:24] from India and half of them are from US.
[03:48:27] So, in that case, both of these nodes
[03:48:29] will be busy. This is a good scenario
[03:48:31] because both of the nodes will be used
[03:48:33] and will be busy in order to provide the
[03:48:35] information. And also it is possible
[03:48:37] that the node one is only taking care of
[03:48:40] India request
[03:48:42] and the US request are being taken care
[03:48:44] by partition two or node two. So, in
[03:48:47] this case what happens? Let's say the
[03:48:49] application is very popular in US, but
[03:48:52] is not that popular in India. So, maybe
[03:48:55] P1 is getting maybe 100 requests per
[03:48:58] second and on the other hand our
[03:49:00] partition two is getting maybe 10,000
[03:49:03] requests per second. Now, earlier this
[03:49:06] was looking good on the surface level,
[03:49:08] but now this is messy because one
[03:49:10] partition here is clearly becoming the
[03:49:13] hotspot. Now, what is hotspot? A hotspot
[03:49:16] is that partition which is getting more
[03:49:18] requests compared to other ones. So, it
[03:49:22] is our duty to maintain this hotspot as
[03:49:24] well. We don't want any node to become
[03:49:27] hotspot because eventually a hotspot can
[03:49:30] leads to the node failure. And if that
[03:49:33] node fails, we have to basically
[03:49:35] distribute the data into multiple nodes
[03:49:37] then and then do the configuration again
[03:49:39] or maybe change this node or maybe
[03:49:42] transfer this data to other node. All
[03:49:44] the things we have to manage, but that
[03:49:46] thing is surely not recommended. So, we
[03:49:48] avoid any node from becoming a hotspot.
[03:49:52] I hope this is making sense to you. So,
[03:49:54] one way of handling the hotspot is let's
[03:49:58] say for every request, we also attach
[03:50:01] timestamp and if most of these requests
[03:50:04] are going to node one and very less are
[03:50:07] going to node two, that means the data
[03:50:10] distribution which we did is not good.
[03:50:13] So, we have to rearrange our data with
[03:50:16] some other methods. So, let's see what
[03:50:18] the other points are. The second
[03:50:20] approach here can be partitioning the
[03:50:23] data with hash value of key. What we
[03:50:27] will do here is, let's say we have user
[03:50:29] one, user two, maybe user three as the
[03:50:33] ID or unique identifier of the data. And
[03:50:36] now we have to put that data into
[03:50:38] different partitions. We will not here
[03:50:40] choose ID, but we will use any hash
[03:50:43] function to basically transfer the ID to
[03:50:46] a unique number. Maybe this is one, this
[03:50:48] is two. And user three belongs to maybe
[03:50:51] one again because of the hash function
[03:50:53] which we are using. So, based on this,
[03:50:55] one and one will go to partition one and
[03:50:59] two will go here. Or maybe we are
[03:51:01] catering some range here, so maybe one
[03:51:03] to 10 can go into one direction and 10
[03:51:06] to 15 can go into other direction. So,
[03:51:08] this is also one way of doing the
[03:51:10] partition. The challenge here is still
[03:51:12] same. If the request bombarded at P1, we
[03:51:16] don't have any other way, but we have to
[03:51:18] rearrange like we discussed in the
[03:51:20] previous example. So, based on our
[03:51:22] discussion so far, the hotspot is
[03:51:24] becoming a real issue. Before solving it
[03:51:27] for partitions, let's first see how do
[03:51:29] we solve this issue in a local DB. Let's
[03:51:32] say we have a table for products. And in
[03:51:35] products, we have various attributes.
[03:51:37] Let's say we have some name and color or
[03:51:40] maybe price. We can have more filter
[03:51:43] values, right? And like this, we can
[03:51:45] have as many attributes as we want. So,
[03:51:47] name, color, price, material. All these
[03:51:49] attributes basically are used in order
[03:51:52] to filter these products. Name can be
[03:51:54] used in query parameters. Other than
[03:51:57] that, color, price, and range can be
[03:52:00] used in filter easily. So, what we will
[03:52:03] do in normal scenario? We will create
[03:52:05] indexes based on material, based on
[03:52:08] color, maybe based on price as well. I'm
[03:52:11] not sure about it because price normally
[03:52:13] goes into a range, but we can easily
[03:52:16] make a secondary index out of this and
[03:52:19] by that, whenever any user basically
[03:52:22] tries to search that particular product
[03:52:24] with material, maybe material is wood.
[03:52:26] So, what will happen? We will not go to
[03:52:28] our table or this huge table directly.
[03:52:31] Where we will redirect this query to, it
[03:52:33] is going to redirect it to our second
[03:52:35] query, which is maintained for material.
[03:52:38] And if that data or that value is here,
[03:52:42] we will then redirect those records
[03:52:44] particularly to our display. So, this is
[03:52:47] how we manage the queries to find out if
[03:52:49] we have the data or not, and if we have
[03:52:51] the data, where is that data
[03:52:53] particularly. This is how we solve it in
[03:52:55] local DB or a single instance. Now, we
[03:52:58] are going to use the same way into
[03:53:00] partitioning as well. So, what we are
[03:53:02] going to do? We are going to do the
[03:53:04] partitioning by the secondary index.
[03:53:07] What do we mean by this is, we are going
[03:53:09] to maintain secondary indexes in each
[03:53:13] partition. So, that means all the
[03:53:15] secondary indexes will be present in
[03:53:18] each partition respectively. This way is
[03:53:21] also used by Cassandra and also by
[03:53:24] Elastic Search. What we are going to do
[03:53:26] here is, let's say this is our partition
[03:53:28] one, which have some data. Maybe this
[03:53:30] partition have car data from ID, let's
[03:53:34] say 200 to 400. And we have partition
[03:53:37] two, where also we have some car data
[03:53:40] from ID, let's say 500 to 700. Here, we
[03:53:45] are maintaining some secondary indexes.
[03:53:47] Maybe we are maintaining color as a
[03:53:49] secondary index. And for color, we know
[03:53:51] that the blue color is for car maybe
[03:53:54] with ID 209 and 305. Similarly, for red,
[03:53:59] we can say the ID is 350
[03:54:03] or 359, anything, right?
[03:54:07] For P2 also, we are maintaining it like
[03:54:08] this only. Again, for color, we know
[03:54:11] that the blue color cars are maybe ID
[03:54:14] 509
[03:54:15] and 609 and red cars are 610 690. So,
[03:54:21] these are the indexing which is done in
[03:54:23] both of these partitions. So, whenever a
[03:54:25] query comes for a blue car, we don't
[03:54:28] have to scan to all the records, but we
[03:54:31] can directly see the blue car here
[03:54:33] belongs to 209 and 305. And here, we
[03:54:37] have blue car for 509 and 609 only.
[03:54:40] Let's say a new request come for silver
[03:54:43] car. So, we don't have to basically
[03:54:46] indulge into all the records, but by
[03:54:48] seeing secondary indexes on color only,
[03:54:51] we will get that this partition doesn't
[03:54:53] have any car which is of silver color.
[03:54:55] So, we don't scan this partition
[03:54:57] entirely and this request can now go to
[03:55:00] some other partition. So, this is how we
[03:55:02] are maintaining the request so that our
[03:55:05] data doesn't get overloaded with a lot
[03:55:07] of request, but based on the request, if
[03:55:10] they are present in our secondary
[03:55:11] indexes, then only we will entertain
[03:55:13] them and show them the records or fetch
[03:55:15] some records, otherwise, we will
[03:55:17] directly skip them. Now, this kind of
[03:55:19] setup also have its challenges, right?
[03:55:21] Because partitioning is done, but
[03:55:24] secondary indexes are also present in
[03:55:27] each partition. That means even if the
[03:55:30] partition doesn't have any value, we
[03:55:33] still have to send a request to that
[03:55:35] particular partition. This is again a
[03:55:37] drawback of the system which can make
[03:55:39] the system heavy, which can send the
[03:55:41] request to many partitions where the
[03:55:44] data is not there and we are still
[03:55:45] getting the request. So, this is also
[03:55:48] wrong. So, that's why we have a fourth
[03:55:50] and final way of solving this, which is
[03:55:53] by having common global index. What we
[03:55:57] will do here is instead of having
[03:55:59] secondary indexes in each and every
[03:56:01] partition, we will choose a partition or
[03:56:04] any data center where we will maintain
[03:56:07] the secondary indexes. So, if we are
[03:56:10] saying that we want the car with color
[03:56:13] blue, we should know that blue car
[03:56:15] colors, according to the previous
[03:56:17] examples, are only 209305
[03:56:20] and here we have 509 and 609. And
[03:56:23] basically, this belongs to our P1 and
[03:56:26] this belongs to our P2.
[03:56:28] So, we should know this first-handedly.
[03:56:31] So, that whenever anyone is requesting
[03:56:33] to get any information about blue color
[03:56:35] car, we will directly redirect it to P1
[03:56:39] and P2. And suppose we have some other
[03:56:41] partitions, P3, P4, and others, we don't
[03:56:46] send the request there. So, that these
[03:56:48] partitions can take care of other
[03:56:50] requests. So, this is our fourth way of
[03:56:53] maintaining the global index. So, with
[03:56:56] this, definitely, we are going to
[03:56:57] improve our reading, but the writing
[03:57:00] becomes a challenge. Why? Because even
[03:57:03] if we are working with partition 79,
[03:57:06] where we are adding some values, and
[03:57:08] again have to update that, "Okay, we
[03:57:10] have some new car, maybe 1011, which is
[03:57:13] of blue color." So, like this, it is
[03:57:15] handled. So, these are the ways of
[03:57:18] handling partitioning into our system.
[03:57:20] After understanding about partitioning,
[03:57:22] replication, and load balancing, we now
[03:57:25] know that we need to segregate our data
[03:57:27] into multiple nodes in order to scale
[03:57:30] them. We can't scale them into a single
[03:57:33] database after an extent. So, after
[03:57:35] understanding this, let's see what CAP
[03:57:38] theorem basically says.
[03:57:40] CAP theorem is one of those theorems
[03:57:42] which we have to know whenever you think
[03:57:45] about trade-offs between capacity and
[03:57:47] availability. So, first see what CAP
[03:57:49] theorem really stands for. In CAP
[03:57:52] theorem, there are three terms
[03:57:54] basically. C stands for consistency,
[03:57:57] whereas A stands for availability, and P
[03:57:59] stands for partition tolerance.
[03:58:02] So, CAP theorem basically states that
[03:58:04] you can only provide two of these three
[03:58:07] variables, which means if we talk about
[03:58:10] consistency, what does it mean?
[03:58:12] Consistency basically means providing
[03:58:14] latest information to every user.
[03:58:17] So, consistency stands for latest
[03:58:19] information. Now, if we are providing
[03:58:21] latest information, let's see what it
[03:58:23] really means. Let's say this is our
[03:58:25] partition one,
[03:58:26] this is our partition two. Some data is
[03:58:29] updated on partition one,
[03:58:32] and someone is reading that data
[03:58:34] immediately after the update. So, this
[03:58:37] update from partition one and partition
[03:58:40] two will also take some time. And at
[03:58:42] that time, we basically show something
[03:58:45] like system is loading or data is
[03:58:47] loading kind of thing to user until the
[03:58:50] change is completed on P2. Then only we
[03:58:53] can show the latest data. So, this means
[03:58:55] that we will trade off our availability
[03:58:58] of that particular information for
[03:59:00] consistency. The second thing is
[03:59:02] availability. Availability basically
[03:59:04] states that we will always respond to
[03:59:08] every request. Now, what does this mean?
[03:59:10] In the same scenario, if it is taking
[03:59:13] time to upload a data from B1 to B2, and
[03:59:16] while updating someone request in
[03:59:18] between, so they will not see loading
[03:59:20] icon. Instead, they will see the stale
[03:59:23] data. So, this is what availability
[03:59:25] means. Now, the third term, which is
[03:59:27] partitioning. Partitioning, we all know
[03:59:29] now we need to divide our data into
[03:59:32] multiple nodes, right? Now, with
[03:59:34] partition, we can also see tolerance
[03:59:36] here. What does it mean? Let's say there
[03:59:38] are some nodes attached or linked to
[03:59:41] each other. Now, this is partition
[03:59:44] tolerant when the network of this node
[03:59:47] is completely broken. So, this can't be
[03:59:50] updated from any other method. We can
[03:59:52] either wait to basically fix this
[03:59:54] partition connection and update the
[03:59:56] value or we can keep it working to
[03:59:58] provide the information. But, then the
[04:00:01] information we are going to provide is
[04:00:03] going to be stale data. Why? Because the
[04:00:05] connections between this node and the
[04:00:07] other nodes are broken. Now, let's talk
[04:00:09] about the combinations one by one. So,
[04:00:11] first combination is CA,
[04:00:14] which means we are saying that our data
[04:00:16] will be consistent and it will be
[04:00:18] available also. In this case, we can't
[04:00:21] provide the partitioning part. Because
[04:00:23] if we are saying that our data is
[04:00:24] consistent and available, that means we
[04:00:27] are maintaining a single database. We
[04:00:29] can't basically have two data centers or
[04:00:32] two nodes and think about consistency
[04:00:35] and availability at the same time.
[04:00:36] Suppose we have updated any data here,
[04:00:38] it is going to take at least some
[04:00:40] fraction of time to update the data to
[04:00:42] other node. So, in that meantime, if
[04:00:45] someone request about that particular
[04:00:47] data, we can't decide basically whether
[04:00:49] to show that data or node. Because if we
[04:00:52] show that data, that means we are
[04:00:53] compromising our consistency there. And
[04:00:56] if we don't show that data and wait for
[04:00:58] the update, that means we are
[04:00:59] compromising with the availability. So,
[04:01:01] this combination is only possible when
[04:01:05] we are working with a single database or
[04:01:06] a single node. We can't do partitioning
[04:01:09] here. With this, let's move to our
[04:01:10] second combination,
[04:01:12] which is CP. CP means we are choosing
[04:01:15] consistency over availability. So, here
[04:01:18] we are saying consistency and
[04:01:20] partitioning will be there, but we'll be
[04:01:22] trade-off availability. Now, we have
[04:01:24] understood this term, let me take the
[04:01:26] example again. These are our two nodes
[04:01:28] and the partition happens. Basically,
[04:01:31] the connection between these nodes
[04:01:32] break. Now, this doesn't have the
[04:01:35] updated value. Now, when we are choosing
[04:01:37] consistency, we have to let go of the
[04:01:39] availability. So, we are saying no
[04:01:42] request will be processed by this node.
[04:01:44] Until when? Until it gets updated with
[04:01:47] the latest data. So, this is what
[04:01:48] happens when we are working in a
[04:01:50] partitioned environment and choose
[04:01:51] consistency over availability. That
[04:01:53] means the requests which are calling
[04:01:55] this node will be redirected to some
[04:01:58] other nodes which have the latest or
[04:02:00] consistent data. With this, let's see
[04:02:02] the third combination as well, which is
[04:02:05] AP. In AP, we are providing availability
[04:02:08] to every request, right? So, we are
[04:02:10] providing availability with
[04:02:12] partitioning. So, what is going to
[04:02:14] happen here? When there are two nodes
[04:02:17] and the partition tolerance happen, that
[04:02:19] means this node doesn't have updated no
[04:02:22] updates. At that time also, because we
[04:02:25] have chosen availability over
[04:02:26] consistency, we will keep addressing the
[04:02:28] request by showing them the stale data.
[04:02:31] And that means we are compromising with
[04:02:33] consistency. So, why are we learning
[04:02:35] this CAP theorem? The CAP theorem
[04:02:37] basically states that you have to do
[04:02:39] some trade-offs in order to keep your
[04:02:41] application working. Suppose we are
[04:02:44] working on Instagram. In Instagram, the
[04:02:46] availability matters over consistency.
[04:02:48] Suppose you have updated a video or a
[04:02:50] photo, it doesn't matter for your
[04:02:53] followers to see that photo immediately.
[04:02:56] They can wait for 1 or 2 seconds
[04:02:57] basically. So, in Instagram, we will be
[04:03:00] following AP. But in any application,
[04:03:03] let's say banking application, where
[04:03:05] each transaction matters to us, where
[04:03:07] each change matters to us. So, if I have
[04:03:10] sent 100 rupees to any other account,
[04:03:13] the person will have to wait in order to
[04:03:16] process that transaction, and after that
[04:03:18] only they will be able to see. So, here
[04:03:21] CP matters. And for CA, CA will be there
[04:03:25] if we have a single data. That means for
[04:03:27] every small application, CA can work.
[04:03:30] But when the system scales, we don't
[04:03:32] have an option to pick CA. That's when
[04:03:34] we have to choose between consistency
[04:03:36] and availability. So, this is what CAP
[04:03:38] theorem is. I hope you all understand
[04:03:40] it. Now, let's understand one of the
[04:03:42] most important component of our system
[04:03:44] design, which is message queue. Now,
[04:03:46] before going into depth of message
[04:03:48] queue, let's first understand the type
[04:03:50] of request we deal with. We normally
[04:03:52] deal with two type of request. Or we can
[04:03:55] also say requests or maybe processes.
[04:03:58] Some requests are sync. That means
[04:04:01] whenever the request is received, we
[04:04:03] have to immediately provide them some
[04:04:05] output or response for the system to
[04:04:08] keep working. On the other hand, we have
[04:04:10] async calls, requests, or processes in
[04:04:13] which we get the request, but there is
[04:04:15] no hurry for our responses. Also, it is
[04:04:19] also possible that we don't give any
[04:04:21] response at all. So, so that means our
[04:04:24] system only
[04:04:26] takes the request and basically fulfill
[04:04:29] the requirement in the backend
[04:04:30] processes. So, in case of sync type of
[04:04:33] calls, requests, or processes, we can't
[04:04:35] do anything. Our system needs to be
[04:04:38] concentrated on these requests and have
[04:04:41] to provide the responses as soon as
[04:04:43] possible, which we have discussed
[04:04:45] throughout these courses. Now comes the
[04:04:47] second part, which are async requests.
[04:04:49] So, let's understand async process or
[04:04:51] request with some example. Let's say we
[04:04:54] are an e-commerce application. We have
[04:04:57] some store, maybe some product is there,
[04:05:00] and finally someone purchased this
[04:05:01] particular product. So, at the time of
[04:05:04] purchase, what are the operations we
[04:05:06] need to perform? First is, we need to
[04:05:08] send some email to the user that order
[04:05:11] is confirmed and here are your details.
[04:05:13] We have to also update the inventory so
[04:05:16] that if, let's say, only one product is
[04:05:19] left, that product should immediately be
[04:05:21] out of stock so that there will be no
[04:05:23] confusion for any other record. Other
[04:05:25] than this, we also have to inform our
[04:05:27] delivery partner, right? So, that they
[04:05:29] will start packaging and moving the
[04:05:31] order further. Now, out of these three
[04:05:33] processes or request, which do you think
[04:05:36] is the most immediate action? So, let's
[04:05:39] see. Updating inventory is one of the
[04:05:42] crucial task which have to be performed
[04:05:44] immediately. We can't wait for it,
[04:05:45] right? Otherwise, it can create
[04:05:47] blunders. So, this is definitely a
[04:05:50] synchronous task. But, other than that,
[04:05:53] we can use some third-party email
[04:05:55] service to process the email, right? We
[04:05:58] don't have to send the emails
[04:05:59] immediately. Even if the email goes,
[04:06:02] let's say, 1 minute late, that is also
[04:06:04] fine, and our system will be keep
[04:06:06] working.
[04:06:07] Similarly, for delivery, we can say that
[04:06:09] delivery also is an async operation
[04:06:12] because we are not in any hurry. Also,
[04:06:14] our system doesn't need to take care of
[04:06:16] delivery, as well. So, we will simply
[04:06:18] pass this information to any delivery
[04:06:20] service, and our current system can
[04:06:22] basically focus on some other task. So,
[04:06:25] this is how a distributed environment
[04:06:27] works. Basically, we have multiple
[04:06:30] services who communicate with each other
[04:06:33] in order to fulfill the requirement. So,
[04:06:35] if the services are different, and we
[04:06:38] have to use, let's say, email, with
[04:06:39] email, we can also use
[04:06:41] SMS service, or maybe WhatsApp service.
[04:06:45] We can use them, and these all are async
[04:06:48] kind of calls. We don't have to stop our
[04:06:51] system in order to process this request.
[04:06:54] So, I hope up to now we have understood
[04:06:56] about async and sync kind of request,
[04:06:59] and in async, why we can use some other
[04:07:01] services, and for sync, we have to wait
[04:07:04] for the response in order to show some
[04:07:06] immediate data, like out of service
[04:07:08] product. Now, let's talk about some of
[04:07:10] the examples for sync. Every financial
[04:07:13] application can be an example here.
[04:07:15] Wherever we are concerned about
[04:07:17] security, we can't rely on async kind of
[04:07:20] operation. We have to basically provide
[04:07:23] the communication immediately. The third
[04:07:25] area can be dependent. Wherever there is
[04:07:28] a dependency on one or the other task to
[04:07:31] be performed after a particular task in
[04:07:33] a synchronous manner, we have to
[04:07:35] complete this task in a synchronous
[04:07:37] manner.
[04:07:38] So that the dependent processes can also
[04:07:41] work. For example, we can't process any
[04:07:43] emails for order details before
[04:07:46] processing the order. Once the order is
[04:07:48] processed and confirmed, then only we
[04:07:51] can put down the emails or other
[04:07:53] notifications. So after this, let's talk
[04:07:55] about async also. Async request
[04:07:58] basically works wherever we need to
[04:08:00] simply fire our request and our system
[04:08:03] can then forget about that. So this is
[04:08:06] the golden rule to understand what
[04:08:08] system is async or what request is async
[04:08:11] versus sync. Whenever we get the feeling
[04:08:14] or we get the components where we can
[04:08:16] simply fire a request and then our
[04:08:18] system can forget about that, we can
[04:08:21] easily move to async calls, which will
[04:08:23] not only speed our systems but also free
[04:08:26] our system in order to work on different
[04:08:28] tasks. So some examples on free and
[04:08:31] forget can be broadcasting. Broadcasting
[04:08:33] can be of anything like email
[04:08:35] broadcasting, even the matches, the live
[04:08:37] matches which we see online on any
[04:08:39] application, there also we can feel some
[04:08:42] latency. The latency can be from 0
[04:08:44] seconds to 7 or 8 or 10 seconds also
[04:08:47] based on the network connections you
[04:08:49] have. So broadcasting we have discussed,
[04:08:51] email we can write here. Also we have
[04:08:53] seen
[04:08:54] SMS
[04:08:56] or WhatsApp. Basically any communication
[04:08:58] can be held asynchronously. Also the OTP
[04:09:01] applications. In all the OTP
[04:09:04] application, there is a timer and that
[04:09:06] timer is mostly more than 30 seconds.
[04:09:09] Why? Because in 30 seconds our system
[04:09:12] can handle this request in an async
[04:09:14] manner. So, now we have understood sync
[04:09:16] and async, let's talk about message
[04:09:18] queues. In order to understand message
[04:09:20] queue, let's take the same example. So,
[04:09:22] this is our e-commerce application and
[04:09:25] we are using the service for emails.
[04:09:28] Now, on our e-commerce application, we
[04:09:30] are getting some order and based on that
[04:09:33] order, we have to send emails.
[04:09:35] But, in between, we will implant message
[04:09:38] queue. In diagrams, message queue is
[04:09:41] denoted like this because it is
[04:09:42] basically a queue
[04:09:44] and each of these order request or email
[04:09:47] request can be hold in the message queue
[04:09:49] and then through our message queues, it
[04:09:52] can go directly to our email services.
[04:09:55] So, what our application needs to do, it
[04:09:58] will simply dump all the email request
[04:10:01] to our message queue and from there, the
[04:10:03] message queue will take care of those
[04:10:04] requests. It is like a buffer or we can
[04:10:07] say broker in between two apps or
[04:10:09] services. Now, whichever party or
[04:10:12] application is putting the request into
[04:10:15] message queues are known as producers
[04:10:18] and whichever service is taking the
[04:10:21] request from message queues are called
[04:10:23] consumers. With this, producers can also
[04:10:26] be called publishers and consumers can
[04:10:29] also be called subscribers because
[04:10:32] publishers are publishing the message to
[04:10:34] message queue and then subscribers are
[04:10:37] the message who are subscribed to take
[04:10:39] those request from our message queue.
[04:10:42] So, this is how a message queue
[04:10:43] basically works. You may think now that
[04:10:46] why are we using message queue? Can't we
[04:10:47] directly call the consumer or the email
[04:10:50] service from our application? Yes, we
[04:10:52] can call, but that will keep our system
[04:10:55] busy. We don't want to keep our system
[04:10:57] busy and we also want that whatever
[04:10:59] request we are sending should be taken
[04:11:01] care by. So, these two things can only
[04:11:04] be done by a message queue. Now, if we
[04:11:07] talk about qualities of message queue,
[04:11:09] before writing the qualities, I just
[04:11:11] want to say that if you still don't get
[04:11:13] what message queues are, just bear with
[04:11:15] me for some minutes and you will be
[04:11:16] absolutely get why do we use message
[04:11:19] queues. So, the first quality here is
[04:11:21] that our message queues can basically
[04:11:24] hold the request. With holding the
[04:11:26] request, our message queues will have to
[04:11:29] communicate those requests to our
[04:11:31] servers. So, they can communicate to
[04:11:33] servers or we can say services here.
[04:11:36] With this, why do we use message queue?
[04:11:38] The reason is it can also be used to
[04:11:41] handle the failed calls. And with this,
[04:11:43] one of the major reason of using message
[04:11:45] queue is handles the load which we are
[04:11:47] giving to the third party or the service
[04:11:50] application here, email service. At this
[04:11:52] point, let's talk about direct
[04:11:54] communication again. If we again send
[04:11:57] the request directly from our e-commerce
[04:11:59] application to email services, that
[04:12:01] means every time a new order is placed,
[04:12:03] this call is going to be there. If our
[04:12:06] email server is down or anything, that
[04:12:08] call is going to handle the failure case
[04:12:10] also. That will be responsibility of our
[04:12:13] e-commerce application. But now, since
[04:12:15] we are using message queue, these both
[04:12:17] queries and these both troubles will be
[04:12:20] handled by our message queue itself. So,
[04:12:22] we don't have to care about the failed
[04:12:24] request also. So now, what happens is
[04:12:26] there are various ways of sending
[04:12:28] request from message queue to the
[04:12:30] server. Normally, our message queues
[04:12:32] follows FIFO. We all know about FIFO.
[04:12:35] FIFO basically means first-in,
[04:12:37] first-out. That means whatever request
[04:12:40] comes first will be delivered first to
[04:12:43] our consumer. And this is how the series
[04:12:46] will follow. So, in this case, the first
[04:12:49] request will be taken care and then
[04:12:51] after that second, after then third, and
[04:12:54] so forth.
[04:12:55] So, this is what the first-in, first-out
[04:12:56] principle is and it is used by our
[04:12:58] message queue in order to process the
[04:13:00] request. So, in FIFO, we have two
[04:13:03] approaches. First is
[04:13:05] strict order approach, which basically
[04:13:07] means, let's say this is our message
[04:13:08] queue again,
[04:13:10] and while processing the orders or
[04:13:12] requests, let's say first process is
[04:13:14] processed by our consumer, done.
[04:13:17] After that, we'll come to the second
[04:13:19] one. So, the second one is also
[04:13:21] processed.
[04:13:22] Then, while processing the third
[04:13:24] request, it breaks down. So, maybe
[04:13:26] something is wrong with the request or
[04:13:28] maybe our consumer is down for some
[04:13:30] time. Because of any reason,
[04:13:33] our request was not processed. So, if we
[04:13:36] are following strict order, even if
[04:13:39] anything fails at this level, our queue
[04:13:42] will not proceed. Our consumer, even if
[04:13:45] it starts working again, can't process
[04:13:47] the fourth request. So, this is not
[04:13:50] recommended at all because of obvious
[04:13:52] reasons, because we want our process to
[04:13:55] keep continue even if one or other
[04:13:57] request fails.
[04:14:00] So, the second part solve this issue,
[04:14:02] which is unordered queue. So, in
[04:14:04] unordered queue, what we'll do, we'll
[04:14:07] again create like this only structure of
[04:14:10] our message queue. So, every time our
[04:14:12] consumer or subscriber
[04:14:14] takes back our request, so one, two, and
[04:14:18] even if there is some issue with the
[04:14:20] third request, our system will jump to
[04:14:23] the other request in order to fulfill
[04:14:25] that. So, our consumer will get the
[04:14:27] request to perform the operations. Our
[04:14:29] system will not break. What will happen
[04:14:32] to the third request? Let's talk about
[04:14:33] that in a bit. So, after unordered
[04:14:36] queue, it is also possible that the
[04:14:38] things which we are getting
[04:14:40] in request in the message queues, maybe
[04:14:43] our first request, second request, third
[04:14:45] request, and fourth request,
[04:14:48] between all of them, our fourth request
[04:14:50] is like very important to us, is of high
[04:14:54] priority, and maybe second request is
[04:14:56] also of high priority, but not first and
[04:14:59] third. So, in this case we can't follow
[04:15:01] FIFO principle, right? So, our consumer
[04:15:03] needs to get the second and the fourth
[04:15:05] request first. This is where we used
[04:15:08] priority queue.
[04:15:09] What we will do, we will attest a
[04:15:11] priority
[04:15:12] like number or some ID to every call.
[04:15:16] And whose priority is higher, those
[04:15:18] calls will be picked first by the
[04:15:20] consumers. So, in this structure if we
[04:15:22] talk about if the priority of every call
[04:15:26] is set, let's say the priority of first
[04:15:28] call is 10, the priority of second call
[04:15:31] is maybe three, the priority of third
[04:15:33] call is eight, and priority of fourth
[04:15:35] call is one. So, that means the first
[04:15:39] call which our C is going to cater is
[04:15:42] fourth one.
[04:15:43] After fourth, it will cater the second
[04:15:45] call. After second, it will cater the
[04:15:48] third call, and after third, it can
[04:15:50] cater the first call. Also, these
[04:15:53] numbers are in ascending order. I have
[04:15:55] created uh my system in that way that
[04:15:58] one will be the most important priority
[04:16:00] request, but you can reverse the order
[04:16:02] as well. So, this is how our priority
[04:16:05] queue is going to take request. After
[04:16:07] understanding priority queue, there are
[04:16:09] two more concepts here.
[04:16:11] So, the one concept is pull request. So,
[04:16:14] in pull request or pull-based request,
[04:16:16] what happens is whenever we have some
[04:16:19] data in our queue, let's again put 1 2 3
[04:16:23] or some random values. Now, these
[04:16:25] requests are in queue, which means that
[04:16:28] the queue message queue will take care
[04:16:30] of them.
[04:16:31] But, the consumer here will decide when
[04:16:35] to pick the request. Maybe our consumer
[04:16:37] is working with some other task, and the
[04:16:39] moment it gets free, it can pull the
[04:16:42] request. So, message queue will not send
[04:16:45] the request to consumers. Our consumer
[04:16:48] will pull the request accordingly.
[04:16:50] Again, the reverse of this is push-based
[04:16:53] request. In push-based request, what
[04:16:55] happens is the opposite of pull-based
[04:16:58] request, which means if we have some
[04:17:01] request in our queue, our message queue
[04:17:04] is going to start the communication with
[04:17:07] consumer and going to push our request
[04:17:09] to the consumers. So, here the
[04:17:11] communication starts from message queue,
[04:17:14] and in the previous case of pull-based,
[04:17:16] it will start with consumer. Also, I can
[04:17:18] change the
[04:17:20] uh direction of our request.
[04:17:22] So, because it is pulling, so request
[04:17:24] will come from here. So, I hope up to
[04:17:27] now the things are clear.
[04:17:28] Now, let's talk about pub/sub models.
[04:17:31] So, in pub/sub kind of architecture,
[04:17:33] what normally happens is we have
[04:17:35] publishers here who are like sending the
[04:17:38] message to our message queue.
[04:17:40] We have message queue in between,
[04:17:42] and here we can have multiple
[04:17:43] subscribers as well. So, what we are
[04:17:45] going to do, these publishers are going
[04:17:48] to send some or the other message to our
[04:17:50] message queue, which will be taken care
[04:17:52] by our message queue by providing them
[04:17:54] to the subscribers. Maybe this is using
[04:17:56] push, and this is using pull. So, this
[04:17:59] is how the system works in pub/sub
[04:18:01] model. Pub/sub is nothing but the
[04:18:03] understanding of our message queues
[04:18:05] only. So, in this model, we include
[04:18:07] subscribers
[04:18:09] and publishers as well. Now, as
[04:18:11] discussed in the previous example, our
[04:18:13] message queue needs to perform some
[04:18:15] operations in pub/sub model as well.
[04:18:17] First thing is it will hold the request.
[04:18:20] It will send these requests one by one
[04:18:22] to the subscribers. And also, in case of
[04:18:26] any failed response, message queue needs
[04:18:29] to take care of that. With this, our
[04:18:31] message queue is also responsible in a
[04:18:33] way to take care of subscribers as well.
[04:18:36] By taking care, I mean our message queue
[04:18:38] needs to check subscriber is working or
[04:18:41] not. If it is not working, our message
[04:18:43] queue will not send the request to that
[04:18:46] particular subscriber, and it will
[04:18:48] redirect the request to maybe some other
[04:18:50] subscriber. This is how the things work.
[04:18:52] So, our message queue basically
[04:18:54] maintains or the whole state of the
[04:18:57] request as well.
[04:18:58] Send the request to subscribers. Take
[04:19:01] care of the failed request by using DLQ.
[04:19:04] We will see that in a minute. And also
[04:19:07] take care of the subscribers health.
[04:19:09] Also keep checking whether the
[04:19:10] subscriber is it still alive to work or
[04:19:13] not. We can also say that it's still
[04:19:15] alive or not. We can also say that our
[04:19:17] message queue takes care of request and
[04:19:19] takes the response from subscribers as
[04:19:22] well. So, that means our message queue
[04:19:23] know which subscriber is working fine or
[04:19:26] fast and which is not working that
[04:19:28] delicately. So, every time we get a
[04:19:31] priority queue or a priority task, it
[04:19:33] will be sent to the subscriber who is
[04:19:35] working efficiently. So, this is what
[04:19:37] Pub/Sub basically is. Let's talk about
[04:19:39] some of the factors which can affect
[04:19:41] Pub/Sub. The first thing which you can
[04:19:43] talk about is message order. Let's talk
[04:19:46] about message order. So, we are saying
[04:19:48] that all the calls which are going to
[04:19:50] message queue are async calls. Then why
[04:19:53] do we need to maintain order? Okay.
[04:19:55] First thing is that even if we want to
[04:19:57] maintain some order, we know that we can
[04:20:00] use priority queue.
[04:20:01] And this is the only way of maintaining
[04:20:03] any kind of order in message queue.
[04:20:05] There is no other way. Maybe it is
[04:20:07] handled by our application or maybe we
[04:20:09] can add some additional information of
[04:20:11] order in the request itself. This is how
[04:20:14] we can handle message orders. Other than
[04:20:16] that, it is for async calls where the
[04:20:19] order doesn't matter. The second thing
[04:20:21] we can talk about is how our messages
[04:20:24] are going to be consumed. So, we know
[04:20:26] that publishers publish the message and
[04:20:29] they will store in message queue and
[04:20:30] consumers are going to consume this. But
[04:20:32] how they are going to consume this? We
[04:20:34] are not maintaining any order. That
[04:20:36] means these consumptions are random.
[04:20:40] Maybe out of 100 request, the consumer
[04:20:43] can pick up the 100 requests first. Even
[04:20:46] if we are using priority queue, we can
[04:20:48] make the priority of 100 requests first.
[04:20:50] So, there is no particular order in
[04:20:53] which the requests are going to be
[04:20:54] fulfilled.
[04:20:55] Consumers can pick any of the request
[04:20:58] anytime. Also, message queue can send
[04:21:00] any of the request anytime based on the
[04:21:02] priority either or it is completely
[04:21:05] random. Let's talk about the third
[04:21:06] factor, which is poison message. So, all
[04:21:10] the poison messages means all the
[04:21:13] messages that subscribers are not able
[04:21:16] to process. Maybe because they are bad
[04:21:19] requests or maybe invalid. It is also
[04:21:23] possible that they are failing like
[04:21:25] after multiple returns as well. Also, if
[04:21:27] we think about it, let's say a request
[04:21:30] failed at the consumer side. And then,
[04:21:32] if we send those requests again and
[04:21:34] again, those are going to use or consume
[04:21:37] the consumers energy and will do
[04:21:39] nothing. Those requests are basically
[04:21:41] our poison request who are taking time
[04:21:44] and resource from our consumer as well
[04:21:46] as message queue but are not able to
[04:21:47] fulfill. Now, at this point, let's talk
[04:21:50] about DLQ. So, this is our message
[04:21:52] queue. This is our publisher or
[04:21:54] producer, we can say. And here, we have
[04:21:56] our consumer or subscriber. Now, let's
[04:21:59] say we have a request which has not been
[04:22:02] processed by our subscriber due to any
[04:22:04] of the reasons. So, in this case, our
[04:22:07] message queue can't stop. It will send
[04:22:09] the next request. But, this first
[04:22:12] request will go to a different queue for
[04:22:15] retry or to maintain that this request
[04:22:18] was failed. This queue basically, which
[04:22:21] is maintained by our message queue only,
[04:22:23] is called DLQ. DLQ stands for dead queue
[04:22:27] or dead letter queue. So, our message
[04:22:30] queue maintains this DLQ in order to
[04:22:32] keep track of the failed request as
[04:22:34] well.
[04:22:35] So, that even if the publisher have put
[04:22:38] the async operations, eventually
[04:22:41] they will have to know that these cases
[04:22:43] are failed. So, we will see the failed
[04:22:45] logs or failed requests through any
[04:22:47] logs, from which we will see, "Okay,
[04:22:50] this request was failed."
[04:22:51] Or other than that, we can also send
[04:22:53] some or the other information to our
[04:22:55] publisher in a async manner or in a
[04:22:58] report kind of manner, where we will
[04:22:59] give the stats of these many requests
[04:23:01] are passed, these many requests are
[04:23:03] failed. And here are the reasons of the
[04:23:05] failed request. So, this DLQ is the
[04:23:08] mechanisms through which our message
[04:23:10] queue will take care of the failed
[04:23:12] requests as well. I hope you get it now.
[04:23:15] Also, poison. Poison means any request
[04:23:18] which can't be processed, which is using
[04:23:20] or consuming the resources, but can't be
[04:23:22] processed.
[04:23:24] So, with this, let's move to our four
[04:23:26] factor. Fourth factor basically is
[04:23:29] duplicacy. So, if, let's say, our
[04:23:32] message queue have processed this
[04:23:35] request when it is already processed by
[04:23:37] subscriber one, then it should not
[04:23:40] travel to subscriber two by any other
[04:23:43] way.
[04:23:43] Because the request is already
[04:23:45] processed, it should not be processed
[04:23:47] again. What if this request contains
[04:23:50] some important information which can't
[04:23:52] be done twice? So, in order to maintain
[04:23:55] duplicacy, our message queue only takes
[04:23:58] care of this thing.
[04:23:59] So, with taking care of each request and
[04:24:03] dead request, it is also duty of message
[04:24:06] queue that whenever a process is done,
[04:24:09] it should be deleted from our message
[04:24:11] queue, so that we don't perform any
[04:24:13] operation on that particular request. It
[04:24:15] should be deleted. And if configured,
[04:24:18] our message queue keeps end track of
[04:24:20] this, that there was some request which
[04:24:22] was obtained from P1 producer
[04:24:25] and was handled by our S1 subscriber.
[04:24:28] So, this is how our message queue will
[04:24:30] take care of the duplicacy of the
[04:24:32] request as well. After discussing all
[04:24:35] these things, let's talk about some of
[04:24:36] the use cases. Like where we can use
[04:24:39] message Q easily and where we should
[04:24:41] avoid using message Q. Let's say if we
[04:24:44] are working on any async kind of
[04:24:46] environment, any async operations, any
[04:24:49] async request, we can easily go for
[04:24:52] message Q. There is no doubt about that.
[04:24:54] Similarly, if we talk about any
[04:24:56] decoupling activity, which can be like
[04:24:59] taking care of user analytics we want to
[04:25:01] see and capture, maybe we want to
[04:25:02] capture where our user lands, if our
[04:25:05] order is failing, why they are failing,
[04:25:07] and all the log systems. We can easily
[04:25:09] do this with our message Q as well.
[04:25:12] There is no doubt about this.
[04:25:14] The third area can be our load balancing
[04:25:17] acts. So, if we think about it, our
[04:25:19] message Q does everything what a load
[04:25:22] balancer does, right? So, our message Qs
[04:25:25] can be used as load balancers as well.
[04:25:29] Where it will take care of all the
[04:25:31] request, it will keep them in a Q, and
[04:25:33] it will provide those requests to
[04:25:35] servers respectively.
[04:25:37] Also, we can use the message Q with this
[04:25:39] with the deferred system. Where we have
[04:25:42] some operations, but we can basically do
[04:25:44] them later, like generating reports and
[04:25:47] everything. After every day, we can
[04:25:49] generate some reports. Or maybe there
[04:25:51] can be any schedule processes for doing
[04:25:53] anything. Let's say we are adding
[04:25:55] products into our catalogs like whole
[04:25:57] day, and in the evening we want them to
[04:25:59] be live. So, we will schedule a process
[04:26:01] in order to work with them. So, the
[04:26:03] message Qs can be used with load
[04:26:05] balancer as well as they can be used by
[04:26:07] our deferred system. Now, message Qs are
[04:26:10] a costly service. So, if we don't have a
[04:26:13] lot of request, we should not use
[04:26:15] message Qs, right? Because it is a
[04:26:17] costly service, and why waste our cost
[04:26:21] when we can use them in a synchronous
[04:26:22] manner? Or maybe if the request count is
[04:26:25] low, we will directly call the
[04:26:27] subscriber from producers. Like for
[04:26:29] emailing, we will directly send the
[04:26:30] request for our email service. With
[04:26:33] this, if we are using any real-time
[04:26:35] application, we can't use message queues
[04:26:37] basically. Why? Because we need the
[04:26:40] response to be in a synchronous manner.
[04:26:42] We need the response to be immediate.
[04:26:44] And if we are using message queue,
[04:26:46] our request can take some time
[04:26:49] to basically respond from any email
[04:26:51] service or any other services which we
[04:26:53] are using. So, in these cases, we should
[04:26:55] avoid using message queues. And also, we
[04:26:57] should avoid using message queues
[04:26:59] whenever we need some acknowledgement.
[04:27:04] Because if we need some acknowledgement,
[04:27:05] that means our server or our system is
[04:27:09] waiting for the some response to get.
[04:27:11] But message queue normally doesn't do
[04:27:12] it. In this example, where we were
[04:27:14] sending some reports, this will be also
[04:27:17] done by some or the other intervention
[04:27:19] of our code only, so that we can see the
[04:27:21] processes. But if we want response from
[04:27:23] every request, it can't be done by
[04:27:25] message queue. So, whenever we need
[04:27:27] acknowledgement, we don't use message
[04:27:29] queues here. And with this, we have
[04:27:31] covered about message queues. Now, let's
[04:27:33] talk about faults. Whenever we think
[04:27:36] about faults or error, we basically,
[04:27:39] while building any system or while
[04:27:41] building any software as well, we have
[04:27:42] to take care of each and every fault and
[04:27:44] error. Now, while studying system
[04:27:46] design, we have encountered very
[04:27:48] components and we know what the
[04:27:50] complexity our software also holds. So,
[04:27:53] let's talk about faults and error. So,
[04:27:55] our faults or errors can be called as in
[04:27:58] any condition, if our system is not
[04:28:01] responding in a way it should respond,
[04:28:03] that means we have some issue or some
[04:28:06] fault or some error with our system. We
[04:28:09] can easily categorize them into three
[04:28:11] categories. The first category is
[04:28:13] hardware. So, hardware faults are
[04:28:15] basically belongs to our server. Maybe
[04:28:18] we are using databases, so DB can also
[04:28:20] crash.
[04:28:21] We are using message queues, we are
[04:28:23] using each and every components, and
[04:28:25] every component can fail our system if
[04:28:27] they stops working. So, this hardware
[04:28:30] issue or hardware fault is our first
[04:28:32] type, and the nature of our hardware
[04:28:34] failures is it can be random, right?
[04:28:37] Like our system can fail entirely
[04:28:39] anytime. There can be various reasons of
[04:28:42] its failure. We can have like a disk is
[04:28:44] full or something out of memory issue,
[04:28:47] or let's say our server is down. We also
[04:28:49] use network cables, so maybe they are
[04:28:51] damaged. Maybe there is an issue with
[04:28:54] the power supply. Maybe one or the other
[04:28:56] node is not configured correctly, or
[04:28:58] maybe it is experiencing some spike in
[04:29:00] request, so it is down because of
[04:29:02] overheating. Also, we are using
[04:29:04] databases, so database can also be
[04:29:06] compromised, right? These all things are
[04:29:08] basically the fault of our hardware. We
[04:29:11] do have some control over it, like we
[04:29:12] can pass some alerts whenever we are
[04:29:15] sensing any risk out of them, but they
[04:29:18] are like inevitable. Whenever a hardware
[04:29:21] fails, it mostly fails abruptly. That's
[04:29:24] why we use multiple systems in databases
[04:29:27] as well, and in terms of servers as
[04:29:29] well, so that if any server crashes or
[04:29:31] any databases goes down,
[04:29:34] we can use our system by using the other
[04:29:36] database or other server, maybe. So,
[04:29:38] this is what the hardware issue is. Now,
[04:29:42] let's talk about the second category of
[04:29:44] our issues, which is software issue.
[04:29:47] Now, our software issue can be caused
[04:29:48] through anything. Maybe the code which
[04:29:51] we are working on is written badly.
[04:29:53] Maybe we have forgot to handle any
[04:29:56] exception or anything. Maybe while
[04:29:58] testing our application, we tested all
[04:30:00] of the cases, but there are some edge
[04:30:01] cases which comes to our picture when
[04:30:03] the user actually uses the application.
[04:30:06] So, there can be some edge cases. Also,
[04:30:09] while coding in microservices or using
[04:30:11] APIs, we also configure them into our
[04:30:13] configurations. Maybe there can be some
[04:30:16] issue with the configuration itself that
[04:30:18] our system stops responding or maybe not
[04:30:21] responding in a way which it should be
[04:30:23] responding. Other than that, we can have
[04:30:25] some deployment issues as well. There
[04:30:27] can be some issues with the development
[04:30:28] environment and the production
[04:30:30] environment mismatch. So, something is
[04:30:32] working on production but not working on
[04:30:34] our development or vice versa. These
[04:30:36] things come on a day-to-day basis in the
[04:30:38] life of software developers. So, don't
[04:30:40] worry about this but we have to take
[04:30:41] care of this and this is our software
[04:30:44] issue or software fault we can say. With
[04:30:46] this, if I have to write any other
[04:30:48] thing, uh one of the major pain points
[04:30:50] can be merge requests. So, let's say two
[04:30:53] developers working on similar feature or
[04:30:55] same file parallelly and when the code
[04:30:58] compiles of both of them, we need to
[04:31:00] thoroughly test both of the
[04:31:02] functionalities so that it doesn't break
[04:31:04] down each other on the production or on
[04:31:06] staging or on any environment. So, this
[04:31:08] is one of the most pain point thing of
[04:31:11] any developer. Other than that, our
[04:31:12] software fault or software issue can be,
[04:31:15] let's say, our requests are taking too
[04:31:17] much time. So, the performance is also
[04:31:20] something which software should take
[04:31:22] care of. But the good and the bad thing
[04:31:24] about software issues is that it is not
[04:31:27] random. There has to be something in the
[04:31:29] configuration or code file which we can
[04:31:31] find out and solve that issue. Also,
[04:31:34] this is not random, this is a good thing
[04:31:37] so that we can find out the issue. But
[04:31:39] with not random, it is also
[04:31:40] deterministic which means by following
[04:31:43] the same steps, we can get that proper
[04:31:46] error again and again. And if that error
[04:31:49] is not fixed sooner, that can basically
[04:31:51] break our system or give a bad
[04:31:53] experience to our users.
[04:31:55] So, we need to fix software issues very
[04:31:58] carefully and ASAP. Now, the third fault
[04:32:01] is not really a fault but it comes into
[04:32:04] the category of fault and is considered
[04:32:06] the most important faults in our system
[04:32:09] which is human fault. We know that every
[04:32:12] human is unpredictable and we don't have
[04:32:15] any control over ourselves. We can do
[04:32:17] basically anything. So, this kind of
[04:32:19] issue or error can cause unpredictably.
[04:32:23] Why? Because humans are considered to be
[04:32:26] most unreliable components of software
[04:32:28] development among all.
[04:32:30] Every component, whenever they are
[04:32:32] failing or not working, give us an alert
[04:32:35] beforehand. But with humans, it is
[04:32:38] sometimes possible, sometimes not
[04:32:39] possible based on the value of that
[04:32:41] particular developer or anyone attached
[04:32:43] to the software development cycle. But
[04:32:45] with saying these all things about
[04:32:47] developers or humans, we also need to
[04:32:49] know that it is one of the most powerful
[04:32:52] component or person in the software
[04:32:55] development life cycle. If human stops
[04:32:57] working, nothing is going to work. Even
[04:33:00] if the code is written by AI agents or
[04:33:03] AI anything, Claude, OpenAI, or any
[04:33:05] other open source, it is still needs to
[04:33:08] be rectified by human only. Because we
[04:33:11] need some accountability over that code
[04:33:13] because that code is going to build a
[04:33:15] product which is going to be used by
[04:33:17] humans only. So, we need human in
[04:33:20] between all these processes. So, this is
[04:33:22] one of the most powerful thing. That
[04:33:24] means that makes us responsible for
[04:33:27] handling the code even more. So, these
[04:33:29] are the three categories in which we
[04:33:30] divide our faults normally into. The
[04:33:33] software issue, the hardware issue, and
[04:33:36] the human fault or human error. Human
[04:33:39] issues can be solved by having good
[04:33:41] behavior or not doing the band-aid fixes
[04:33:43] or quick fixes in the wrong manner, but
[04:33:46] going deep into the system and fixing
[04:33:48] the thing entirely for each and every
[04:33:50] area. Also, by software issues, we
[04:33:53] should not write bad code, handle
[04:33:55] exceptions properly, see the edge cases,
[04:33:57] maybe do testing thoroughly of each and
[04:33:59] every component every time you make a
[04:34:01] build. It can be solved, right? Also,
[04:34:04] deployment issues can be solved if you
[04:34:05] configure each and every environment
[04:34:07] variable carefully. There can be other
[04:34:09] configurations for databases or for
[04:34:11] other APIs which can be configured on
[04:34:14] development environment as well in order
[04:34:16] to replicate that issue and eventually
[04:34:18] solve it. Now, if we talk about
[04:34:20] hardwares, hardwares are something which
[04:34:21] we don't have any control on. So, if any
[04:34:24] hardware is going down, it is mostly
[04:34:27] unpredictable. So, this is also a danger
[04:34:29] point. That's why we have to scale our
[04:34:31] system in order to handle the system
[04:34:34] perfectly or in a better manner. So,
[04:34:37] this is all about faults and errors.
[04:34:39] Now, let's understand about the last
[04:34:41] topic of system design, which is most
[04:34:44] important but many playlists skip this
[04:34:46] one. This is our monitoring and
[04:34:49] observability. We all know that in our
[04:34:52] product life cycle, our product is once
[04:34:54] developed will be deployed to any of
[04:34:56] these servers and then will be
[04:34:58] maintained. Now, creating a product is
[04:35:01] entirely different from maintaining that
[04:35:04] product. Here, we don't have to maybe
[04:35:06] change a lot of code and add lot of
[04:35:08] features, but we have to keep monitoring
[04:35:11] whether our product is working fine or
[04:35:14] not. So, we have to take care of these
[04:35:16] following things. Are there any errors
[04:35:18] in our system or not? Is every component
[04:35:20] basically is working fine or not? How's
[04:35:22] the health of each and every server,
[04:35:24] every component, every database? If
[04:35:27] there are coming edge cases or any
[04:35:29] errors in our system, are we recording
[04:35:31] them correctly? Do we have logs in place
[04:35:34] so that each and every customer request
[04:35:36] can be tracked and can be seen whether
[04:35:38] they are working fine or not. And if
[04:35:40] there is any error, can we like go to
[04:35:42] the RCA of that particular error so that
[04:35:45] our developer can debug and perform the
[04:35:47] required operation. And also, if any
[04:35:49] other component is going down or
[04:35:51] basically down at this particular
[04:35:53] moment, do we have other systems in
[04:35:55] place who will take care of the system?
[04:35:57] And also, do we have proper alert
[04:35:59] systems so that we can rectify or get
[04:36:01] these messages beforehand so that we can
[04:36:04] take care of the situation in a better
[04:36:05] way. So we need to take care of all of
[04:36:07] these things plus more in the
[04:36:09] maintenance phase or while maintaining
[04:36:11] our application. For example, let's talk
[04:36:13] about microservices. So one microservice
[04:36:17] can do two operations, right? Either it
[04:36:19] can handle a request and work on it or
[04:36:22] the other thing it can do is it can even
[04:36:24] redirect the request to any other
[04:36:26] microservices. So in this case, we have
[04:36:28] to monitor two things. The first thing
[04:36:30] is how our APIs are performing and while
[04:36:34] handling any request or whenever a
[04:36:36] microservice or a server is working on
[04:36:38] anything, we need to also check
[04:36:40] how it is affecting our machine. Like
[04:36:43] how much memory it is consuming, what
[04:36:45] are the consequences of this particular
[04:36:47] request if it gets overloaded or
[04:36:49] something. So we have to take care of
[04:36:51] the machine as well as the APIs at the
[04:36:54] same time. Now let's talk about both of
[04:36:56] them one by one. So if we talk about API
[04:36:59] monitoring, the first thing we need to
[04:37:01] check is our throughput. Now what is
[04:37:03] throughput? Throughput basically means
[04:37:05] how many requests can our server handle.
[04:37:08] Let's say our server can handle 10k
[04:37:11] requests per second. So that means if
[04:37:15] our server is already hitting 9k or
[04:37:18] maybe 8k responses, we have to configure
[04:37:21] some alerts in order to know whether we
[04:37:23] are going to hit our throughput or not
[04:37:25] and maybe we'll migrate the data or the
[04:37:27] request to some other servers at the
[04:37:29] particular time because we need this
[04:37:31] server to perform or to be alive. The
[04:37:34] other thing which we can monitor while
[04:37:35] using the APIs can be our error codes.
[04:37:39] Like we all know about 500 issues and
[04:37:43] 400 issues and maybe we are using some
[04:37:45] redirects also so 300 issues as well. We
[04:37:49] need to know how many 500s are we
[04:37:51] getting, how many 400 requests are we
[04:37:53] getting, how many 300 requests are we
[04:37:55] getting. So the first thing is when we
[04:37:57] are getting too many error things, we
[04:37:59] need to know the RCA of it. So, that
[04:38:02] means our logging should be in places so
[04:38:05] that our developer can work. One thing
[04:38:06] is that. Also, we need to put some alert
[04:38:09] whenever the count increases after a
[04:38:11] particular point so that we can get to
[04:38:13] know about the 500 issues or 400 issues
[04:38:16] or 300 issues and fix them accordingly.
[04:38:18] Third thing is our health check. So, in
[04:38:21] order to check health of any components,
[04:38:24] we have already seen that we can do it
[04:38:25] by two ways, passive and active. So, we
[04:38:28] have to constantly monitor the 200
[04:38:31] responses as well and see if our
[04:38:33] component is in a working condition or
[04:38:36] not and is giving the positive replies
[04:38:38] or not. The fourth thing is to check our
[04:38:41] latency. Latency is a very good metrics
[04:38:44] in order to check the performance of any
[04:38:45] system. How can we check the latency?
[04:38:48] Suppose we have some 10 requests and
[04:38:51] suppose these values are the response
[04:38:53] time of those APIs. Now, we need to know
[04:38:57] the response time of our particular
[04:38:59] server, of our particular API system.
[04:39:02] So, how do we calculate them? If we use,
[04:39:05] let's say, average, the average gives
[04:39:07] the wrong value because, let's say, our
[04:39:09] average value for this will come to 6.8
[04:39:12] seconds, right? But, if we see most of
[04:39:15] our requests are being handled in a much
[04:39:18] lower rate. So, this average value
[04:39:20] basically gives a wrong impression of
[04:39:22] our services. So, apart from average, we
[04:39:26] check P values. What is P? P basically
[04:39:29] stands for percentile. So, what is a
[04:39:31] percentile? Percentile basically says if
[04:39:34] we are writing P90, we are saying that
[04:39:37] our 90% of the request can be handled in
[04:39:41] a particular seconds or maybe
[04:39:44] milliseconds, whatever the time is. In
[04:39:46] our current example, if we arrange them
[04:39:48] in an ascending order, something like
[04:39:50] this, we can see that we have 10
[04:39:52] requests and P90 will be calculated here
[04:39:55] and all of the requests like 90% of the
[04:39:58] requests will take lesser time than this
[04:40:00] time. So, this is our 12 seconds maybe.
[04:40:03] So, let me also remove this milliseconds
[04:40:05] for a bit. 12 seconds should not be idle
[04:40:07] time for any API response. This is just
[04:40:09] for the example, okay? Similarly, if we
[04:40:12] talk about let's say P50 here, P50 will
[04:40:15] be 4 seconds, right? So, that means 50%
[04:40:18] of our request are currently covered
[04:40:21] under 4 seconds. So, we can see that P50
[04:40:24] is 4 second and somehow P90 is 12
[04:40:27] second, that means something should be
[04:40:29] off between these two. We have to check
[04:40:31] all the APIs which are giving us the
[04:40:33] response of near 12 seconds. And we have
[04:40:36] to basically optimize them and improve
[04:40:38] the performance of our entire system.
[04:40:40] Again, these P90, P50, P70, P maybe
[04:40:46] 99.9,
[04:40:47] when we have a large system and a lot of
[04:40:49] calls, so all these matrices and values
[04:40:52] percentiles help us in jot down how our
[04:40:55] system is working in a majority portion.
[04:40:58] And also, we can optimize the
[04:41:00] performance of our system by checking
[04:41:02] the differences of different P values.
[04:41:04] So, it is very useful in case of
[04:41:06] optimizing our code as well and also, we
[04:41:08] need to know how our system is
[04:41:10] eventually working. So, this is what
[04:41:13] percentile is used for and we use it to
[04:41:16] calculate the latency of our project.
[04:41:18] Again, here also, we can provide some
[04:41:20] alert system. Let's say our P90 here is
[04:41:23] 12 second and if our responses are
[04:41:26] taking 50 second or something, we should
[04:41:28] get an additional alert because this is
[04:41:31] an unusual behavior for us now. So, this
[04:41:34] is how we take care of latency of our
[04:41:36] system as well. So, after APIs, let's
[04:41:38] talk about machine monitoring. By
[04:41:40] machine, I mean hardware, right? The
[04:41:42] factors of measuring how our hardwares
[04:41:45] are working, the first factor if we talk
[04:41:47] about it can be our CPU usage, like how
[04:41:50] much power is being consumed by that
[04:41:52] particular operation or that particular
[04:41:55] hardware while doing some particular
[04:41:56] operation. And if that usage basically
[04:41:59] exceeds any limit, let's say I'm taking
[04:42:01] example of 75, maybe you can take 70, 90
[04:42:04] accordingly. We should get an alert that
[04:42:07] your CPU usage is already attained a
[04:42:10] 75%. So you need to take care of the
[04:42:12] systems. Again, the other thing can be
[04:42:15] memory usage. Let's say already we have
[04:42:17] consumed 90% of the memory.
[04:42:20] So we know now that our database will
[04:42:23] not be able to hold more values. So we
[04:42:25] need to immediately either scale our
[04:42:27] system or we need to see whether we are
[04:42:30] getting some error or not. Similarly, we
[04:42:32] have a lot of input-output operations as
[04:42:35] well. So we have to take care of disk IO
[04:42:37] operations as well as network also. In
[04:42:40] both of these cases, we can set the
[04:42:42] limit and once the limit is exceed, we
[04:42:45] can send alerts accordingly. So this is
[04:42:47] all about monitoring our APIs and
[04:42:49] machine. Now, let me give you a quick
[04:42:51] recap of all the things which we have
[04:42:53] discussed so far. We have discussed
[04:42:55] about system design, what is system
[04:42:57] design, what are the different
[04:42:59] components of system design. Then we
[04:43:01] have discussed about data intensive and
[04:43:03] compute intensive applications, then
[04:43:05] functionality and non-functionality
[04:43:07] requirements, what is DNS, APIs. We have
[04:43:10] also understood REST APIs in details.
[04:43:13] After that we move on to DB, our SQL and
[04:43:16] no SQL DB with detail. Also, cache and
[04:43:19] their strategies of eviction as well as
[04:43:22] how do we store the data in cache. We
[04:43:24] have completed all the cache part very
[04:43:25] extensively so that we don't get any
[04:43:28] issues afterwards.
[04:43:29] We have also covered load balancing and
[04:43:31] load balancer in which we have talked
[04:43:33] about how a load balancer acts as a
[04:43:35] mediator between the coming request and
[04:43:38] the request which goes to server. Also,
[04:43:41] it works as an orchestration between
[04:43:43] different servers and take care of each
[04:43:45] and everyone's health. With that, we
[04:43:47] have covered various forms of
[04:43:48] replication, partitioning. Ultimately,
[04:43:51] one of the most important theorems which
[04:43:53] we're going to cover in each and every
[04:43:55] interview, that is CAP theorem. Whether
[04:43:58] you'll choose availability over
[04:44:00] consistency or vice versa. After CAP
[04:44:03] theorem, we have covered message queues,
[04:44:05] fault tolerance, and then we had a brief
[04:44:07] discussion about monitoring and
[04:44:09] observability also.
[04:44:11] So, with all these topics, now we are
[04:44:13] ready to give any interview or to design
[04:44:17] any system design component which we
[04:44:19] want to. We have a solid foundation now.
[04:44:22] Now, we can design any system. So,
[04:44:25] congratulations, you have unlocked a new
[04:44:27] trick, a new component, a new system in
[04:44:30] your resume, in your abilities. Also, if
[04:44:33] you feel like I have missed any point or
[04:44:35] any topic, please mention that in the
[04:44:37] comment. I may make a video of it in the
[04:44:40] coming days.
[04:44:41] With this, let's move to the last part
[04:44:43] of our video, which is designing a
[04:44:46] system. So, whenever you appear in an
[04:44:48] interview of system design or maybe you
[04:44:50] will design a system by yourself, it is
[04:44:52] very important to think out loud. So,
[04:44:55] you have to take your decisions very
[04:44:57] specifically. No one is looking for the
[04:44:59] perfect solution, but everyone here is
[04:45:01] looking for what are the trade-offs you
[04:45:03] make, what are the components you use.
[04:45:05] Also, when I'm talking about components,
[04:45:08] whenever you are using a component, it
[04:45:10] is very important that you use it for
[04:45:12] the right reasons. Just because you know
[04:45:15] about all the components, it is not
[04:45:16] recommended to add all the components
[04:45:18] into your system. Because remember,
[04:45:21] every component you add will add the
[04:45:23] costing of your system also. So, we have
[04:45:26] to use the component and design the
[04:45:28] system very efficiently so that it can
[04:45:31] be cost-efficient as well as work
[04:45:33] efficiently to solve our purpose. So,
[04:45:36] for now, let's design a video streaming
[04:45:39] application.
[04:45:40] So, see, we already have a lot of
[04:45:42] applications. We have YouTube for
[04:45:44] streaming. We also have, let's say,
[04:45:46] Hotstar, Netflix, Prime. Also, if we
[04:45:50] talk about streaming applications, we
[04:45:52] can also say G Meet is also a streaming
[04:45:55] application because we can do the live
[04:45:57] streaming.
[04:45:58] Uh we can call it a Zoom call or a G
[04:46:00] Meet also. So, Zoom can also come into
[04:46:03] this category where we stream our video
[04:46:05] live to other members. So, a call is
[04:46:09] basically also an example of a streaming
[04:46:10] application. Now, with this, we can also
[04:46:13] use LMS or any other software for
[04:46:16] streaming our data. We can have more
[04:46:18] applications. I'm just jotting this down
[04:46:20] so that you get the idea of the
[04:46:22] applications which use streaming. Now,
[04:46:24] before starting, it is very important to
[04:46:27] jot down the requirement. So, for our
[04:46:29] video, we doesn't care about user login.
[04:46:32] We don't care about their reviews and
[04:46:35] maybe rating also. We don't care about
[04:46:38] any other operation, but we only need to
[04:46:41] know how a video basically process from
[04:46:44] one system to finally our client system.
[04:46:48] This is what we need to know in this
[04:46:50] particular example. Now, whenever you
[04:46:53] appear on an interview also, it is very
[04:46:55] important to jot down the requirement
[04:46:57] because let's say they give you an
[04:46:59] example of designing any software like
[04:47:01] Netflix, you need to know what are the
[04:47:04] features the interviewer is interested
[04:47:06] in. With that, while creating your
[04:47:09] systems also, you need to know
[04:47:10] specifically what you are designing
[04:47:12] because you may be designing an entire
[04:47:14] LMS, but for that moment, you need to
[04:47:17] pick feature by feature and design each
[04:47:20] component and at the end, maybe collect
[04:47:22] all the findings and create a system.
[04:47:25] This is how every system is built. Now,
[04:47:28] here, we only are talking about this
[04:47:30] process
[04:47:31] of getting a video to our client system
[04:47:34] from any server or from any other
[04:47:36] source. Okay, so let's start from very
[04:47:38] basic.
[04:47:39] What is a video? A video is nothing but
[04:47:42] a collection of different images we can
[04:47:45] say and with this we also have some
[04:47:47] audio here.
[04:47:48] So different images are combined with
[04:47:50] audio to create a video, okay? So in
[04:47:53] order to calculate different images we
[04:47:55] can see FPS or frame per second. We can
[04:47:58] have 30 or 60.
[04:48:00] These two things are available. Also, we
[04:48:02] can use 120 or 240 if they're available.
[04:48:05] I'm not that sure about it. But yeah,
[04:48:07] these two frame rates are quite common
[04:48:10] in our day-to-day life.
[04:48:11] So what does it mean to have 30 and 60
[04:48:14] FPS? Basically, in 1 second, if we are
[04:48:18] using 30 FPS, our video will be divided
[04:48:21] into 30 images.
[04:48:23] And if we are using 60, for 1 second, it
[04:48:26] will be divided into 60 images.
[04:48:28] So that means the size of 60 FPS will be
[04:48:31] more than that of a 30 FPS video. But if
[04:48:35] we talk about the video smoothness, also
[04:48:38] the 60 FPS video will be more smoother
[04:48:41] than a 30 FPS video. Now with this,
[04:48:44] let's stick to 30 FPS thing. Let's say a
[04:48:47] size of a normal video, let I'm like I
[04:48:51] am recording a video in 30 FPS right
[04:48:53] now.
[04:48:54] My recording, let's say went for 1 hour
[04:48:57] and for the 1 hour recording video, the
[04:48:59] size of my recording is basically
[04:49:02] around 2GB.
[04:49:04] So if, let's say you are watching this
[04:49:06] video and if you want to download the
[04:49:09] entire video in the start before playing
[04:49:12] and then you play,
[04:49:14] what will happen? It will add latency to
[04:49:17] our system because downloading 2GB will
[04:49:19] take time for sure. Also, you have to
[04:49:22] see buffer and let's say you downloaded
[04:49:25] all the 2GBs of content into your system
[04:49:27] just to see a particular section or
[04:49:29] maybe you see the first 10 seconds of
[04:49:31] the video and didn't like it. So, you
[04:49:33] wasted your internet and storage. So,
[04:49:35] this is not a good option to download
[04:49:37] 2GB entirely first hand and then see a
[04:49:40] video. It is completely waste of time.
[04:49:42] So, we have to think about something
[04:49:44] else. So, the thing is here we have to
[04:49:46] use some network which is suitable for
[04:49:48] our system. So, in order to process
[04:49:51] information in video or images form, we
[04:49:53] normally go for TCP. Because TCP
[04:49:56] maintains a sequence of things. Why do
[04:49:59] we need sequence? Let's see in a bit.
[04:50:01] So, in TCP we have two protocols. One is
[04:50:05] RTMP which is Real Time Messaging
[04:50:07] Protocol and the other one is RTSP which
[04:50:09] is Real Time Streaming Protocols. Both
[04:50:12] of these protocols basically help us in
[04:50:14] order to stream a particular video to
[04:50:16] our device. Now, what this protocol does
[04:50:18] is let's say we have a complete video
[04:50:20] here. It is going to divide our video
[04:50:23] into different chunks called as
[04:50:26] segments. And our client machine or the
[04:50:28] server from which we are watching is
[04:50:31] going to pull these segments one by one.
[04:50:34] Now, in message queues we have talked
[04:50:35] about pull and push. This time I'm
[04:50:37] saying pull. So, just connect the dots.
[04:50:40] Keep connecting the dots while I'm
[04:50:41] saying things, okay? So, this is going
[04:50:43] to pull our segments one by one based on
[04:50:46] the network. Now, we'll come to this
[04:50:48] part in a bit. So, this will solve our
[04:50:50] issues.
[04:50:51] This will give us a low latency because
[04:50:54] we don't have to download the entire
[04:50:55] video. We can download some segments
[04:50:57] also. With this we'll now be able to
[04:50:59] stream in a much better way and it will
[04:51:02] be more efficient than downloading the
[04:51:04] entire video which was consuming our
[04:51:06] resources and network bandwidth. Now,
[04:51:08] this time we have to only download some
[04:51:10] segments which is going to be more
[04:51:13] efficient because this time we are
[04:51:15] downloading in parts. So, suppose we are
[04:51:18] watching one video, first 10 seconds is
[04:51:20] over and now we don't want to watch the
[04:51:22] entire video. So maybe some or the other
[04:51:25] sections will be pre-downloaded for us
[04:51:27] so that if you go ahead we don't see
[04:51:30] buffer, but we don't have to download
[04:51:32] the entire video which will save us a
[04:51:34] lot of space and lot of network
[04:51:36] bandwidth as well. Now with FPS we also
[04:51:39] have one more factor which changed the
[04:51:41] game entirely which is resolution. With
[04:51:45] videos we have different resolutions,
[04:51:47] right? We can use 4K, we can use HD, we
[04:51:50] can use maybe 720p,
[04:51:53] we can use 480 or 240 or even 144p. Even
[04:51:59] 64p was an option. I'm not sure whether
[04:52:02] our video will be able to render in that
[04:52:04] quality or not. I have like way before
[04:52:06] when I was in school, maybe I saw that.
[04:52:09] After that I didn't. So yeah, these are
[04:52:11] all the resolutions on which we can see
[04:52:14] our video. 4K will obviously have better
[04:52:17] quality and 144p
[04:52:20] is going to have bad quality. But why
[04:52:23] are we talking about resolutions is even
[04:52:25] if let's say we are streaming a 4K
[04:52:28] video,
[04:52:29] which I already said for 1 hour video we
[04:52:32] need to store it in 2GB space. Suppose
[04:52:36] we divide this into multiple segments
[04:52:38] for each second, then 1 second will be
[04:52:41] 0.57
[04:52:42] MB. Now this looks small but is a huge
[04:52:45] size if we talk about network. What if
[04:52:47] we have a poor network? What if we are
[04:52:50] traveling? So our network is keep on
[04:52:52] fluctuating on a different level. Also
[04:52:54] if we sit by working on our office or on
[04:52:56] system, our networks keep on fluctuating
[04:52:59] as well. So that means we are not going
[04:53:02] to have a common bandwidth throughout
[04:53:04] our video viewing experience. So our
[04:53:06] network will keep on increasing and
[04:53:08] decreasing. So we have to take care of
[04:53:10] that also. Let's say I record videos in
[04:53:13] HD only and if I start recording in 4K,
[04:53:17] that means the size of 2GB can become
[04:53:21] big, right? The 2GB can go to 4GB. Maybe
[04:53:24] I use multi-cam setups. At that time,
[04:53:27] the 4GB can also go up to 8GB, maybe.
[04:53:30] Also, in my videos, I'm not doing much
[04:53:32] activity. The frames are pretty still.
[04:53:35] Only my hand movements can be shown once
[04:53:37] in a while. I'm sitting still. I'm just
[04:53:39] facing the camera or the screen. I'm not
[04:53:41] doing much activities. Also, the screen
[04:53:43] you are seeing is black on which I'm
[04:53:45] writing in white. So, there are no
[04:53:47] colors, also. So, this is pretty easy
[04:53:50] video to see. But, if I start recording
[04:53:53] outside or maybe I start recording any
[04:53:55] action sequence, so in that case, the
[04:53:57] size can also get to 16GB for the same
[04:54:01] 4K video of 1 hour. So, this size can
[04:54:04] also be increased to four times. So,
[04:54:06] that will be around 4MB. So, the issue
[04:54:09] here is for even 1-second video, we are
[04:54:12] using 4MB. And if our network is not
[04:54:15] that good, we are still going to see
[04:54:17] buffer or face loading issues, which is
[04:54:20] going to basically ruin the experience
[04:54:22] of our viewer, and they will leave the
[04:54:24] application. This is not what we want
[04:54:27] entirely, right? So, we have to do
[04:54:28] something about it. Also, if you think
[04:54:30] about it, there are different screens on
[04:54:32] which you work on. We maybe watching
[04:54:34] something on TV. We maybe using our
[04:54:36] laptop screen. Uh also, we can use our
[04:54:39] mobile screen, maybe our watch as well.
[04:54:42] Maybe we are seeing it on iPad. We don't
[04:54:44] want 4K qualities in all of them, right?
[04:54:47] Let's say we are watching on watch, we
[04:54:49] don't want 4K.
[04:54:51] Maybe on watch, 480 works fine. And
[04:54:54] also, on iPad, also, I don't think 4K is
[04:54:57] required. Maybe we can show them in SD,
[04:54:59] and it will be enough. On TV, we
[04:55:01] basically require 4K. Like, we don't
[04:55:03] have to compromise here. But, on laptop,
[04:55:06] also, we can switch between HD and 4K.
[04:55:09] We can choose. We can pick based on the
[04:55:11] requirement or based on the
[04:55:12] configuration, based on the network
[04:55:14] also. On mobile also, we can work pretty
[04:55:17] well with SD. We don't need 4K here as
[04:55:19] well. So, that means not only network,
[04:55:22] but based on our screen size, we can
[04:55:24] change the resolution of our video. So,
[04:55:26] why are we changing?
[04:55:28] Because it is going to reduce the size
[04:55:30] of our segment. And the lesser the size,
[04:55:32] the faster it will be to show. So, in
[04:55:34] order to maintain streaming, we have one
[04:55:37] mechanisms, which is adaptive bitrate
[04:55:39] streaming. What it basically conveys is,
[04:55:42] let's say you start watching a video on
[04:55:44] 300 Mbps. And your networks keep on
[04:55:47] fluctuating. Maybe it went down till 10
[04:55:50] Mbps. So, when the network fluctuates,
[04:55:52] we can't download with the same
[04:55:54] consistency. And if we are not able to
[04:55:56] download with the same consistency,
[04:55:58] there's high chance of seeing the buffer
[04:56:01] icon. And we don't want that.
[04:56:03] So, in order to achieve this, what can
[04:56:05] we do? We have a source video
[04:56:08] of 4K, right?
[04:56:10] We have to divide this video into
[04:56:12] different segments, that we know. Also,
[04:56:15] we have to divide those segments into
[04:56:17] different qualities. So, for example,
[04:56:20] this 4K video is divided into 10
[04:56:22] segments of 4K quality. But now, also we
[04:56:25] have to divide these segments into more
[04:56:27] configurations, the lower
[04:56:29] configurations. Now, our basic
[04:56:31] resolutions and segments are ready. Now,
[04:56:34] let's see in real time how our function
[04:56:37] really works. So, let's say here we have
[04:56:39] our client who is watching something on
[04:56:42] our desktop screen. In starting, the
[04:56:44] network connection was 300 Mbps. So, we
[04:56:48] start showing them the 4K video. So, it
[04:56:51] sees segment one, maybe segment two also
[04:56:53] he watches. And then, the network drops
[04:56:56] to 10 Mbps. So, at this point, maybe
[04:56:59] this is already loaded into their system
[04:57:02] in the form of cache. So, they can still
[04:57:04] see this section into 4K. But after
[04:57:06] that, we need to load the data again.
[04:57:09] And the network is now at 10 Mbps. So,
[04:57:12] we can't load the 4K data. What we will
[04:57:14] do, we will load the lower configuration
[04:57:17] data. Maybe according to this we will
[04:57:19] pick 480p.
[04:57:22] So, we will start downloading this data.
[04:57:24] And once the network restores to maybe
[04:57:26] 300 or 150 Mbps, we will start switching
[04:57:30] our configurations accordingly. So, we
[04:57:32] can go to 1080p as well. And if it then
[04:57:37] drops to 50 Mbps, we can still give them
[04:57:40] 720p. And at the end, if network
[04:57:43] basically restores to 300 Mbps,
[04:57:47] we can show them the last segment in 4K
[04:57:49] again. So, this is how an YouTube or any
[04:57:52] other stream basically works.
[04:57:55] They will keep switching our quality
[04:57:57] based on our network bandwidth because
[04:57:59] we are mostly seeing that entire video
[04:58:01] on a single screen.
[04:58:03] And based on our network, they will keep
[04:58:05] switching the qualities. And we see the
[04:58:07] entire video into one go
[04:58:10] without seeing the much difference there
[04:58:12] because normally the network doesn't
[04:58:14] drop so drastically. We just keep these
[04:58:16] segments in order to show them into
[04:58:18] different devices. If you pay attention
[04:58:21] in most of the streaming applications
[04:58:23] where you are seeing the video, in the
[04:58:25] side corner, you also see a segment
[04:58:27] where you can switch your configurations
[04:58:29] again. You can choose between auto,
[04:58:33] maybe HD, or maybe they will directly
[04:58:36] use the configuration that is 720p or
[04:58:39] 480p,
[04:58:40] something like this.
[04:58:42] So, you can choose between them. And if
[04:58:44] you choose auto,
[04:58:46] they are going to perform this
[04:58:47] orchestration or this game while you
[04:58:49] watch the entire video. So, what did we
[04:58:52] see here? If the network throughput,
[04:58:55] that means our network speed, is greater
[04:58:57] than the bitrate of the downloaded
[04:59:00] segment, that means we have downloaded
[04:59:02] in a lower quality and now network is
[04:59:05] greater than that. So we can now switch
[04:59:09] to a better quality. Similarly, if the
[04:59:12] network throughput is less than
[04:59:15] the bitrate of
[04:59:17] downloaded segment, so in this case what
[04:59:21] we will do, we will switch down the
[04:59:23] quality of our video. So after getting
[04:59:26] all this knowledge, after discussing all
[04:59:28] these things with your interviewer or
[04:59:30] with your team,
[04:59:31] then you start deciding what components
[04:59:33] do you use in your system design. Now
[04:59:36] the path is very clear, right? We need
[04:59:38] to store the current data or the actual
[04:59:41] data somewhere. Maybe this is our CDN
[04:59:44] where the actual data or the actual
[04:59:46] video is uploaded and it is uploaded
[04:59:48] from where? From any server. Now from
[04:59:51] here we need to create the segments, so
[04:59:53] that means we need to give this data to
[04:59:55] a service which can basically transform
[04:59:58] our video. So we can name that we can
[05:00:00] say it is a transformation service. Now
[05:00:03] after this we have to send the segments
[05:00:06] to our queue. We can use priority queue
[05:00:08] here, right? So we can create a queue.
[05:00:11] And why we are using priority queue? You
[05:00:13] need to answer yourself. Now
[05:00:15] from this message queue, our system is
[05:00:18] going to use the services of downgrading
[05:00:21] each and every quality. So we use worker
[05:00:24] term here. Worker is basically used in
[05:00:26] order to denote another service. So we
[05:00:29] may be using worker one for downgrading
[05:00:32] it to HD. Also we can use worker two for
[05:00:35] maybe downgrading it to 720p and so
[05:00:39] forth. So after working with these
[05:00:41] resolutions, again we need a message
[05:00:43] queue to store the results into segments
[05:00:46] and again we need a priority queue here.
[05:00:48] Okay, with this we will send this
[05:00:50] request to a distributed CDN kind of
[05:00:52] services from where it can go into
[05:00:55] different part of our servers. So, if
[05:00:58] someone is watching from India, they can
[05:01:00] access the data from this server and
[05:01:03] they can watch it from US server and the
[05:01:05] other servers are for other regions.
[05:01:07] Now, by doing this, we have completed
[05:01:10] the entire system design of our video
[05:01:12] streaming application. And from this
[05:01:14] server,
[05:01:15] eventually, we are going to access it on
[05:01:17] our client machine on which our user is
[05:01:20] going to watch their video. So, now
[05:01:22] after creating this diagram, let's also
[05:01:24] do some maths.
[05:01:26] Let's say our source video is of 50 GB
[05:01:30] and it is of 20 minutes. So, it is a
[05:01:33] high-quality video, maybe 4K, and it is
[05:01:35] having 60 FPS. So, that's why the size
[05:01:38] is too big. So, this is we are taking as
[05:01:40] an average size of the video which we
[05:01:42] are going to stream. Maybe we are
[05:01:44] streaming an entire match. So, this is
[05:01:46] the size which we are going for our
[05:01:47] 20-minute video. Now, let's decide how
[05:01:50] many segments can we divide it to. So,
[05:01:52] I'm doing an easy maths. So, 20 minutes
[05:01:55] multiplied by
[05:01:57] 60, that will convert it into seconds.
[05:02:00] So, it will be 1 2 0 0 seconds. And
[05:02:04] also, I am making the segments also
[05:02:06] equal, so that means 1 2 0 0
[05:02:09] segments as well. Also, with this, let's
[05:02:11] talk about different resolutions. So,
[05:02:13] let's say 4K is of 50 GB, which will be
[05:02:17] divided by our segment. So, here the
[05:02:19] size of our segment is too large, right?
[05:02:21] Because it is a 4K video. Maybe we can
[05:02:24] divide it into more segments. So, but
[05:02:27] for this example, let's stick to it.
[05:02:29] Let's say our 1080 pixel video,
[05:02:32] let it be for 20 GB and again, we are
[05:02:35] going to divide it by 1200. It is going
[05:02:38] to be again 16.6 MB.
[05:02:41] With this, let me write all the
[05:02:42] resolutions.
[05:02:43] Now, this is what the calculation looks
[05:02:45] like if we divide it for each segment
[05:02:47] for each resolution. For 720, it will be
[05:02:50] 8.3 MB. For 480, it will be 4.17. And
[05:02:54] for 250, it will be 2.08 MB. That means
[05:02:57] if we combine them all, it is going to
[05:03:00] be 72.65
[05:03:02] MB, approximately. So, that means the
[05:03:05] size of one segment of our video is
[05:03:08] going to be 72 MB, which is too huge, I
[05:03:11] feel. So, maybe we can divide it into
[05:03:13] further segments. But for now, this is
[05:03:15] going to be the size of our one segment.
[05:03:18] And accordingly, we need to load the
[05:03:20] data into our stream.
[05:03:22] Also, while calculating the size, we
[05:03:24] should also take care of our user. That
[05:03:26] means we should know how many users are
[05:03:29] going to see the stream. So, if the user
[05:03:31] count is, let's say, 100, we can use the
[05:03:34] same server or a single server only,
[05:03:36] right? For 100 number. If we count this,
[05:03:39] it will comes down to 87.5 GB.
[05:03:42] So, we can store 87.5
[05:03:44] GB
[05:03:46] into a single server, and from which
[05:03:48] these 100 users can view our streaming
[05:03:51] easily. What if the user changes from
[05:03:54] 100 users to 100,000 users? Now, this
[05:03:58] will change our picture. Now, this is
[05:04:00] where we will know that our one server
[05:04:03] is maybe not enough to cater so much
[05:04:05] requests. So, we will divide our servers
[05:04:08] into two, maybe. And based on the number
[05:04:11] of users, we have to keep increasing the
[05:04:13] count of servers. Maybe we'll use
[05:04:15] message queues. Maybe we'll add some
[05:04:17] caching algorithms. And all of this will
[05:04:19] be managed through our diagram. Here, I
[05:04:22] have not used any caching. But we can
[05:04:25] use the caching on CDN level.
[05:04:28] Or we can use the cache on our browser
[05:04:30] level,
[05:04:31] which is going to hold the segments of
[05:04:33] the coming part. So, this is what the
[05:04:35] design look like. This is what the
[05:04:37] calculation is. And this is what is the
[05:04:39] logic behind the system design of my
[05:04:42] system, which will stream our video to a
[05:04:46] 10,000 or a 100,000 user. Now, this
[05:04:49] diagram can be different in your case
[05:04:52] also. It is very possible that you will
[05:04:54] design a system better than me, and it
[05:04:57] is also possible that you will see some
[05:04:59] other YouTube video who have designed
[05:05:01] the video better than me or maybe worse
[05:05:03] than me. So, these designs are basically
[05:05:06] your practice.
[05:05:08] The more you practice, the more you see
[05:05:10] other designs, the more you read
[05:05:12] different papers, your designs are going
[05:05:14] to improve. And more your design
[05:05:16] improves, the quality of your system or
[05:05:18] your workflow increases with time. So,
[05:05:21] with this, I end the discussion of
[05:05:23] system design.
[05:05:24] And I really hope you all enjoyed this
[05:05:26] series so far. This was a long video,
[05:05:29] and we covered a lot of topic. I hope
[05:05:31] you all enjoyed it. Now, you can like
[05:05:34] this video or comment the most
[05:05:35] interesting section you found out in
[05:05:37] this video. Also, you can comment out
[05:05:40] any topic which you want to see in
[05:05:42] future on Telescop. With this, my name
[05:05:45] is Akshat Agarwal, signing off. Thank
[05:05:47] you.
