In addition to Weibo, there is also WeChat
Please pay attention
WeChat public account
Shulou
2025-02-23 Update From: SLTechnology News&Howtos shulou NAV: SLTechnology News&Howtos > Internet Technology >
Share
Shulou(Shulou.com)06/02 Report--
In this issue, the editor will bring you about how to start and handle http requests in Nginx. The article is rich in content and analyzes and narrates it from a professional point of view. I hope you can get something after reading this article.
1. Nginx starts the process
Nginx is very large, it is difficult to read all the code in a short time, and I do not see a lot of time, so here is mainly from a macro point of view, to do an overall analysis of nginx.
In fact, if you start directly from the main function, you can actually understand most of it, but there are too many nginx callback functions. When you look at it, you suddenly come up with a callback function.
Therefore, it is necessary to use gdb for fixed-point debugging.
To use gdb, you first need to add the-g option when gcc compiles, as follows:
Open the nginx directory / auto/cc/conf file, then change the ngx_compile_opt= "- c" option and add-g, which is ngx_compile_opt= "- c-g"
Then run. / configure and make to compile and generate the executable file, in the file objs directory
After generating the executable file nginx, you can run it directly on the terminal. Nginx will load the default configuration file and run it as daemon.
After nginx is running, you can debug it through gdb
Open gdb as follows
Then, get the nginx process number through the pidof command, and you can attach, as follows:
Nginx starts a master process and a worker process by default, so the above command returns two process numbers, 8125 and 8126 on my host, the smaller is the master process and the larger is the worker process. Next, take a look at the master process.
In this way, you can debug the worker process of nginx directly, and you can view the function stack of the master process with the command bt.
After nginx is enabled, the first thing to start is the master process, starting with the main function
The main function mainly does some initialization operations, initializes the startup parameters, opens daemon, creates a new pid file, etc., and then calls the ngx_master_process_cycle function.
In the ngx_master_process_cycle function, the most important thing is to start the child process, then call the sigsuspend function, and the master process is blocked in the signal.
Therefore, the task of the master process is to start the child process and then manage the child process; how to manage it?
A signal, yes, is a signal; when the master process receives a signal, it passes the signal to the worker process, and the worker process processes it separately according to different signals.
So the question comes again, how does the master process signal to the worker process?
The pipe, yes, is the pipe. The principle is the same as memcache's MasterThread and worker thread communication mechanism, that is, each worker process has two file descriptors fd [0] and fd [1], one reader and one writer.
The worker process adds the reader to the epoll event listener. When the master process receives a signal, it writes a flag on the writing side of each worker process, and then the worker process triggers the read event, reads the flag, and does the corresponding operation according to the flag.
So nginx receives client requests and processes client requests, mainly in the worker process. Let's look at the worker process function stack.
Because the worker process is fork by the master process, the worker process contains the function stack of the master process; let's start directly with the # 5 function
The ngx_start_worker_processes function calls ngx_spawn_process to open the child process and sets the pipeline for communication between the master process and the worker process.
The ngx_spawn_process function mainly sets the communication pipeline between the master process and the worker process, such as non-blocking, etc., and then formally starts the child process through the fork function
The child process calls the callback function ngx_worker_process_cycle passed in through the parameters to formally cut into the child process part, and the parent process then sets the properties related to the worker process.
Ngx_worker_process_cycle starts by calling the ngx_worker_process_init function to initialize the worker process, including setting the process priority, the maximum file descriptor allowed by the worker process, setting blocking signals, initializing all modules, adding master processes and worker inter-process communication pipes to listening for readable events, and so on.
Then in an infinite loop, the function ngx_worker_process_cycle then calls ngx_process_events_and_timers to start the event listening loop
In the ngx_process_events_and_timers function, the first step is to acquire the lock. If the lock is acquired, listenfd can receive the client, otherwise listenfd cannot receive client events.
Then call the ngx_process_events function, which is the ngx_epoll_process_events function, to enable event listening
The ok,worker process is now ready to wait for the client to connect and request data.
In order to avoid panic and achieve worker process load balancing, every time there is a client connection, all worker processes will scramble for the lock first. If a worker process acquires the lock, it can receive client and client request events.
If the worker process does not scramble for the lock, only the client request event is executed.
two。 Important callback function settings
When the master process and worker process of nginx are turned on, the client can send the request; next, take a look at how nginx handles the request
When the client sends the request, the connection is first established through the tcp three-way handshake; when the connection is successfully established, the callback function of listenfd is executed, but which callback function of listenfd? This is actually very difficult for beginners to find listenfd callback functions.
The following is an analysis:
Callbacks like listenfd's and how modules fit together are almost all done during module initialization.
The callback function for listenfd is set when the event module is initialized or when some setting functions of the event module are called
After the client connects to the server, the callback function after the server receives the request is also set when the http module is initialized or when some setting functions of the module http module are called.
When the event module initializes, the ngx_event_process_init function is called. The most important code for this function is listed below:
In the for loop, iterate over each listening socket, and recv is the read event of the listenfd connection object. Here, set the callback function of the listenfd read event to the ngx_event_accept function, and then add each listenfd to the event listener and set it as a readable event.
Ok, when we look at the definitions of ngx_add_conn and ngx_add_event, it is as follows:
It shows that both ngx_add_conn and ngx_add_event are function pointers set in the structure ngx_event_actions structure.
In fact, this ngx_event_actions is the key to nginx cross-platform, because different platforms use different event listeners, resulting in different ngx_event_actions.
For example, linux uses epoll, so the ngx_event_actions structure is set when the epoll module loads, in the first half of the above code. Let's take a look at the epoll module actions.init function:
As you can see from the code, ngx_event_actions is set to ngx_epoll_module_ctx.actions, and then look at this structure:
Therefore, when ngx_add_conn and ngx_add_event are called, ngx_epoll_add_connection and ngx_epoll_add_event are called respectively
In this way, if this is the mac platform, then the event listener used is kqueue, so when ngx_add_event is called, ngx_kqueue_add_event is called.
If you use a poll listener, the call will be ngx_poll_add_event, and so on.
Next, we will analyze a very important callback function, that is, the callback function when sending a request after the client is connected to the client. Let's take a look at the listenfd callback function.
When the client connects to the server, the listenfd callback function first calls the accept function to receive the client request, and then gets an encapsulated client socket connection object from the object pool.
If you are currently using an epoll event listener, call ngx_add_conn (c) to place the event listener, and finally call the callback function of ngx_listening_t to further operate on the client connection
Ok, what is this ls- > handler (c)? When I looked at the code for the first time, I looked confused!
Remember what you said before? The connection between modules is almost always set when the module is initialized or when some setting functions of the module are called, so next, let's take a look at what the http module does during initialization.
The http module does not set ls- > handler (c) in the module initialization function, but executes the setting in the command function ngx_http_block when the "http" command is read
It's hidden deep enough. After four functions, I finally see the ls-handler setting function, that is, the ngx_http_init_connection function, and this function is in the http module, which is the entry function for client http request processing.
So far, we can know that after receiving the client, the server first encapsulates the client into a ngx_connection_t structure, and then gives it to the http module to execute the http request.
3. Nginx handles http requests
Nginx processing http requests is the most important and complex part of nginx. You can outline the execution process:
Read parse request line
Read parsing request header
Start with the most important part, that is, multi-stage processing
Nginx divides the request processing into 11 stages, that is, when the nginx reads the request line and the request header, the request is encapsulated in the structure ngx_http_request_t, and then the handler of each stage processes the request according to this ngx_http_request_t, such as rewriting uri, permission control, path lookup, generating content, logging, and so on.
Return the result to the client
Multi-stage processing is the most important part of the nginx module, because the third-party module is also registered here; for example, someone wrote a third-party module that uses nginx and memcache for page caching, and can also replace memcache with redis clusters, and so on.
And nginx multi-stage processing is somewhat similar to the middleware of python and golang web framework, the latter mainly uses decorator mode to encapsulate handler layer by layer, while nginx combines multi-stage handler in the form of array (linked list), and then executes it according to handler linked list.
Because the content of multi-stage is not fully understood, following the online tutorial, I wrote the simplest third-party module, which is used to set up fixed-point debugging and observe the execution process of http phase function. The steps are as follows:
Create a new directory thm (third mudole) under the nginx directory, create a new foo directory (foo module), and then create a new ngx_http_foo_module.c under the foo directory
Then create a new configuration file config in the foo directory as well
In this way, the simplest third-party module is written.
The above two functions are easy to understand. One is the initialization function, which registers the handler of the module to some stage.
This example is in the phase NGX_HTTP_CONTENT_PHASE, and then when the program reaches the above stage, the foo module can be executed; finally, it can be recompiled into an executable file.
Next, take a look at the http execution process using gdb and set the fixed point to
In a brief description of the above functions, the version I read is different from the running version, so the above is for reference only:
When a client sends a tcp connection request, ngx_epoll_process_events returns a listenfd readable event, calls the ngx_event_accept function to receive the client request, then encapsulates the request into a ngx_connection_t structure, and finally calls the ngx_http_init_connection function to enter http processing
In the new version of nginx, we do not see ngx_http_wait_request_handler, but change it to the ngx_http_init_connection (ngx_connection_t * c) function, and then call the ngx_http_init_request function inside this function to initialize the request structure ngx_http_request_t and call the ngx_http_process_request_line function
The ngx_http_process_request_line function first calls the ngx_http_read_request_header function to read the request line into the cache, then calls the ngx_http_parse_request_line function to parse the request line information, and finally calls ngx_http_process_request_header to process the request header.
Inside the function ngx_http_process_request_header, the function ngx_http_read_request_header is called to read the request header, then the ngx_http_parse_header_line function is called to parse the request header, then the ngx_http_process_request_header function is called to verify the request header, and finally the ngx_http_process_request function is called to process the request.
The ngx_http_handler (ngx_http_request_t r) function is called inside the ngx_http_process_request function, and the function ngx_http_core_run_phases is called inside the ngx_http_handler (ngx_http_request_t r) function for multi-stage processing.
Let's take a look at the multistage processing function ngx_http_core_run_phases
Http multi-stage processing, each phase may correspond to a handler, or it may correspond to multiple handler, and each phase corresponds to the same checker.
So in the above while loop, iterate through all the http module handler, and then make the corresponding processing in the handler function according to the request structure ngx_http_request_t.
From the above gdb debugging results, you can see that the checker function of the NGX_HTTP_CONTENT_PHASE phase is ngx_http_core_content_phase, and then execute the handler (ngx_http_foo_handler) of the foo module inside the checker function.
Wait until the multi-phase processing is over, and then return the response to the client.
This is how to start and process http requests in the Nginx shared by the editor. If you happen to have similar doubts, please refer to the above analysis to understand. If you want to know more about it, you are welcome to follow the industry information channel.
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.