Mercurial > hg > nginx
comparison src/http/modules/ngx_http_limit_req_module.c @ 7281:bd6563e81cea
Limit req: improved handling of negative times.
Negative times can appear since workers only update time on an event
loop iteration start. If a worker was blocked for a long time during
an event loop iteration, it is possible that another worker already
updated the time stored in the node. As such, time since last update
of the node (ms) will be negative.
Previous code used ngx_abs(ms) in the calculations. That is, negative
times were effectively treated as positive ones. As a result, it was
not possible to maintain high request rates, where the same node can be
updated multiple times from during an event loop iteration.
In particular, this affected setups with many SSL handshakes, see
http://mailman.nginx.org/pipermail/nginx/2018-May/056291.html.
Fix is to only update the last update time stored in the node if the
new time is larger than previously stored one. If a future time is
stored in the node, we preserve this time as is.
To prevent breaking things on platforms without monotonic time available
if system time is updated backwards, a safety limit of 60 seconds is
used. If the time stored in the node is more than 60 seconds in the future,
we assume that the time was changed backwards and update lr->last
to the current time.
author | Maxim Dounin <mdounin@mdounin.ru> |
---|---|
date | Wed, 30 May 2018 15:40:34 +0300 |
parents | 903fb1ddc07f |
children | bca4dad0d3cb |
comparison
equal
deleted
inserted
replaced
7280:76e7e20cda05 | 7281:bd6563e81cea |
---|---|
397 ngx_queue_remove(&lr->queue); | 397 ngx_queue_remove(&lr->queue); |
398 ngx_queue_insert_head(&ctx->sh->queue, &lr->queue); | 398 ngx_queue_insert_head(&ctx->sh->queue, &lr->queue); |
399 | 399 |
400 ms = (ngx_msec_int_t) (now - lr->last); | 400 ms = (ngx_msec_int_t) (now - lr->last); |
401 | 401 |
402 excess = lr->excess - ctx->rate * ngx_abs(ms) / 1000 + 1000; | 402 if (ms < -60000) { |
403 ms = 1; | |
404 | |
405 } else if (ms < 0) { | |
406 ms = 0; | |
407 } | |
408 | |
409 excess = lr->excess - ctx->rate * ms / 1000 + 1000; | |
403 | 410 |
404 if (excess < 0) { | 411 if (excess < 0) { |
405 excess = 0; | 412 excess = 0; |
406 } | 413 } |
407 | 414 |
411 return NGX_BUSY; | 418 return NGX_BUSY; |
412 } | 419 } |
413 | 420 |
414 if (account) { | 421 if (account) { |
415 lr->excess = excess; | 422 lr->excess = excess; |
416 lr->last = now; | 423 |
424 if (ms) { | |
425 lr->last = now; | |
426 } | |
427 | |
417 return NGX_OK; | 428 return NGX_OK; |
418 } | 429 } |
419 | 430 |
420 lr->count++; | 431 lr->count++; |
421 | 432 |
507 ngx_shmtx_lock(&ctx->shpool->mutex); | 518 ngx_shmtx_lock(&ctx->shpool->mutex); |
508 | 519 |
509 now = ngx_current_msec; | 520 now = ngx_current_msec; |
510 ms = (ngx_msec_int_t) (now - lr->last); | 521 ms = (ngx_msec_int_t) (now - lr->last); |
511 | 522 |
512 excess = lr->excess - ctx->rate * ngx_abs(ms) / 1000 + 1000; | 523 if (ms < -60000) { |
524 ms = 1; | |
525 | |
526 } else if (ms < 0) { | |
527 ms = 0; | |
528 } | |
529 | |
530 excess = lr->excess - ctx->rate * ms / 1000 + 1000; | |
513 | 531 |
514 if (excess < 0) { | 532 if (excess < 0) { |
515 excess = 0; | 533 excess = 0; |
516 } | 534 } |
517 | 535 |
518 lr->last = now; | 536 if (ms) { |
537 lr->last = now; | |
538 } | |
539 | |
519 lr->excess = excess; | 540 lr->excess = excess; |
520 lr->count--; | 541 lr->count--; |
521 | 542 |
522 ngx_shmtx_unlock(&ctx->shpool->mutex); | 543 ngx_shmtx_unlock(&ctx->shpool->mutex); |
523 | 544 |