comparison src/http/modules/ngx_http_limit_req_module.c @ 7399:d6ca744c727e

Limit req: "delay=" parameter. This parameter specifies an additional "soft" burst limit at which requests become delayed (but not yet rejected as it happens if "burst=" limit is exceeded). Defaults to 0, i.e., all excess requests are delayed. Originally inspired by Vladislav Shabanov (http://mailman.nginx.org/pipermail/nginx-devel/2016-April/008126.html). Further improved based on a patch by Peter Shchuchkin (http://mailman.nginx.org/pipermail/nginx-devel/2018-October/011522.html).
author Maxim Dounin <mdounin@mdounin.ru>
date Wed, 21 Nov 2018 18:56:50 +0300
parents bca4dad0d3cb
children 2db68852d6a0
comparison
equal deleted inserted replaced
7398:bca4dad0d3cb 7399:d6ca744c727e
42 42
43 typedef struct { 43 typedef struct {
44 ngx_shm_zone_t *shm_zone; 44 ngx_shm_zone_t *shm_zone;
45 /* integer value, 1 corresponds to 0.001 r/s */ 45 /* integer value, 1 corresponds to 0.001 r/s */
46 ngx_uint_t burst; 46 ngx_uint_t burst;
47 ngx_uint_t nodelay; /* unsigned nodelay:1 */ 47 ngx_uint_t delay;
48 } ngx_http_limit_req_limit_t; 48 } ngx_http_limit_req_limit_t;
49 49
50 50
51 typedef struct { 51 typedef struct {
52 ngx_array_t limits; 52 ngx_array_t limits;
497 ngx_http_limit_req_ctx_t *ctx; 497 ngx_http_limit_req_ctx_t *ctx;
498 ngx_http_limit_req_node_t *lr; 498 ngx_http_limit_req_node_t *lr;
499 499
500 excess = *ep; 500 excess = *ep;
501 501
502 if (excess == 0 || (*limit)->nodelay) { 502 if ((ngx_uint_t) excess <= (*limit)->delay) {
503 max_delay = 0; 503 max_delay = 0;
504 504
505 } else { 505 } else {
506 ctx = (*limit)->shm_zone->data; 506 ctx = (*limit)->shm_zone->data;
507 max_delay = excess * 1000 / ctx->rate; 507 max_delay = (excess - (*limit)->delay) * 1000 / ctx->rate;
508 } 508 }
509 509
510 while (n--) { 510 while (n--) {
511 ctx = limits[n].shm_zone->data; 511 ctx = limits[n].shm_zone->data;
512 lr = ctx->node; 512 lr = ctx->node;
542 542
543 ngx_shmtx_unlock(&ctx->shpool->mutex); 543 ngx_shmtx_unlock(&ctx->shpool->mutex);
544 544
545 ctx->node = NULL; 545 ctx->node = NULL;
546 546
547 if (limits[n].nodelay) { 547 if ((ngx_uint_t) excess <= limits[n].delay) {
548 continue; 548 continue;
549 } 549 }
550 550
551 delay = excess * 1000 / ctx->rate; 551 delay = (excess - limits[n].delay) * 1000 / ctx->rate;
552 552
553 if (delay > max_delay) { 553 if (delay > max_delay) {
554 max_delay = delay; 554 max_delay = delay;
555 *ep = excess; 555 *ep = excess;
556 *limit = &limits[n]; 556 *limit = &limits[n];
873 static char * 873 static char *
874 ngx_http_limit_req(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) 874 ngx_http_limit_req(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
875 { 875 {
876 ngx_http_limit_req_conf_t *lrcf = conf; 876 ngx_http_limit_req_conf_t *lrcf = conf;
877 877
878 ngx_int_t burst; 878 ngx_int_t burst, delay;
879 ngx_str_t *value, s; 879 ngx_str_t *value, s;
880 ngx_uint_t i, nodelay; 880 ngx_uint_t i;
881 ngx_shm_zone_t *shm_zone; 881 ngx_shm_zone_t *shm_zone;
882 ngx_http_limit_req_limit_t *limit, *limits; 882 ngx_http_limit_req_limit_t *limit, *limits;
883 883
884 value = cf->args->elts; 884 value = cf->args->elts;
885 885
886 shm_zone = NULL; 886 shm_zone = NULL;
887 burst = 0; 887 burst = 0;
888 nodelay = 0; 888 delay = 0;
889 889
890 for (i = 1; i < cf->args->nelts; i++) { 890 for (i = 1; i < cf->args->nelts; i++) {
891 891
892 if (ngx_strncmp(value[i].data, "zone=", 5) == 0) { 892 if (ngx_strncmp(value[i].data, "zone=", 5) == 0) {
893 893
913 } 913 }
914 914
915 continue; 915 continue;
916 } 916 }
917 917
918 if (ngx_strncmp(value[i].data, "delay=", 6) == 0) {
919
920 delay = ngx_atoi(value[i].data + 6, value[i].len - 6);
921 if (delay <= 0) {
922 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
923 "invalid delay value \"%V\"", &value[i]);
924 return NGX_CONF_ERROR;
925 }
926
927 continue;
928 }
929
918 if (ngx_strcmp(value[i].data, "nodelay") == 0) { 930 if (ngx_strcmp(value[i].data, "nodelay") == 0) {
919 nodelay = 1; 931 delay = NGX_MAX_INT_T_VALUE / 1000;
920 continue; 932 continue;
921 } 933 }
922 934
923 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, 935 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
924 "invalid parameter \"%V\"", &value[i]); 936 "invalid parameter \"%V\"", &value[i]);
954 return NGX_CONF_ERROR; 966 return NGX_CONF_ERROR;
955 } 967 }
956 968
957 limit->shm_zone = shm_zone; 969 limit->shm_zone = shm_zone;
958 limit->burst = burst * 1000; 970 limit->burst = burst * 1000;
959 limit->nodelay = nodelay; 971 limit->delay = delay * 1000;
960 972
961 return NGX_CONF_OK; 973 return NGX_CONF_OK;
962 } 974 }
963 975
964 976