Transcription
Hello friends!
This is Max Dobrynin. I am 100% sure that each of you has wondered what microservices exist today. But the main question is: which of them are used in real projects?
We all know that there are patterns like Saga, Event Sourcing, and other interesting designs. However, after implementing numerous projects and talking to many current and former colleagues, as well as acquaintances in the IT field, it became clear that not all cool design patterns are actually applied in real projects.
Strangely enough, there is a list of the most popular design patterns that are often underestimated by juniors, mid-levels, and even seniors. I assure you, after watching this video, you will know about the design patterns that are truly used in projects, rather than some flashy concepts that are frequently discussed in various topics, yet no one has ever seen them in action.
So, let's dive in!
[Music]
First up is the API Gateway. Yes, we all know that there is such a thing as an API Gateway; it’s not a secret. However, let’s try to understand in detail what it is, why it’s needed, and what types of API Gateways exist.
The first thing to consider is the task that the Gateway solves. Imagine you are in a microservices architecture. You have several services that are interconnected, forming your ecosystem. Now, let’s picture various clients—not customers in a store, but clients connecting to your application via some protocol, let’s say HTTP.
How do you envision this client communicating with the various services in your ecosystem? Of course, traditionally, you need to know the list of URLs in the system. However, in a microservices architecture, this only complicates things.
Imagine we need to support authentication. Here arises a logical question: does each service have to handle authentication, or in other words, secure access, on its own?
Now, let’s return to our microservices architecture, and we will quickly realize that this authentication service would have to be placed in front of each service. Agree, that’s not very convenient. On the other hand, we still suffer from the problem of having one URL for each specific service, and our client needs to know all of this.
This is where the API Gateway comes in, serving as a single entry point into our ecosystem.
Now, let’s complicate the situation. We live in a time of vast amounts of data, and naturally, all these services must handle the load. Now, the client needs to know not only the URL of a specific service but also its specific instance or node—whatever you want to call it.
At this point, we have gathered a multitude of problems. First, the client needs to know the specific URL of a specific service. Second, we somehow need to ensure secure access to data through these services, even though each service may have its own unique set of security rules.
Last but not least, scaling. We need to know how many instances of a specific service are currently running and ready to work. This means that the client now needs to know not just one URL and its corresponding port, but several ports corresponding to the instances of this service.
This is where the API Gateway comes in. Essentially, it acts as a simple gate, providing a single access point to our services. The client does not need to know how many services actually exist; it only needs to know the paths—or endpoints—that perform business operations through a specific service.
This greatly simplifies the client’s life, as they do not need to know the details of the entire infrastructure, and they should not have to react to it.
On the other hand, when we talk about scaling, this is again a great option. If a service starts to scale and the number of its instances increases, the client still does not need to worry about the URL or the corresponding ports, because they have the API Gateway. They have one URL that leads to this API, and the API Gateway will distribute the load among the running services.
When we want to access a service, many security issues can be delegated to the API Gateway, and through the API Gateway, they will be resolved. If a user is not authenticated, that client will simply receive a denial of their request, and in general, such a request will not reach the service.
Another cool feature of the API Gateway that almost everyone forgets or doesn’t know about is that it can be divided into different types. Here, we are talking about what this API Gateway is aimed at.
The first type I would like to highlight is the Gateway that is focused on Web APIs. In other words, this is a type of gateway designed to communicate with clients that serve as graphical interfaces. It’s not hard to guess that this is a browser.
On the other hand, we live in a world of devices. Every day, we carry phones, tablets, and other gadgets that are being developed. How do you think all these devices interact with a complex microservices architecture? Of course, through a special gateway created for mobile applications.
Lastly, we can mention the public API Gateway, which is tasked with providing APIs that will later be used by clients that are, in turn, other services.
You might ask me, “Seriously, Max, why create various gateways? Can’t we just use one?” No, friends, in modern times, that makes no sense. If you truly have a complex infrastructure with a huge number of users and an even larger amount of data being exchanged, having a special gateway solves many of your problems.
If you think for a moment about the vast amount of data provided for an application you open in a browser, and if you take almost the same application and open it on your phone, you will likely be disappointed that it doesn’t have the full set of functionalities and far from all the data available in the full version, which is browser-based or desktop-based.
This is because it’s simply impossible to fit everything into one. In other words, one of the reasons why there are different API Gateways is the subject area and the environment where the provided data is applied.
What did you think? The API Gateway is just about accessing multiple services in your structure? No, of course, there’s much more to it, but now you know this and can share it with your colleagues.
If you didn’t know this but want to learn more, practice, or test your knowledge, dive into the training platform IPR. There, you can practice for technical interviews before going to a real one or just check your knowledge.
On the other hand, if you need to implement a microservices architecture in a team, prove that it’s possible, add it to your portfolio, and then show off during a technical interview, then dive into the IPR training platform as well.
All links are in the description. Fill out the form, and a manager will get in touch with you. Now, let’s move on to implementing popular design patterns.
Next up is the very popular Health Check API. Many people simply forget about this, even though this design pattern is fundamental for any service implemented in a microservices architecture.
So, what is a Health Check API? Well, it’s clear from the name—it’s about health. But what exactly does it refer to?
Let’s imagine a specific situation. You have a service that performs key logic, and many other services connect to this service. Additionally, your service has a relational database, caches, connections to asynchronous queues, and much more that can be imagined.
Now, let’s assume that one of these services, on which your service relies, has simply gone down. For example, the database has run out of memory, or the asynchronous queue is currently unavailable for some unknown reason.
At the same time, a huge influx of client requests comes in, and your service starts to crash with errors. It reacts to failed requests, begins to scale, and new instances are added. Kafka is still down, Redis is down, and who knows what’s happening with the database.
Even though each service has its own instance of the database, they can all be down. Let’s assume the data center has gone down. Naturally, client requests have no idea that some services or their key nodes are down or currently not in the best shape.
This is where the Health Check API comes in, designed to respond to these tasks and provide the necessary information to the relevant services for decision-making about whether this service is ready as a whole to handle incoming requests.
In simpler terms, a Health Check API is an additional endpoint that exists for each service and its specific instance. It shows the current status of each individual component on which this service depends.
For example, the database, its memory usage, resources consumed, and so on. After we have the status of each specific service that our service relies on, the system can automatically compute the overall health status of our specific service.
Such a service can be identified as operational, often referred to as "Up," or it may be completely non-operational, with a status of "Down," or it may currently be unavailable, and it’s undesirable to direct any requests to it, which would be indicated by a status of "Out Of Service."
Accordingly, an internal service that periodically polls the Health Check API can decide whether to direct requests to this service based on the overall status of the specific service instance.
We briefly touched on load balancers, but we won’t discuss them now, so don’t get ahead of yourself.
When your service, in a single instance, goes down, the internal system can poll its Health Check. It can initiate an additional instance of this service, and here automatic scaling will kick in based on the status. In this case, clients will not receive denials for their requests. Instead, it may take a little longer, and those requests can be redirected to another service that is ready for operation.
There can be many combinations and solutions, but the main point is that you now know that Health Check is an integral part of any service in a microservices architecture.
Well, if you’re still interested, give us a like and subscribe. This helps us grow on the internet and make this video truly public property.
A moment ago, we touched on the topic of authorization and authentication as part of the API Gateway, but it’s time to talk about a very popular thing that is used in almost any microservice: the Access Token design pattern.
What is it? You might know it better as a JWT token or JSON Web Token. This token contains all the necessary data that identifies a specific user in the system. In other words, based on this token, we can verify whether the person making the request is who they claim to be, or simply put, perform the authentication process.
Moreover, this token can also include authorization data, meaning what rights the authenticated user has. There is a difference: authentication is essentially determining the authenticity of the person they claim to be. For simplicity, think of it as an ID card that contains your data.
And of course, since a JWT token is just JSON, it can easily be sent over HTTP. Subsequently, in your infrastructure, the service responsible for authentication can confirm the user based on the data contained in this token.
On the other hand, the authorization process is essentially granting access to perform certain operations.
We’ve already established that, yes, I am Max Dobrynin, and I have an ID card. Well, it’s like Lilu Dallas—those who have seen it know.
The point is that not everyone has the right to access certain operations. If you log into your social media profile, you can edit that profile. However, if you are a manager of a public page representing a store, not every user granted managerial rights for that selling page can perform admin actions, such as renaming the page, hiding it, or even deleting it.
This, friends, is the authorization process, and all of this is packed into the JWT token. Why? Because it’s simply convenient.
Returning to the microservices architecture, imagine you have multiple microservices, and your user indeed exists in the database. We can identify them. Moreover, the system has roles, and this user has several roles.
However, if you look at the microservices architecture and see that there are several services, not every role is suitable for performing operations across different services.
This is where the JWT token helps us again. After we pass through the API Gateway and the user is authenticated, the service can again check this JWT token and decide whether another user can access the operations that this service exposes. If not, they will receive an HTTP error 403 Forbidden, meaning the operation is not allowed.
Again, nothing complicated—just a simple design pattern in microservices architecture that for some reason everyone forgets to talk about.
By the way, I would also like to hear about it, especially since it can be explained briefly with simple examples instead of spending 45 minutes discussing Saga or struggling to explain the Secure pattern in agony, because not many people truly understand what the Secure pattern is, and even fewer have had to implement it, and even fewer have had to overcome the problems created by this Secure pattern.
But you already understand that if you need to learn how to build a good microservices architecture, dive into the IPR training platform. You will find it there. The link is in the description, and a manager will get in touch with you.
I won’t go on with this propaganda anymore. I know for sure that all of you are excited about all these message brokers, asynchronous queues, and so on.
This is indeed a very convenient mechanism for implementing asynchronous communication. It helps scale, sends messages, reacts to errors, and can go on endlessly repeating this.
But that’s not what we’re talking about.
Let’s imagine a situation where you are implementing a system for transferring funds from one account to another. Very often, you have to communicate with other financial institutions.
Now, let’s imagine a situation where an error occurred during the request to transfer funds from one account to another. However, the communication took place, and the message was sent to another financial institution.
But your service knows nothing about it because the error occurred right at the thin line where the message was sent, but there was no logging or anything.
What will you do in this case? Of course, in retry mode, which is also a microservices pattern, you will repeat this request, and by doing so, you will most likely create an error because the money will be transferred twice.
How is that possible? I only transferred the funds once! The situation is that your request went to another financial institution, which has already registered this request, and the process of debiting funds has begun.
However, because your system was not notified about this, it sent another request, and it was successfully processed by that same second financial institution.
How can we avoid such a problem? We don’t want to lose money!
This is where the Idempotency pattern comes in.
No, friends, not this time. We will talk about Idempotency.
Everyone has surely heard of the Idempotency Key phenomenon. This key is essentially part of the Idempotency implementation.
The idea is that every time a system wants to deliver a message or process a message, it only does so once by creating a special database that stores unique identifiers describing each specific request.
Accordingly, the API client that sends a request to such a consumer must include an idempotency key generated by a special algorithm in the request.
And voila! After receiving the request, the consumer accesses this key. They can check its existence in the database, and if it already exists, that request will not be processed, and the client will receive the corresponding response.
If such a record does not exist, it is added, and that request is marked for processing by the idempotent consumer.
As you can see, there’s nothing super complicated about this. However, while discussing this design pattern, we also indirectly touched on the Retry pattern, which is also a design pattern in microservices architecture.
You might ask me, “Will anyone talk about this in technical interviews?” No, everyone tries to talk about the Secure pattern for no reason, never having implemented it.
So, friends, after this video, you have definitely become a little better than you were moments ago. Now you have a complete deck of microservices architecture design patterns, and you can confidently lay these cards on the table when asked what design patterns in microservices architecture you have ever applied or know about, or what you would do in this situation to avoid duplicating incoming requests.
You already understand that this video needs to be added to your favorites, liked, commented on, and of course, shared with your colleagues, friends, and the entire honest world.
This was Max Dobrynin. That’s all for today, and I remind you that you are on the JetBrains channel. Subscribe here, follow us on Telegram—it’s awesome there!
And of course, join our IPR training platform. All links are in the description.
Friends, see you soon!
[Music]