Nginx Source Analysis-Main process-multi-process cluster and process load balancing processing

Source: Internet
Author: User
Tags epoll mutex nginx server

Therewas a panic about the socket's accept before the Linux 2.6 release. The later version has solved the problem.

Surprise group refers to the phenomenon that when multiple processes / threads are waiting for the same resource, all processes / threads compete for resources whenever resources are available.

Nginx uses a multi-process mode. Assuming that the Linux system is the 2.6 version, when there is a client to connect to the Nginx server, Nginx N process will listen to the socket accept, if all n processes are the client socket connection is monitored, it will cause the competition of resources and even data confusion . we want to make sure that a link is handled on one of the nginx processes, including the accept and Read/write events.


The key points of nginx to solve the load balance of surprise group and process

1. Nginx n process will scramble for file lock, when only get the file lock process, can handle the event of accept .

2. The process of not getting the file lock can only handle the read event of the current connection object

3. When the total number of connection connections for a single process reaches the total of 7/8 , no new Accpet events are received.

4. If the process to get the lock can quickly finish Accpet, and not get the lock has been waiting (waiting for delay:ngx_accept_mutex_delay), easy to cause the process busy busy, empty very empty


Specific implementation of the Ngx_process_events_and_timers process event dispatcher

This method is the core function of the process implementation. Main functions: Event distribution, surprise group processing, simple load balancing.


Load Balancing:

1. When the event configuration is initialized, a global variable is set: ngx_accept_disabled = NGX_CYCLE->CONNECTION_N/8-ngx_cycle->free_connection_n;

2. When ngx_accept_disabled is positive, when connection reaches 7/8 of the total number of connections, the new connection accept event is no longer processed and only the read event of the current connection is processed


Surprise group Treatment:

1. Through the Ngx_trylock_accept_mutex scramble for file locks, to get the file lock, you can handle the Accept event.

2. Ngx_accept_mutex_held is a flag to get the lock, when the lock is taken, flags will be set to ngx_post_events, this flag will be in the event handler function ngx_ Process_events All events (accept and read) into the corresponding ngx_posted_accept_events and ngx_posted_events queues Deferred processing .

3. When you do not get the lock, call the event handler function ngx_process_events , you can explicitly read the event, so you can call the event Ev->handler method callback processing.

4. To get the lock process, the next priority is to handle the Accept event on the ngx_posted_accept_events queue, processing the function:ngx_event_process_posted

5. After the Accept event is processed, the file lock is released

6. Next process the Read event on the ngx_posted_events queue, processing function:ngx_event_process_posted


