nginx ngx_http_reqstat_module模块说明

req_stat是计数器,目前只能按照server块的粒度来进行统计状态码。

配置如下:

req_status_lazy on;

req_status_zone req_status "$server_addr:$server_port:$upstream_addr" 50M;

req_status req_status;

server {

    listen 1.1.1.1:80;

    location /check_req_status {

        req_status_show req_status;

    }

}

在req_status_zone 指令的函数中,将这个字符串进行编译,放入ctx→value,ctx是这个模块的上下文

static char *

ngx_http_reqstat_zone(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)

{

...

    ctx = ngx_pcalloc(cf->pool, sizeof(ngx_http_reqstat_ctx_t));

    ngx_memzero(&ccv, sizeof(ngx_http_compile_complex_value_t));

    ccv.cf = cf;

    ccv.value = &value[2];

    // ccv的complex_value指针指向ctx->value

    ccv.complex_value = &ctx->value;

    // compile之后,ctx的value存储这一格式

    if (ngx_http_compile_complex_value(&ccv) != NGX_OK) {

        return NGX_CONF_ERROR;

    }

    // ctx->val是个string,记录这个key的名字

    ctx->val = ngx_palloc(cf->pool, sizeof(ngx_str_t));

    if (ctx->val == NULL) {

        return NGX_CONF_ERROR;

    }

    *ctx->val = value[2];

...

}

ngx_http_reqstat是把对应的req_status_zone配置相应的共享内存

static char *

ngx_http_reqstat(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)

{

...

    // 这块是从ngx_conf_handler中取出来的配置,按理说我们配置里面都把ngx_http_reqstat放在http下面,应该也是main conf

    ngx_http_reqstat_conf_t      *rlcf = conf;

    value = cf->args->elts;

    // 这个smcf是从cf->ctx中拿出来的reqstat main 配置,按理说和上面的rlcf应该相同,不明白为何不一样。

    // 终于弄明白了,cmd->type那块是NGX_HTTP_MAIN_CONF,而ngx_conf_handler那块是NGX_MAIN_CONF,所以一定会走到loc_conf里面,所以cmd第四个那个位置就是这个指令修改的配置最终在哪里的意思

    // 因此这块修改都是http块下面生成的loc conf

    smcf = ngx_http_conf_get_module_main_conf(cf, ngx_http_reqstat_module);

    // 将rlcf的monitor初始化,并且将没有的添加进smcf中。

    rlcf->monitor = ngx_array_create(cf->pool, cf->args->nelts - 1,

                                     sizeof(ngx_shm_zone_t *));

    for (i = 1; i < cf->args->nelts; i++) {

        // 添加对应数量的shm_zone,放入rlcf->monitor数组

        shm_zone = ngx_shared_memory_add(cf, &value[i], 0,

                                         &ngx_http_reqstat_module);

        z = ngx_array_push(rlcf->monitor);

        *z = shm_zone;

        z = smcf->monitor->elts;

        for (j = 0; j < smcf->monitor->nelts; j++) {

            if (!ngx_strcmp(value[i].data, z[j]->shm.name.data)) {

                break;

            }

        }

        // smcf存一个全量

        if (j == smcf->monitor->nelts) {

            z = ngx_array_push(smcf->monitor);

            if (z == NULL) {

                return NGX_CONF_ERROR;

            }

            *z = shm_zone;

        }

    }

...

}

配置指定完之后,会调用ngx_http_reqstat_init函数,来把两个handler放入对应阶段中

static ngx_int_t

ngx_http_reqstat_init(ngx_conf_t *cf)

{

...

    cmcf = ngx_http_conf_get_module_main_conf(cf, ngx_http_core_module);

    h = ngx_array_push(&cmcf->phases[NGX_HTTP_LOG_PHASE].handlers);

    *h = ngx_http_reqstat_log_handler;

    h = ngx_array_push(&cmcf->phases[NGX_HTTP_REWRITE_PHASE].handlers);

    *h = ngx_http_reqstat_init_handler;

...

}

ngx_http_reqstat_init_handler在rewrite阶段,每个请求都经过,如果没有store的话,初始化store

static ngx_int_t

ngx_http_reqstat_init_handler(ngx_http_request_t *r)

