Events: fixed balancing between workers with EPOLLEXCLUSIVE.
Linux with EPOLLEXCLUSIVE usually notifies only the process which was first to add the listening socket to the epoll instance. As a result most of the connections are handled by the first worker process (ticket #2285). To fix this, we re-add the socket periodically, so other workers will get a chance to accept connections.
This commit is contained in:
parent
7d591be08f
commit
d29c0a2728
3 changed files with 64 additions and 0 deletions
|
@ -55,6 +55,7 @@ ngx_uint_t ngx_accept_events;
|
|||
ngx_uint_t ngx_accept_mutex_held;
|
||||
ngx_msec_t ngx_accept_mutex_delay;
|
||||
ngx_int_t ngx_accept_disabled;
|
||||
ngx_uint_t ngx_use_exclusive_accept;
|
||||
|
||||
|
||||
#if (NGX_STAT_STUB)
|
||||
|
@ -644,6 +645,8 @@ ngx_event_process_init(ngx_cycle_t *cycle)
|
|||
|
||||
#endif
|
||||
|
||||
ngx_use_exclusive_accept = 0;
|
||||
|
||||
ngx_queue_init(&ngx_posted_accept_events);
|
||||
ngx_queue_init(&ngx_posted_next_events);
|
||||
ngx_queue_init(&ngx_posted_events);
|
||||
|
@ -889,6 +892,8 @@ ngx_event_process_init(ngx_cycle_t *cycle)
|
|||
if ((ngx_event_flags & NGX_USE_EPOLL_EVENT)
|
||||
&& ccf->worker_processes > 1)
|
||||
{
|
||||
ngx_use_exclusive_accept = 1;
|
||||
|
||||
if (ngx_add_event(rev, NGX_READ_EVENT, NGX_EXCLUSIVE_EVENT)
|
||||
== NGX_ERROR)
|
||||
{
|
||||
|
|
|
@ -462,6 +462,7 @@ extern ngx_uint_t ngx_accept_events;
|
|||
extern ngx_uint_t ngx_accept_mutex_held;
|
||||
extern ngx_msec_t ngx_accept_mutex_delay;
|
||||
extern ngx_int_t ngx_accept_disabled;
|
||||
extern ngx_uint_t ngx_use_exclusive_accept;
|
||||
|
||||
|
||||
#if (NGX_STAT_STUB)
|
||||
|
|
|
@ -11,6 +11,9 @@
|
|||
|
||||
|
||||
static ngx_int_t ngx_disable_accept_events(ngx_cycle_t *cycle, ngx_uint_t all);
|
||||
#if (NGX_HAVE_EPOLLEXCLUSIVE)
|
||||
static void ngx_reorder_accept_events(ngx_listening_t *ls);
|
||||
#endif
|
||||
static void ngx_close_accepted_connection(ngx_connection_t *c);
|
||||
|
||||
|
||||
|
@ -314,6 +317,10 @@ ngx_event_accept(ngx_event_t *ev)
|
|||
}
|
||||
|
||||
} while (ev->available);
|
||||
|
||||
#if (NGX_HAVE_EPOLLEXCLUSIVE)
|
||||
ngx_reorder_accept_events(ls);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
|
@ -420,6 +427,57 @@ ngx_disable_accept_events(ngx_cycle_t *cycle, ngx_uint_t all)
|
|||
}
|
||||
|
||||
|
||||
#if (NGX_HAVE_EPOLLEXCLUSIVE)
|
||||
|
||||
static void
|
||||
ngx_reorder_accept_events(ngx_listening_t *ls)
|
||||
{
|
||||
ngx_connection_t *c;
|
||||
|
||||
/*
|
||||
* Linux with EPOLLEXCLUSIVE usually notifies only the process which
|
||||
* was first to add the listening socket to the epoll instance. As
|
||||
* a result most of the connections are handled by the first worker
|
||||
* process. To fix this, we re-add the socket periodically, so other
|
||||
* workers will get a chance to accept connections.
|
||||
*/
|
||||
|
||||
if (!ngx_use_exclusive_accept) {
|
||||
return;
|
||||
}
|
||||
|
||||
#if (NGX_HAVE_REUSEPORT)
|
||||
|
||||
if (ls->reuseport) {
|
||||
return;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
c = ls->connection;
|
||||
|
||||
if (c->requests++ % 16 != 0
|
||||
&& ngx_accept_disabled <= 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (ngx_del_event(c->read, NGX_READ_EVENT, NGX_DISABLE_EVENT)
|
||||
== NGX_ERROR)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (ngx_add_event(c->read, NGX_READ_EVENT, NGX_EXCLUSIVE_EVENT)
|
||||
== NGX_ERROR)
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
static void
|
||||
ngx_close_accepted_connection(ngx_connection_t *c)
|
||||
{
|
||||
|
|
Loading…
Reference in a new issue