comparison src/event/ngx_event_accept.c @ 7992:e2d07e4ec636

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.
author Maxim Dounin <mdounin@mdounin.ru>
date Thu, 30 Dec 2021 01:08:46 +0300
parents fdc3d40979b0
children
comparison
equal deleted inserted replaced
7991:57581198e51e 7992:e2d07e4ec636
9 #include <ngx_core.h> 9 #include <ngx_core.h>
10 #include <ngx_event.h> 10 #include <ngx_event.h>
11 11
12 12
13 static ngx_int_t ngx_disable_accept_events(ngx_cycle_t *cycle, ngx_uint_t all); 13 static ngx_int_t ngx_disable_accept_events(ngx_cycle_t *cycle, ngx_uint_t all);
14 #if (NGX_HAVE_EPOLLEXCLUSIVE)
15 static void ngx_reorder_accept_events(ngx_listening_t *ls);
16 #endif
14 static void ngx_close_accepted_connection(ngx_connection_t *c); 17 static void ngx_close_accepted_connection(ngx_connection_t *c);
15 18
16 19
17 void 20 void
18 ngx_event_accept(ngx_event_t *ev) 21 ngx_event_accept(ngx_event_t *ev)
312 if (ngx_event_flags & NGX_USE_KQUEUE_EVENT) { 315 if (ngx_event_flags & NGX_USE_KQUEUE_EVENT) {
313 ev->available--; 316 ev->available--;
314 } 317 }
315 318
316 } while (ev->available); 319 } while (ev->available);
320
321 #if (NGX_HAVE_EPOLLEXCLUSIVE)
322 ngx_reorder_accept_events(ls);
323 #endif
317 } 324 }
318 325
319 326
320 ngx_int_t 327 ngx_int_t
321 ngx_trylock_accept_mutex(ngx_cycle_t *cycle) 328 ngx_trylock_accept_mutex(ngx_cycle_t *cycle)
416 } 423 }
417 } 424 }
418 425
419 return NGX_OK; 426 return NGX_OK;
420 } 427 }
428
429
430 #if (NGX_HAVE_EPOLLEXCLUSIVE)
431
432 static void
433 ngx_reorder_accept_events(ngx_listening_t *ls)
434 {
435 ngx_connection_t *c;
436
437 /*
438 * Linux with EPOLLEXCLUSIVE usually notifies only the process which
439 * was first to add the listening socket to the epoll instance. As
440 * a result most of the connections are handled by the first worker
441 * process. To fix this, we re-add the socket periodically, so other
442 * workers will get a chance to accept connections.
443 */
444
445 if (!ngx_use_exclusive_accept) {
446 return;
447 }
448
449 #if (NGX_HAVE_REUSEPORT)
450
451 if (ls->reuseport) {
452 return;
453 }
454
455 #endif
456
457 c = ls->connection;
458
459 if (c->requests++ % 16 != 0
460 && ngx_accept_disabled <= 0)
461 {
462 return;
463 }
464
465 if (ngx_del_event(c->read, NGX_READ_EVENT, NGX_DISABLE_EVENT)
466 == NGX_ERROR)
467 {
468 return;
469 }
470
471 if (ngx_add_event(c->read, NGX_READ_EVENT, NGX_EXCLUSIVE_EVENT)
472 == NGX_ERROR)
473 {
474 return;
475 }
476 }
477
478 #endif
421 479
422 480
423 static void 481 static void
424 ngx_close_accepted_connection(ngx_connection_t *c) 482 ngx_close_accepted_connection(ngx_connection_t *c)
425 { 483 {