{

...

    ngx_http_reqstat_conf_t      *rmcf, *rlcf;

    ngx_http_reqstat_store_t     *store;

    store = ngx_http_get_module_ctx(r, ngx_http_reqstat_module);

    rmcf = ngx_http_get_module_main_conf(r, ngx_http_reqstat_module);

    rlcf = ngx_http_get_module_loc_conf(r, ngx_http_reqstat_module);

    if (store == NULL) {

        if (r->variables[rmcf->index].valid) {

            return NGX_DECLINED;

        }

        // 创建store

        store = ngx_http_reqstat_create_store(r, rlcf);

        if (store == NULL) {

            return NGX_ERROR;

        }

        // 这个store只关联于这个request,一旦这个request销毁,就不复存在,因此每个新的请求都要创建一个store

        ngx_http_set_ctx(r, store, ngx_http_reqstat_module);

    }

...

}

ngx_http_reqstat_create_store函数:

static ngx_http_reqstat_store_t *

ngx_http_reqstat_create_store(ngx_http_request_t *r,

    ngx_http_reqstat_conf_t *rlcf)

{

...

    store = ngx_pcalloc(r->pool, sizeof(ngx_http_reqstat_store_t));

    // 创建monitor index和value index

    if (ngx_array_init(&store->monitor_index, r->pool, rlcf->monitor->nelts,

                       sizeof(ngx_http_reqstat_rbnode_t *)) == NGX_ERROR)

    {

        return NULL;

    }

    if (ngx_array_init(&store->value_index, r->pool, rlcf->monitor->nelts,

                       sizeof(ngx_str_t)) == NGX_ERROR)

    {

        return NULL;

    }

    // 在shm_zone里查找val,从而找到node(应该是模糊匹配?),每个shm_zone对应一个store里面的value_index和monitor_index

    shm_zone = rlcf->monitor->elts;

    for (i = 0; i < rlcf->monitor->nelts; i++) {

        z = shm_zone[i];

        ctx = z->data;

        if (ngx_http_complex_value(r, &ctx->value, &val) != NGX_OK) {

            ngx_log_error(NGX_LOG_WARN, r->connection->log, 0,

                          "failed to reap the key \"%V\"", ctx->val);

            continue;

        }

        value = ngx_array_push(&store->value_index);

        *value = val;

        fnode = ngx_http_reqstat_rbtree_lookup(shm_zone[i], &val);

        fnode_store = ngx_array_push(&store->monitor_index);

        *fnode_store = fnode;

...

}

ngx_http_reqstat_log_handler真正记录

static ngx_int_t

ngx_http_reqstat_log_handler(ngx_http_request_t *r)

{

...

    // 获取共享内存,fnode数组,value数组。

    shm_zone = rcf->monitor->elts;

    fnode_store = store->monitor_index.elts;

    value = store->value_index.elts;

    // 遍历之前存好的monitor_index,这个适合shm_zone的数量是对应起来的,给每个shm_zone都加入这个计数

    for (i = 0; i < store->monitor_index.nelts; i++) {

        if (fnode_store[i] == NULL) {

            continue;

        }

        // 获取z和上下文ctx

        z = shm_zone[i];

        ctx = z->data;

        // 核心:判断是否是lazy

        if (rcf->lazy) {

            // 是的话,使用r重新compile val,这次有了upstream相关的,任何变量都能用。

            if (ngx_http_complex_value(r, &ctx->value, &val) != NGX_OK) {

                ngx_log_error(NGX_LOG_WARN, r->connection->log, 0,

                              "failed to reap the key \"%V\"", ctx->val);

                continue;

            }

            // 如果重新编译的val和之前编译过的是value一致的话,就不用重新在tree里面搜索了,代表两次编译(虽然打开lazy开关),但是一致,

            if (value[i].len == val.len

                && ngx_strncmp(value[i].data, val.data, val.len) == 0)

            {

                fnode = fnode_store[i];

            // 如果不行的话,需要重新搜索,之前搜索那个匹配不上。

            } else {

                // 终于有了真正的fnode

                fnode = ngx_http_reqstat_rbtree_lookup(shm_zone[i], &val);

                if (fnode == NULL) {

                    ngx_log_error(NGX_LOG_WARN, r->connection->log, 0,

                                  "failed to alloc node in zone \"%V\", "

                                  "enlarge it please",

                                  &z->shm.name);

                    fnode = fnode_store[i];

                // 开始计数

                } else {

                    ngx_http_reqstat_count(fnode, NGX_HTTP_REQSTAT_BYTES_OUT,

                                           r->connection->sent);

                    ngx_http_reqstat_count(fnode, NGX_HTTP_REQSTAT_BYTES_IN,

                                           r->connection->received);

                    if (store) {

                        store->recv = r->connection->received;

                    }

                }

            }

        } else {

            fnode = fnode_store[i];

        }

...

}

发布了17 篇原创文章 · 获赞 0 · 访问量 3222

猜你喜欢

转载自blog.csdn.net/realmardrid/article/details/104497625
今日推荐