In addition to Weibo, there is also WeChat
Please pay attention
WeChat public account
Shulou
2025-03-14 Update From: SLTechnology News&Howtos shulou NAV: SLTechnology News&Howtos > IT Information >
Share
Shulou(Shulou.com)11/24 Report--
This article comes from the official account of Wechat: low concurrency programming (ID:dibingfa), with the original title: "Bad stuff | Why is Redis so fast", author: flash
I'm a redis service, and I'm about to start it.
Because my master is typing:
/ redis-server look at my process from a macro point of view, suddenly, the owner pressed the enter key, which is amazing.
The shell program loads my program into memory and starts executing my main method, and that's where it all starts.
Int main (int argc, char * * argv) {initServer (); aeCreateFileEvent (fd, acceptHandler,); aeMain ();} Don't think I'm very complicated here, in fact, there are only three major steps.
As a first step, I created a TCP connection through the listenToPort () method.
My method really knows the meaning by name, and if you expand it, you will find that there is no mystery, that is, the socket bind listen standard takes three steps to establish a TCP snooping and returns a file descriptor fd.
In the second step, I add the above file descriptor fd returned by creating a TCP connection to a linked list called aeFileEvent through the aeCreateFileEvent () method.
At the same time, bind the file descriptor to a function acceptHandler, so that when a client connects in, the function will be executed.
In the third step, through the aeMain () method, I use all the file descriptors in the above aeFileEvent linked list as input parameters of select, which is the IO multiplexing mode. If you don't know much about it, please read, "you call this stupid thing IO multiplexing?" ".
Well, in fact, it just turns on a TCP listener, and then if a client comes in, let him execute the acceptHandler function.
I've been waiting for the client to connect ever since.
Void aeMain (aeEventLoop * eventLoop) {eventLoop-stop = 0; while (! eventLoop-stop) aeProcessEvents (eventLoop, AE_ALL_EVENTS);}
Start to experience my specific work at this time, another person started a redis-client and connected to me.
Redis-cli-h host-p port then the fd on my head senses data reading and executes the acceptHandler method.
Static void acceptHandler () {cfd = anetAccept (); c = createClient (cfd)} you can see that when a new client connects in, createClient is called to create a dedicated client to serve it.
Static redisClient * createClient (int fd) {aeCreateFileEvent (c-fd, readQueryFromClient,);} you can see here that the so-called proprietary service is actually still this aeCreateFileEvent function.
As mentioned above, the function of this function is to hang the file descriptor on the linked list and assign a handler.
Of course, this time the handler is no longer the acceptHandler that handles the new client connection, but the function readQueryFromClient that handles the redis command sent by the specific client.
It is not difficult to imagine that if there is another client, there is another client. Then constantly hang up the file descriptor of the new client, and it is always the top file descriptor that listens to the new client connection.
All right, the server is listening and the client is connected to the server. At this time, I am still waiting for the arrival of the new client connection, but also waiting for the command from the client that is already connected.
Note that in the case of death, there is only one thread that iteratively calls the aeProcessEvents function and listens for multiple file descriptors in a select way. Put the third step of the main method just now to help you remember.
Void aeMain (aeEventLoop * eventLoop) {eventLoop-stop = 0; while (! eventLoop-stop) aeProcessEvents (eventLoop, AE_ALL_EVENTS);} when a new client establishes a connection, it triggers the execution of the acceptHandler function, with an extra descriptor waiting for data.
When there is data from the client, the readQueryFromClient function is triggered to execute the command.
Note that because only one thread is listening to these descriptors and doing processing. So even if the client sends commands concurrently, the commands are still fetched in turn and executed sequentially.
This is what we often say, redis is single-threaded, commands and commands are executed sequentially, and there is no need to consider thread safety.
In order to make it easier for you to brag, let me boost it. Have you noticed that my startup process is actually divided into two major parts.
One is to listen for client requests, which is to use IO multiplexing to listen for multiple file descriptors, which is what the aeMain () method just did.
One is to execute the corresponding function to handle the request. Exactly what function is executed is bound by multiple aeCreateFileEvent () methods. This corresponding function, to put it taller, is called an event handler.
The so-called connection reply processor here is the function acceptHandler bound by the file descriptor that just listened for the connection.
The so-called command request processor is the function readQueryFromClient bound by the file descriptor that listens for client commands (read events).
The so-called command reply processor is the function sendReplyToClient that listens for the file descriptor binding of the client response (write event), as mentioned later.
This one is responsible for responding to IO events, and the other is responsible for handing it to the corresponding event handler, which is called Reactor pattern.
Redis develops its own file event handler based on Reactor pattern, implements a high-performance network communication model, and maintains the simplicity of single-thread design within Redis.
I'm a little worried that the boasting of this sentence is not enough. In fact, I made reference to "Redis Design and implementation" and took a screenshot for you.
Exactly how to execute a Redis command
Now, we issue a redis command from a client that has established a connection.
Set dibingfa niubi the readQueryFromClient function will be executed at this time.
This function will go to a table to find the function corresponding to the command, and this part of the coding technique is called command mode.
Static struct redisCommand cmdTable [] = {{"get", getCommand,2,REDIS_CMD_INLINE}, {"set", setCommand,3,REDIS_CMD_BULK | REDIS_CMD_DENYOOM}, {"setnx", setnxCommand,3,REDIS_CMD_BULK | REDIS_CMD_DENYOOM}, {"del", delCommand,-2,REDIS_CMD_INLINE}, {"exists", existsCommand,2,REDIS_CMD_INLINE},} found the function corresponding to the set command is setCommand.
This function will eventually store key and value step by step.
After the command is processed, the response is sent to the client.
Static void setCommand (redisClient * c) {addReply (c, nx? Shared.cone: shared.ok);} this response is not written back synchronously, nor does it start a thread to write back asynchronously.
It still calls the vicious aeCreateFileEvent function and hangs the sendReplyToClient function on the file descriptor of the client connection that needs to respond.
Static void addReply (redisClient * c, robj * obj) {aeCreateFileEvent (server.el, c-fd, AE_WRITABLE, sendReplyToClient, c, NULL) = = AE_ERR;} well, the hole dug in the previous section has finally been filled.
The above crap, is my startup process, I am not very cute.
Postscript
I don't seem to talk about why Redis is so fast in the whole article, because I don't think it's a good question.
You can start from the IO multiplexing point of view of receiving network requests, or from the event handler-driven Reactor mode, or from the specific data structure when dealing with commands, such as the sds behind the string has actually done a lot of clever design.
If I were the interviewer, I would specifically ask the interviewer to talk about the startup process of Redis, or the whole process of Redis processing commands.
There are a lot of points to dig here, and if you can talk and laugh, it is naturally that the technical level is not bad.
In addition, you will find a lot of bluff terms in this article, such as Reactor pattern, event handler, etc., you will find that it is really very simple after taking a look at the Redis source code.
To put it bluntly, everything does not talk about the specific implementation, and you pile up a lot of bluffing articles or people, are playing hooligans.
In this article, I refer to the Redis3.0.0 source code, but the explanation code used in this article is Redis1.0.0, and the design of the whole network module is exactly the same.
Welcome to subscribe "Shulou Technology Information " to get latest news, interesting things and hot topics in the IT industry, and controls the hottest and latest Internet news, technology news and IT industry trends.
Views: 0
*The comments in the above article only represent the author's personal views and do not represent the views and positions of this website. If you have more insights, please feel free to contribute and share.
Continue with the installation of the previous hadoop.First, install zookooper1. Decompress zookoope
"Every 5-10 years, there's a rare product, a really special, very unusual product that's the most un
© 2024 shulou.com SLNews company. All rights reserved.