深入理解nginx的请求限速模块[下]
目录
- 3. 源码分析
- 3.1 配置指令
-
- 3.1.1 limit_req_zone指令
-
- 3.1.2 limit_req指令
- 3.1.3 limit_req_dry_run指令
- 3.1.4 limit_req_log_level指令
- 3.1.5 limit_req_status指令
- 3.2 模块初始化
- 3.3 请求处理
-
- 3.3.1 ngx_http_limit_req_handler
- 3.3.1 ngx_http_limit_req_lookup
- 3.3.2 ngx_http_limit_req_account
上接 深入理解nginx的请求限速模块[上]](https://blog.csdn.net/bluestn/article/details/136710631)
3. 源码分析
3.1 配置指令
3.1.1 limit_req_zone指令
limit_req_zone指令的作用是定义一个共享内存区,用于在worker进程间共享限速的状态信息,因此请求限速模块的限速功能是服务器级别的,而不是单个worker进程级别的。其配置指令定义如下:
{
ngx_string("limit_req_zone"),
NGX_HTTP_MAIN_CONF|NGX_CONF_TAKE3,
ngx_http_limit_req_zone,
0,
0,
NULL
},
ngx_http_limit_req_zone函数的重要逻辑就是解析相应的参数,然后创建共享内存区:
static char *
ngx_http_limit_req_zone(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
{
......
ngx_http_limit_req_ctx_t *ctx;
......
ctx = ngx_pcalloc(cf->pool, sizeof(ngx_http_limit_req_ctx_t));
解析配置指令
......
ctx->rate = rate * 1000 / scale;
/* 创建共享内存区 */
shm_zone = ngx_shared_memory_add(cf, &name, size,
&ngx_http_limit_req_module);
if (shm_zone == NULL) {
return NGX_CONF_ERROR;
}
if (shm_zone->data) {
ctx = shm_zone->data;
ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
"%V \"%V\" is already bound to key \"%V\"",
&cmd->name, &name, &ctx->key.value);
return NGX_CONF_ERROR;
}
shm_zone->init = ngx_http_limit_req_init_zone;
shm_zone->data = ctx; /* 设置共享内存区的上下文信息 */
}
3.1.2 limit_req指令
limit_req指令则是开启请求限速功能,它需要引用前面limit_req_zone指令定义的共享内存区,并且指定允许的busrt突发值和delay值。其配置指令定义如下:
{
ngx_string("limit_req"),
NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE123,
ngx_http_limit_req,
NGX_HTTP_LOC_CONF_OFFSET,
0,
NULL },
static char *
ngx_http_limit_req(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
{
ngx_http_limit_req_conf_t *lrcf = conf;
ngx_http_limit_req_limit_t *limit, *limits;
......
解析配置指令
/* 如果还没有创建限速规则数组,则创建一个 */
limits = lrcf->limits.elts;
if (limits == NULL) {
if (ngx_array_init(&lrcf->limits, cf->pool, 1,
sizeof(ngx_http_limit_req_limit_t))
!= NGX_OK)
{
return NGX_CONF_ERROR;
}
}
for (i = 0; i < lrcf->limits.nelts; i++) {
if (shm_zone == limits[i].shm_zone) {
return "is duplicate";
}
}
/* 将当前limit_req指令添加到lrcf->limits数组中 */
limit = ngx_array_push(&lrcf->limits);
if (limit == NULL) {
return NGX_CONF_ERROR;
}
limit->shm_zone = shm_zone;
limit->burst = burst * 1000; /* busrt的单位是r/ms,所以乘以1000 */
limit->delay = delay * 1000; /* delay的单位是r/ms,所以乘以1000 */
return NGX_CONF_OK;
}
3.1.3 limit_req_dry_run指令
该指令设置了一个开关,如果是on的话,如果发生了限流事件,只是在error日志中打印日志,而不是实际执行限流动作。这个指令主要用于开启限流操作前进行测试验证工作。配置指令定义如下:
{
ngx_string("limit_req_dry_run"),
NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG,
ngx_conf_set_flag_slot,
NGX_HTTP_LOC_CONF_OFFSET,
offsetof(ngx_http_limit_req_conf_t, dry_run),
NULL },
3.1.4 limit_req_log_level指令
该指令设置了当发生限流事件的时候,在nginx的error日志中输出的日志的日志级别。配置指令定义如下:
{
ngx_string("limit_req_log_level"),
NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
ngx_conf_set_enum_slot,
NGX_HTTP_LOC_CONF_OFFSET,
offsetof(ngx_http_limit_req_conf_t, limit_log_level),
&ngx_http_limit_req_log_levels },
3.1.5 limit_req_status指令
该指令设置了当发生限流事件的时候,nginx返回给客户端的响应码。
{
ngx_string("limit_req_status"),
NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
ngx_conf_set_num_slot,</