/** * Process Event Dispatcher */void ngx_process_events_and_timers (ngx_cycle_t *cycle) {ngx_uint_t flags;ngx_msec_t timer, delta;if (NGX _timer_resolution) {timer = Ngx_timer_infinite;flags = 0;} else {timer = Ngx_event_find_timer (); flags = ngx_update_time;# if (NGX_WIN32)/* Handle signals from master in case of network inactivity */if (timer = = Ngx_timer_infinite | | Timer > {timer = 500;} #endif}/** * Ngx_use_accept_mutex variable represents whether the accept mutex is used by default and can be switched off by Accept_mutex off; * The function of the accept mutex is to avoid the cluster, while achieving load balancing */if (Ngx_use_accept_mutex) {/** * ngx_accept_disabled = NGX_CYCLE->CONNECTION_N/8-Ngx_cycle->free_connection_ N * When connection reaches 7/8 of the total number of connections, the new connection accept event is no longer processed, only the read event of the current connection is processed * This is a relatively simple load balancing method */if (ngx_accept_disabled > 0) {ngx_ accept_disabled--;} else {/* get lock Failed */if (Ngx_trylock_accept_mutex (cycle) = = Ngx_error) {return;} /* Get the Lock */if (Ngx_accept_mutex_held) {/** * adds tag ngx_post_events to the flags as a parameter of the core function ngx_process_events of the processing time, All events in this function will be deferred for processing. * The Accept event is put into the ngx_posted_accept_events chainTable, * Epollin|epollout Ordinary events are placed in the ngx_posted_events linked list **/flags |= ngx_post_events;} else {/** * 1. Acquiring a lock failure means that neither the current worker process can attempt to grab the lock frequently, nor let it go through too long an event to grab the lock * 2. The timer_resolution time accuracy is turned on, and you need to let Ngx_process_ The change method waits at least ngx_accept_mutex_delay milliseconds to try to grab the lock * 3 when there is no new event. When there is no time accuracy, the timer is set to Ngx_accept_mutex_delay milliseconds * 4 If the time-out distance for the most recent timer event is now more than ngx_accept_mutex_delay milliseconds. You cannot allow the Ngx_process_change method to wait longer than ngx_accept_mutex_delay when there are no new events, which affects the entire load balancing mechanism * 5. If the process to get the lock can quickly finish Accpet, and not get the lock has been waiting, easy to cause the process busy busy, empty very empty */if (timer = = ngx_timer_infinite| | timer > Ngx_accept_mutex_ Delay) {timer = Ngx_accept_mutex_delay;}}}} Delta = ngx_current_msec;/** * Event Dispatch function * 1. When the lock is flags=ngx_post_events, the event is not processed directly, and the accept event is placed in the Ngx_posted_accept_events,read event to ngx_posted_events queue * 2. When the lock is not taken, all that is processed is the read event, and the callback function is processed directly * parameters: Timer-epoll_wait Timeout time (ngx_accept_mutex_delay-delay lock Event Ngx_timer_ infinite-normal epollwait wait event) */(void) ngx_process_events (cycle, timer, flags);d Elta = Ngx_current_msec-delta;ngx_log_ DEBUG1 (ngx_log_debug_event, Cycle->log, 0, "tImer Delta:%M ", delta);/** * 1. Ngx_posted_accept_events is an event queue, staging Epoll from the listener interface wait to the Accept event * 2. This method is to loop through the Accpet event */ngx_event_process_posted (cycle, &ngx_posted_accept_events) on the Accpet event queue;/** * If you get the lock, After the Accept event is processed, the lock */if (Ngx_accept_mutex_held) {Ngx_shmtx_unlock (&ngx_accept_mutex) is released;} if (delta) {ngx_event_expire_timers ();} /** * * *. Normal events will be stored in the ngx_posted_events queue. This method is to loop through the Read event queue on the Read event */ngx_event_process_posted (cycle, &ngx_posted_events);}
Ngx_trylock_accept_mutex Get Accept Lock

1. Ngx_accept_mutex_held is the global variable that gets the unique identity of the lock.

2. When you get the lock, call ngx_enable_accept_events and add the new connection to the event

3. If you do not get the lock, call ngx_disable_accept_events.

/** * Get accept Lock */ngx_int_t Ngx_trylock_accept_mutex (ngx_cycle_t *cycle) {/** * get lock */if (Ngx_shmtx_trylock (&ngx_ Accept_mutex) {ngx_log_debug0 (ngx_log_debug_event, Cycle->log, 0, "accept mutex locked");/* come in several times to determine if you have got the lock */if ( Ngx_accept_mutex_held && ngx_accept_events = = 0) {return NGX_OK;} /* Call ngx_enable_accept_events, turn on the Listen Accpet event */if (ngx_enable_accept_events (cycle) = = Ngx_error) {Ngx_shmtx_unlock ( &ngx_accept_mutex); return ngx_error;} ngx_accept_events = 0;ngx_accept_mutex_held = 1;return ngx_ok;} NGX_LOG_DEBUG1 (ngx_log_debug_event, Cycle->log, 0, "Accept Mutex lock failed:%ui", Ngx_accept_mutex_held);/** * Did not get the lock, but ngx_accept_mutex_held=1 */if (Ngx_accept_mutex_held) {/* did not get the lock, call ngx_disable_accept_events, delete Accpet event */if (Ngx_disable_accept_events (cycle, 0) = = ngx_error) {return ngx_error;} Ngx_accept_mutex_held = 0;} return NGX_OK;}

Ngx_enable_accept_events and Ngx_disable_accept_events

/** * Open the Listen on the Accept event and add the Accept event to the event */static ngx_int_t ngx_enable_accept_events (ngx_cycle_t *cycle) {ngx_uint_t i; ngx_listening_t *ls;ngx_connection_t *c;ls = cycle->listening.elts;for (i = 0; i < cycle->listening.nelts; i++) { c = ls[i].connection;if (c = = NULL | | c->read->active) {continue;} if (Ngx_add_event (C->read, ngx_read_event, 0) = = ngx_error) {return ngx_error;}} return NGX_OK;} /** * Closes the listen for accept event * and removes the Accept event from the event */static ngx_int_t ngx_disable_accept_events (ngx_cycle_t *cycle, ngx_uint_t All) {ngx_uint_t i;ngx_listening_t *ls;ngx_connection_t *c;ls = cycle->listening.elts;for (i = 0; i < cycle->list Ening.nelts; i++) {c = ls[i].connection;/* if c->read->active, then is an active connection, already in use */if (c = = NULL | |!c->read->active) {Contin UE;} #if (ngx_have_reuseport)/* * Do not disable accept on worker's own sockets * when disabling accept events due to accept Mu Tex */if (Ls[i].reuseport &&!all) {continue;} #endif/* Delete event */if (Ngx_del_event (C->read, ngx_read_event,ngx_disable_event) = = Ngx_error) {return ngx_error;}} return NGX_OK;}
Ngx_event_process_posted Event Queue Processing

Callback handling of Accept/read events on the ngx_posted_accept_events or ngx_posted_events queues.

/** * Processing Event queue * */void ngx_event_process_posted (ngx_cycle_t *cycle, ngx_queue_t *posted) {ngx_queue_t *q;ngx_event_t *ev;w Hile (!ngx_queue_empty (posted)) {q = Ngx_queue_head (posted); ev = Ngx_queue_data (q, ngx_event_t, queue); NGX_LOG_DEBUG1 ( Ngx_log_debug_event, Cycle->log, 0, "posted event%p", Ev), ngx_delete_posted_event (EV);/* Event callback function */ev->handler ( EV);}}

Core processing functions of the Ngx_process_events event

This method, we mainly look at the ngx_epoll_process_events method under the Epoll model (NGX_EPOLL_MODULE.C)

1. If a lock is reached, the Accpet/read event is placed on the queue for deferred processing.

2. Processes that do not grab locks are processed directly by the Read event that handles the current connection.

        /* Read Event Epollin */        if ((Revents & Epollin) && rev->active) {#if (ngx_have_epollrdhup)            if (Revents & Amp Epollrdhup) {                rev->pending_eof = 1;            }            rev->available = 1; #endif            rev->ready = 1;            /* If the event grabs the lock, put the event queue *            /if (Flags & ngx_post_events) {                queue = rev->accept? &ngx_posted_accept_events< c10/>: &ngx_posted_events;                Ngx_post_event (rev, queue);            } else {            /* does not grab the lock, the read event is processed directly *                /Rev->handler (rev);}        }


At the beginning of the next section, we will enter the Nginx event module.


Nginx source Code Analysis-Main process-multi-process cluster and process load balancing processing

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.