当前位置:网站首页>Talk about how redis handles requests

Talk about how redis handles requests

2022-07-27 20:03:00 Gegwu MMQ!!

summary

The first is to register the processor ;
Open the loop listening port , Every time you hear a connection, you create one Goroutine;
Then is Goroutine There will be a loop waiting to receive the request data , Then according to the requested address to match the corresponding processor in the processor routing table , Then the request is sent to the processor for processing ;
In code, that's it :

Copy
func (srv *Server) Serve(l net.Listener) error {

baseCtx := context.Background()
ctx := context.WithValue(baseCtx, ServerContextKey, srv)
for {
// receive listener Network connection over here
rw, err := l.Accept()

tempDelay = 0
c := srv.newConn(rw)
c.setState(c.rwc, StateNew)
// Create coprocessing connection
go c.serve(connCtx)
}
}
about Redis It's a little different , Because it's single threaded , Cannot use multithreading to process connections , therefore Redis Select Use Based on Reactor Mode event driver to realize the concurrent processing of events .

 Insert picture description here

stay Redis Zhongso Reactor The pattern is through epoll To monitor multiple fd, Whenever these fd When there is a response, it will be notified in the form of an event epoll Make a callback , Each event has a corresponding event handler .

Such as : accept Corresponding acceptTCPHandler Event handler 、read & write Corresponding readQueryFromClient Event handlers, etc , Then, the event is allocated to the event processor for processing in the form of circular distribution of events .

So this one above Reactor Patterns are all through epoll To achieve , about epoll There are three main methods :

Copy
// Create a epoll The handle of ,size Used to tell the kernel how many monitors there are in total
int epoll_create(int size);

/*

  • It can be understood as , Additions and deletions fd Events that need to be monitored
  • epfd yes epoll_create() Created handle .
  • op Express Additions and deletions
  • epoll_event Indicates the event to be monitored ,Redis Only readable , Can write , error , Hang up Four states
    */
    int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event);

/*

  • It can be understood as querying qualified Events
  • epfd yes epoll_create() Created handle .
  • epoll_event Used to store the collection of events obtained from the kernel
  • maxevents Maximum number of events obtained
  • timeout Waiting timeout
    */
    int epoll_wait(int epfd, struct epoll_event * events, int maxevents, int timeout);
    So we can implement a simple server:

Copy
// Create a listener
int listenfd = ::socket();

// binding ip And port
int r = ::bind();
// establish epoll example
int epollfd = epoll_create(xxx);
// add to epoll The type of event to listen for
int r = epoll_ctl(…, listenfd, …);

struct epoll_event* alive_events = static_cast<epoll_event*>(calloc(kMaxEvents, sizeof(epoll_event)));

while (true) {
// Events wait
int num = epoll_wait(epollfd, alive_events, kMaxEvents, kEpollWaitTime);
// Traversal Events , And handle the event
for (int i = 0; i < num; ++i) {
int fd = alive_events[i].data.fd;
// Get events
int events = alive_events[i].events;
// Distribution of events
if ( (events & EPOLLERR) || (events & EPOLLHUP) ) {

} else if (events & EPOLLRDHUP) {

}

}
}
Calling process #
So according to the above introduction , You know, for Redis There are only a few steps in an event cycle :

Register event listening and callback functions ;
Loop waiting to get the event and handle ;
Call callback function , Processing data logic ;
Write back data to Client;
 Insert picture description here

register fd To epoll in , And set the callback function acceptTcpHandler, If there is a new connection, the callback function will be called ;
Start an endless loop call epoll_wait Wait and continue to handle the event , We will return to aeMain Loop call in function aeProcessEvents function ;
When a network incident comes , Will follow the callback function acceptTcpHandler Call all the way to readQueryFromClient Data processing ,readQueryFromClient Can parse client The data of , Find the corresponding cmd Function execution ;
Redis After the instance receives the client request , After processing the client command , Write the data to be returned to the client output buffer instead of returning immediately ;
And then in aeMain Every time the function loops, it calls beforeSleep Function writes the data in the buffer back to the client ;
In fact, the code steps of the whole event cycle above have been written very clearly , There are also many articles on the Internet , I won't talk more .

Command execution process & Write back client #

Command execution #
Now let's talk about some things that are not mentioned in many online articles , have a look Redis How to execute commands , And then it's stored in the cache , And write data back from the cache Client This process .

 Insert picture description here

In the previous section, we also mentioned , If a network event comes, it will call readQueryFromClient function , It's where the orders are actually executed . We just follow this method and keep looking down :

readQueryFromClient It will call processInputBufferAndReplicate Function to process the requested command ;
stay processInputBufferAndReplicate It's called inside the function processInputBuffer And judge if it is a cluster mode , Whether you need to copy commands to other nodes ;
processInputBuffer The function will cycle through the requested commands , And call according to the requested Protocol processInlineBuffer function , take redisObject Call after object processCommand Carry out orders ;
processCommand When executing the order, it will pass lookupCommand Go to server.commands Find the corresponding execution function according to the command in the table , Then after a series of checks , Call the corresponding function to execute the command , call addReply Write the data to be returned to the client output buffer ;
server.commands Will be in populateCommandTable In the function, all Redis Order to register , As a table that gets command functions according to the command name .

for instance , To execute get command , Then it will call getCommand function :

Copy
void getCommand(client *c) {
getGenericCommand;
}

int getGenericCommand(client *c) {
robj *o;
// Find data
if ((o = lookupKeyReadOrReply(c,c->argv[1],shared.nullbulk)) == NULL)
return C_OK;

}

robj *lookupKeyReadOrReply(client *c, robj *key, robj *reply) {
// To db Find data in
robj *o = lookupKeyRead(c->db, key);
// Write to cache
if (!o) addReply(c,reply);
return o;
}
stay getCommand Data found in function , And then call addReply Write the data to be returned to the client output buffer .

Data write back client

After executing the command above and writing to the buffer , You also need to fetch data from the buffer and return it to Client. For the process of writing data back to the client , In fact, it is also completed in the event cycle of the server .

 Insert picture description here

First Redis Will be in main Call in function aeSetBeforeSleepProc The function will write back to the function of the package beforeSleep Sign up to eventLoop In the middle ;
then Redis Calling aeMain Functions will judge when they cycle events beforesleep Is it set , If there is , Then it will be called ;
beforesleep Function will call handleClientsWithPendingWrites function , It will be called writeToClient Write data back from the buffer to the client ;

原网站

版权声明
本文为[Gegwu MMQ!!]所创,转载请带上原文链接,感谢
https://yzsam.com/2022/208/202207271727483534.html