Chinaunix首页 | 论坛 | 博客
  • 博客访问: 1898014
  • 博文数量: 211
  • 博客积分: 464
  • 博客等级: 下士
  • 技术积分: 3794
  • 用 户 组: 普通用户
  • 注册时间: 2011-01-24 18:25
个人简介

阿弥陀佛

文章分类

全部博文(211)

文章存档

2020年(2)

2019年(3)

2018年(5)

2017年(6)

2016年(10)

2015年(9)

2014年(73)

2013年(90)

2012年(13)

分类: 服务器与存储

2014-02-22 22:52:01

ngx_http_limit_req 模块的作用是限制request的接收的速率。
配置项分为两种,一种是对于全局的设置。
在http域内设置limit_req_zone内存区域。
 limit_req_zone $binary_remote_addr zone=one:64K rate=1r/s;
这里使用binary_remote_addr的意义在于可以有效地节省内存,一个binary_remote_addr是定长的,长度为64B。1m的req_zone 可以容纳1600个不同的客户端的地址。
这样就可以更有效地使用内存。
当用户发送到nginx的请求过快的时候,nginx就会延迟这些请求的处理。保证在rate范围内。
在location字段使用如下配置可以实现对某个location的限流,使用非常灵活。如果不在任何一个location里面写,那么就没有起到限流的作用。
  limit_req zone=one burst=1;

值得注意的是限流的zone的大小必须要超过8KB,如果太小,在解析的时候,nginx就会报错。
1.负责分析conf文件中的limit_req_zone相应的字段。
static char *
ngx_http_limit_req_zone(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)

根据配置文件生成的req_zone是通过共享内存实现的。
以下是使用limit_req模块的调用栈。


ngx_http_init_phase_handlers 这个函数是为各个阶段挂载handler函数。
ngx_http_core_run_phases这个函数会调用各个阶段的处理函数,到不同的阶段,每个阶段又有自己的不同的处理函数:

每个模块都有自己的模块的相应的信息,用户关于这个模块的配置信息在ngx_http_limit_req_conf_t中,ngx_http_get_module_loc_conf可以获得这个结构体。

点击(此处)折叠或打开

  1. static ngx_int_t
  2. ngx_http_limit_req_handler(ngx_http_request_t *r)
  3. {
  4.     size_t len, n;
  5.     uint32_t hash;
  6.     ngx_int_t rc;
  7.     ngx_uint_t excess;
  8.     ngx_time_t *tp;
  9.     ngx_rbtree_node_t *node;
  10.     ngx_http_variable_value_t *vv;
  11.     ngx_http_limit_req_ctx_t *ctx;
  12.     ngx_http_limit_req_node_t *lr;
  13.     ngx_http_limit_req_conf_t *lrcf;

  14.     if (r->main->limit_req_set) {
  15.         return NGX_DECLINED;
  16.     }

  17.     lrcf = ngx_http_get_module_loc_conf(r, ngx_http_limit_req_module); 获得该模块的location的配置信息

  18.     if (lrcf->shm_zone == NULL) {
  19.         return NGX_DECLINED;
  20.     }

  21.     ctx = lrcf->shm_zone->data;设置的共享内存zone

  22.     vv = ngx_http_get_indexed_variable(r, ctx->index);

  23.     if (vv == NULL || vv->not_found) {
  24.         return NGX_DECLINED;
  25.     }

  26.     len = vv->len;

  27.     if (len == 0) {
  28.         return NGX_DECLINED;
  29.     }

  30.     if (len > 65535) {
  31.         ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
  32.                       "the value of the \"%V\" variable "
  33.                       "is more than 65535 bytes: \"%v\"",
  34.                       &ctx->var, vv);
  35.         return NGX_DECLINED;
  36.     }

  37.     r->main->limit_req_set = 1;

  38.     hash = ngx_crc32_short(vv->data, len);通过对数据进行hash映射。

  39.     ngx_shmtx_lock(&ctx->shpool->mutex);

  40.     ngx_http_limit_req_expire(ctx, 1);替换掉队列和红黑树当中的不符合条件的请求。

  41.     rc = ngx_http_limit_req_lookup(lrcf, hash, vv->data, len, &excess);

  42.     ngx_log_debug3(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
  43.                    "limit_req: %i %ui.%03ui", rc, excess / 1000, excess % 1000);

  44.     if (rc == NGX_DECLINED) {

  45.         n = offsetof(ngx_rbtree_node_t, color)
  46.             + offsetof(ngx_http_limit_req_node_t, data)
  47.             + len;

  48.         node = ngx_slab_alloc_locked(ctx->shpool, n);
  49.         if (node == NULL) {

  50.             ngx_http_limit_req_expire(ctx, 0);

  51.             node = ngx_slab_alloc_locked(ctx->shpool, n);
  52.             if (node == NULL) {
  53.                 ngx_shmtx_unlock(&ctx->shpool->mutex);
  54.                 return NGX_HTTP_SERVICE_UNAVAILABLE;
  55.             }
  56.         }

  57.         lr = (ngx_http_limit_req_node_t *) &node->color;

  58.         node->key = hash;
  59.         lr->len = (u_char) len;

  60.         tp = ngx_timeofday();
  61.         lr->last = (ngx_msec_t) (tp->sec * 1000 + tp->msec);

  62.         lr->excess = 0;
  63.         ngx_memcpy(lr->data, vv->data, len);

  64.         ngx_rbtree_insert(&ctx->sh->rbtree, node);将这个新的请求插入到该模块的红黑树当中。

  65.         ngx_queue_insert_head(&ctx->sh->queue, &lr->queue);将这个请求插入到FIFO队列当中。

  66.         ngx_shmtx_unlock(&ctx->shpool->mutex);

  67.         return NGX_DECLINED;
  68.     }

  69.     ngx_shmtx_unlock(&ctx->shpool->mutex);

  70.     if (rc == NGX_OK) {
  71.         return NGX_DECLINED;
  72.     }

  73.     if (rc == NGX_BUSY) {
  74.         ngx_log_error(lrcf->limit_log_level, r->connection->log, 0,
  75.                       "limiting requests, excess: %ui.%03ui by zone \"%V\"",
  76.                       excess / 1000, excess % 1000, &lrcf->shm_zone->shm.name);

  77.         return NGX_HTTP_SERVICE_UNAVAILABLE;
  78.     }

  79.     /* rc == NGX_AGAIN */

  80.     if (lrcf->nodelay) {
  81.         return NGX_DECLINED;
  82.     }

  83.     ngx_log_error(lrcf->delay_log_level, r->connection->log, 0,
  84.                   "delaying request, excess: %ui.%03ui, by zone \"%V\"",
  85.                   excess / 1000, excess % 1000, &lrcf->shm_zone->shm.name);

  86.     if (ngx_handle_read_event(r->connection->read, 0) != NGX_OK) {
  87.         return NGX_HTTP_INTERNAL_SERVER_ERROR;
  88.     }

  89.     r->read_event_handler = ngx_http_test_reading;
  90.     r->write_event_handler = ngx_http_limit_req_delay;
  91.     ngx_add_timer(r->connection->write,
  92.                   (ngx_msec_t) excess * 1000 / ctx->rate);

  93.     return NGX_AGAIN;
  94. }

下面的这个函数处理过期的请求,将他们从红黑树和队列中删除。

点击(此处)折叠或打开

  1. static void
  2. ngx_http_limit_req_expire(ngx_http_limit_req_ctx_t *ctx, ngx_uint_t n)
  3. {
  4.     ngx_int_t excess;
  5.     ngx_time_t *tp;
  6.     ngx_msec_t now;
  7.     ngx_queue_t *q;
  8.     ngx_msec_int_t ms;
  9.     ngx_rbtree_node_t *node;
  10.     ngx_http_limit_req_node_t *lr;

  11.     tp = ngx_timeofday();

  12.     now = (ngx_msec_t) (tp->sec * 1000 + tp->msec);

  13.     /*
  14.      * n == 1 deletes one or two zero rate entries
  15.      * n == 0 deletes oldest entry by force
  16.      * and one or two zero rate entries
  17.      */

  18.     while (n < 3) {

  19.         if (ngx_queue_empty(&ctx->sh->queue)) {
  20.             return;
  21.         }
  22. 1)获得队列中最早的一个请求
  23.         q = ngx_queue_last(&ctx->sh->queue);

  24.         lr = ngx_queue_data(q, ngx_http_limit_req_node_t, queue);

  25.         if (n++ != 0) {

  26.             ms = (ngx_msec_int_t) (now - lr->last);
  27.             ms = ngx_abs(ms);

  28.             if (ms < 60000) {
  29.                 return;
  30.             }
  31. 计算这个请求的到来的时间,看这个请求是否
  32.             excess = lr->excess - ctx->rate * ms / 1000;

  33.             if (excess > 0) {
  34.                 return;
  35.             }
  36.         }

  37.         ngx_queue_remove(q);

  38.         node = (ngx_rbtree_node_t *)
  39.                    ((u_char *) lr - offsetof(ngx_rbtree_node_t, color));

  40.         ngx_rbtree_delete(&ctx->sh->rbtree, node);

  41.         ngx_slab_free_locked(ctx->shpool, node);
  42.     }
  43. }


点击(此处)折叠或打开

  1. static void
  2. ngx_http_limit_req_expire(ngx_http_limit_req_ctx_t *ctx, ngx_uint_t n)
  3. {
  4.     ngx_int_t excess;
  5.     ngx_time_t *tp;
  6.     ngx_msec_t now;
  7.     ngx_queue_t *q;
  8.     ngx_msec_int_t ms;
  9.     ngx_rbtree_node_t *node;
  10.     ngx_http_limit_req_node_t *lr;

  11.     tp = ngx_timeofday();

  12.     now = (ngx_msec_t) (tp->sec * 1000 + tp->msec);

  13.     /*
  14.      * n == 1 deletes one or two zero rate entries
  15.      * n == 0 deletes oldest entry by force
  16.      * and one or two zero rate entries
  17.      */

  18.     while (n < 3) {

  19.         if (ngx_queue_empty(&ctx->sh->queue)) {
  20.             return;
  21.         }

  22.         q = ngx_queue_last(&ctx->sh->queue);

  23.         lr = ngx_queue_data(q, ngx_http_limit_req_node_t, queue);

  24.         if (n++ != 0) {

  25.             ms = (ngx_msec_int_t) (now - lr->last);
  26.             ms = ngx_abs(ms);

  27.             if (ms < 60000) {
  28.                 return;
  29.             }

  30.             excess = lr->excess - ctx->rate * ms / 1000;

  31.             if (excess > 0) {
  32.                 return;
  33.             }
  34.         }

  35.         ngx_queue_remove(q);

  36.         node = (ngx_rbtree_node_t *)
  37.                    ((u_char *) lr - offsetof(ngx_rbtree_node_t, color));

  38.         ngx_rbtree_delete(&ctx->sh->rbtree, node);

  39.         ngx_slab_free_locked(ctx->shpool, node);
  40.     }
  41. }


阅读(8162) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~