nginx 소스 코드 분석 - 프로필 분석

74509 단어 nginx배치 하 다.
Nginx 의 설정 해석 과 관련 된 부분 이 비교적 복잡 합 니 다. 예 를 들 어 왜 4 개의 포인터 가 있어 야 합 니까? 예 를 들 어 NGXMAIN_CONF , loc_conf,NGX_DIRECT_CONF 는 어떤 차이 가 있 나 요?내 앞의 블 로그 들 은 모두 관련 이 있 는데, 이번 에는 주로 설정 을 완전히 꺼 내 서 분석 하 는 것 이다.
우선 설정 해석 시의 데이터 구 조 를 살 펴 보 겠 습 니 다. 여 기 는 주로 ngx 입 니 다.conf_t. 이 구 조 는 설정 파일 을 분석 하 는 데 필요 한 도 메 인 을 저장 합 니 다. 이것 은 매우 중요 한 데이터 구조 입 니 다. 우 리 는 이 구 조 를 자세히 살 펴 보 겠 습 니 다.
struct ngx_conf_s {
//         
    char                 *name;
//         
    ngx_array_t          *args;
//   cycle
    ngx_cycle_t          *cycle;
//       
    ngx_pool_t           *pool;
//  pool            。
    ngx_pool_t           *temp_pool;
//             
    ngx_conf_file_t      *conf_file;
//  log
    ngx_log_t            *log;
//            (       )
    void                 *ctx;
//    
    ngx_uint_t            module_type;
//    
    ngx_uint_t            cmd_type;
//      handler
    ngx_conf_handler_pt   handler;
//   handler conf
    char                 *handler_conf;
};

위의 일부 도 메 인 은 아직 이해 하지 못 할 수도 있 지만 괜찮아 요. 그 다음 에 하나씩 분석 할 거 예요.
설정 해석 의 입 구 를 살 펴 보 겠 습 니 다. 입 구 는 ngx 입 니 다.init_cycle 에서 여 기 는 비교적 간단 합 니 다. 바로 ngx 를 설정 하 는 것 입 니 다.conf_t 그리고 ngx 에 게 전달conf_parse 해석.
//  conf_ctx
    cycle->conf_ctx = ngx_pcalloc(pool, ngx_max_module * sizeof(void *));
    if (cycle->conf_ctx == NULL) {
        ngx_destroy_pool(pool);
        return NULL;
    }
.............................................
    for (i = 0; ngx_modules[i]; i++) {
        if (ngx_modules[i]->type != NGX_CORE_MODULE) {
            continue;
        }
        module = ngx_modules[i]->ctx;
        if (module->create_conf) {
            rv = module->create_conf(cycle);
            if (rv == NULL) {
                ngx_destroy_pool(pool);
                return NULL;
            }
//    conf_ctx          main conf.
            cycle->conf_ctx[ngx_modules[i]->index] = rv;
        }
    }
.................................
//   conf
    conf.ctx = cycle->conf_ctx;
    conf.cycle = cycle;
    conf.pool = pool;
    conf.log = log;
//  ,          MAIN,       core。
    conf.module_type = NGX_CORE_MODULE;
    conf.cmd_type = NGX_MAIN_CONF;
    if (ngx_conf_param(&conf) != NGX_CONF_OK) {
        environ = senv;
        ngx_destroy_cycle_pools(&conf);
        return NULL;
    }
//      
    if (ngx_conf_parse(&conf, &cycle->conf_file) != NGX_CONF_OK) {
        environ = senv;
        ngx_destroy_cycle_pools(&conf);
        return NULL;
    }

그리고 ngxconf_parse, 이 함수 의 두 번 째 는 분석 할 파일 이름 입 니 다. 그러나 여기 서 주의해 야 할 것 은 두 번 째 매개 변 수 는 비어 있 을 수 있 습 니 다. 비어 있 으 면 block 의 내용 이나 param 을 분석 할 것 입 니 다.
char *
ngx_conf_parse(ngx_conf_t *cf, ngx_str_t *filename)
{
    char             *rv;
    ngx_fd_t          fd;
    ngx_int_t         rc;
    ngx_buf_t         buf;
    ngx_conf_file_t  *prev, conf_file;
    enum {
        parse_file = 0,
        parse_block,
        parse_param
    } type;
#if (NGX_SUPPRESS_WARN)
    fd = NGX_INVALID_FILE;
    prev = NULL;
#endif
    if (filename) {
        /* open configuration file */
................................................
    } else if (cf->conf_file->file.fd != NGX_INVALID_FILE) {
//            block    
        type = parse_block;
    } else {
//  
        type = parse_param;
    }
    for ( ;; ) {
        rc = ngx_conf_read_token(cf);
        /*
         * ngx_conf_read_token() may return
         *
         *    NGX_ERROR             there is error
         *    NGX_OK                the token terminated by ";" was found
         *    NGX_CONF_BLOCK_START  the token terminated by "{" was found
         *    NGX_CONF_BLOCK_DONE   the "}" was found
         *    NGX_CONF_FILE_DONE    the configuration file is done
         */
.....................................................
        /* rc == NGX_OK || rc == NGX_CONF_BLOCK_START */
//   handler,   handle
        if (cf->handler) {
            /*
             * the custom handler, i.e., that is used in the http's
             * "types { ... }" directive
             */
            rv = (*cf->handler)(cf, NULL, cf->handler_conf);
            if (rv == NGX_CONF_OK) {
                continue;
            }
            if (rv == NGX_CONF_ERROR) {
                goto failed;
            }
            ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, rv);
            goto failed;
        }
//  handler         
        rc = ngx_conf_handler(cf, rc);
        if (rc == NGX_ERROR) {
            goto failed;
        }
    }
failed:
    rc = NGX_ERROR;
done:
....................................
    return NGX_CONF_OK;
}

보고 있어 ngxconf_handler 전에 Nginx 프로필 의 구조 와 cf - > handler 가 왜 있 는 지 살 펴 보 겠 습 니 다.
일반적인 Nginx 프로필 은 다음 과 같 습 니 다:
worker_processes 1;
error_log logs/error.log;
pid logs/nginx.pid;
events { worker_connections 1024; }
http { include mime.types; default_type application/octet-stream;
sendfile on;
keepalive_timeout 65;
#gzip on;
server { listen 80; server_name localhost;
access_log logs/host.access.log main;
location / { root html; index index.html index.htm; }
error_page 500 502 503 504 /50x.html; location = /50x.html { root html; } }
}
Nginx 의 설정 파일 이 블록 으로 나 뉘 어 져 있 는 것 을 볼 수 있 습 니 다. 그리고 이벤트, http 는 모두 큰 core 모듈 입 니 다. 그리고 core 모듈 에는 2 급 모듈 (epoll / kqeue / proxy..) 이 많이 포함 되 어 있 습 니 다. 즉, 1 급 모듈 에는 2 급 모듈 의 설정 을 저장 하기 위 한 컨 텍스트 가 포함 되 어 있어 야 합 니 다.한편, HTTP 모듈 에 또 일부 특수 한 것 이 있 습 니 다. 그것 은 HTTP 모듈 에 있 는 모든 명령 에 3 개의 역할 영역 이 있 을 수 있 습 니 다. 그것 이 바로 main / server / loc 이기 때문에 HTTP 의 컨 텍스트 에 이 3 개의 컨 텍스트 를 동시에 저장 해 야 합 니 다.
그리고 Nginx 의 명령 은 모두 그런 유형 이 있 습 니 다.
#define NGX_DIRECT_CONF      0x00010000
#define NGX_MAIN_CONF        0x01000000
#define NGX_ANY_CONF         0x0F000000
#define NGX_EVENT_CONF        0x02000000
#define NGX_HTTP_MAIN_CONF        0x02000000
#define NGX_HTTP_SRV_CONF         0x04000000
#define NGX_HTTP_LOC_CONF         0x08000000
#define NGX_HTTP_UPS_CONF         0x10000000
#define NGX_HTTP_SIF_CONF         0x20000000
#define NGX_HTTP_LIF_CONF         0x40000000
#define NGX_HTTP_LMT_CONF         0x80000000
#define NGX_MAIL_MAIN_CONF      0x02000000
#define NGX_MAIL_SRV_CONF       0x04000000

Nginx 의 매개 변수 유형 은 이렇게 여러 가지 가 있 는데 그 중에서 가장 구분 해 야 할 것 은 첫 번 째 와 두 번 째 입 니 다. 일반적으로 DIRECTCONF 와 MAINCONF 는 첫 번 째 가 있 으 면 두 번 째 가 동시에 사용 된다.DIRECT_CONF 는 말 그대로 CONF 에 직접 액세스 한 다 는 것 이다. 즉, 명령 해석 함수 에 들 어가 면서 CONF 가 만 들 어 졌 으 니 직접 사용 하면 된다 는 것 이다. (즉, create conf 리 셋 이 있 을 것 이다) Main conf 는 맨 위 에 있 는 conf, 예 를 들 어 HTTP / EVENT / PID 등 은 모두 CORE 모듈 에 속 하 는 것 을 볼 수 있다. NGX HTTP XXX 는 모든 HTTP 모듈 의 하위 모듈 이다.
Nginx 설정 의 기본 구 조 를 이 해 했 습 니 다. ngx conf handler 를 살 펴 보 겠 습 니 다. 이 함 수 는 예전 에 소 개 했 습 니 다. 이번 에는 가장 핵심 적 인 부분 에 만 관심 을 가지 고 있 습 니 다. 아래 부분 은 명령 표를 옮 겨 다 니 며 해당 하 는 명령 을 찾 은 다음 에 처리 합 니 다.
//     type
            if (!(cmd->type & NGX_CONF_ANY)) {
//            
                if (cmd->type & NGX_CONF_FLAG) {
                    if (cf->args->nelts != 2) {
                        goto invalid;
                    }
                } else if (cmd->type & NGX_CONF_1MORE) {
                    if (cf->args->nelts < 2) {
                        goto invalid;
                    }
.................................................
            }
            /* set up the directive's configuration context */
            conf = NULL;
//      ,
            if (cmd->type & NGX_DIRECT_CONF) {
        ctx      core   conf(create_conf  ),           conf.
                conf = ((void **) cf->ctx)[ngx_modules[i]->index];
            } else if (cmd->type & NGX_MAIN_CONF) {
//    DIRECT_CONF   MAIN,                     (           )
                conf = &(((void **) cf->ctx)[ngx_modules[i]->index]);
            } else if (cf->ctx) {
//          (       )。
                confp = *(void **) ((char *) cf->ctx + cmd->conf);
                if (confp) {
                    conf = confp[ngx_modules[i]->ctx_index];
                }
            }
//         。
            rv = cmd->set(cf, cmd, conf);
            if (rv == NGX_CONF_OK) {
                return NGX_OK;
            }
            if (rv == NGX_CONF_ERROR) {
                return NGX_ERROR;
            }
            ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
                               "\"%s\" directive %s", name->data, rv);
            return NGX_ERROR;
        }

위의 코드 에서 2 급 모듈 은 그 부분 을 분석 할 때 먼저 놓 습 니 다. 먼저 Nginx 에 2 급 모듈 이 있 는 1 급 모듈 이 명령 을 어떻게 해석 하 는 지, HTTP 모듈 (event 모듈 은 기본적으로 같 습 니 다) 의 분석 코드 를 보 겠 습 니 다.
//      direct_conf,  http       。
static ngx_command_t  ngx_http_commands[] = {
    { ngx_string("http"),
      NGX_MAIN_CONF|NGX_CONF_BLOCK|NGX_CONF_NOARGS,
      ngx_http_block,
      0,
      0,
      NULL },
      ngx_null_command
};
static char *
ngx_http_block(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
{
    char                        *rv;
    ngx_uint_t                   mi, m, s;
    ngx_conf_t                   pcf;
    ngx_http_module_t           *module;
    ngx_http_conf_ctx_t         *ctx;
    ngx_http_core_loc_conf_t    *clcf;
    ngx_http_core_srv_conf_t   **cscfp;
    ngx_http_core_main_conf_t   *cmcf;
    /* the main http context */
    ctx = ngx_pcalloc(cf->pool, sizeof(ngx_http_conf_ctx_t));
    if (ctx == NULL) {
        return NGX_CONF_ERROR;
    }
//      ,            conf
    *(ngx_http_conf_ctx_t **) conf = ctx;
    /* count the number of the http modules and set up their indices */
    ngx_http_max_module = 0;
    for (m = 0; ngx_modules[m]; m++) {
        if (ngx_modules[m]->type != NGX_HTTP_MODULE) {
            continue;
        }
//            .
        ngx_modules[m]->ctx_index = ngx_http_max_module++;
    }
    /* the http main_conf context, it is the same in the all http contexts */
//  HTTP   conf,      (main/ser/loc)       conf.
    ctx->main_conf = ngx_pcalloc(cf->pool,
                                 sizeof(void *) * ngx_http_max_module);
    if (ctx->main_conf == NULL) {
        return NGX_CONF_ERROR;
    }
    /*
     * the http null srv_conf context, it is used to merge
     * the server{}s' srv_conf's
     */
    ctx->srv_conf = ngx_pcalloc(cf->pool, sizeof(void *) * ngx_http_max_module);
    if (ctx->srv_conf == NULL) {
        return NGX_CONF_ERROR;
    }
    /*
     * the http null loc_conf context, it is used to merge
     * the server{}s' loc_conf's
     */
    ctx->loc_conf = ngx_pcalloc(cf->pool, sizeof(void *) * ngx_http_max_module);
    if (ctx->loc_conf == NULL) {
        return NGX_CONF_ERROR;
    }
    /*
     * create the main_conf's, the null srv_conf's, and the null loc_conf's
     * of the all http modules
     */
....................................
//       cf,         HTTP        cf,
    pcf = *cf;
//          
    cf->ctx = ctx;
..........................................
    /* parse inside the http{} block */
//           
    cf->module_type = NGX_HTTP_MODULE;
    cf->cmd_type = NGX_HTTP_MAIN_CONF;
//    ,              
    rv = ngx_conf_parse(cf, NULL);
    if (rv != NGX_CONF_OK) {
        goto failed;
    }
    /*
     * init http{} main_conf's, merge the server{}s' srv_conf's
     * and its location{}s' loc_conf's
     */
.........................................
    /*
     * http{}'s cf->ctx was needed while the configuration merging
     * and in postconfiguration process
     */
//  cf
    *cf = pcf;
......................................
    return NGX_CONF_OK;
failed:
    *cf = pcf;
    return rv;
}

여기 서 매우 중요 한 부분 이 있 습 니 다. 그것 은 각 단계 에 해당 하 는 ctx (main / ser / loc) 를 저장 하 는 것 입 니 다. 뭐라고 해 야 할 까요? HTTP main 을 분석 하 는 과정 에서 3 개의 ctx (main / srv / loc) 를 만 들 었 고, HTTP srv block 에 서 는 2 개의 ctx (main / srv / loc) 를 만 들 것 입 니 다. 중복 되 었 으 면 merge 가 필요 합 니 다. 예 를 들 어 명령 (srv offset) 이 필요 합 니 다.HTTP main 중 하나 입 니 다. 그러면 Nginx 는 HTTP main 의 ctx srv ctx 에 넣 고 server block 도 하나 있 습 니 다. 그러면 Nginx 는 Server ctx 의 srv conf 에 계속 넣 고 마지막 으로 merge 를 합 니 다.
그래서 server 라 는 명령 의 해석 을 살 펴 보 겠 습 니 다.
    { ngx_string("server"),
      NGX_HTTP_MAIN_CONF|NGX_CONF_BLOCK|NGX_CONF_MULTI|NGX_CONF_NOARGS,
      ngx_http_core_server,
      0,
      0,
      NULL },
static char *
ngx_http_core_server(ngx_conf_t *cf, ngx_command_t *cmd, void *dummy)
{
    char                        *rv;
    void                        *mconf;
    ngx_uint_t                   i;
    ngx_conf_t                   pcf;
    ngx_http_module_t           *module;
    struct sockaddr_in          *sin;
    ngx_http_conf_ctx_t         *ctx, *http_ctx;
    ngx_http_listen_opt_t        lsopt;
    ngx_http_core_srv_conf_t    *cscf, **cscfp;
    ngx_http_core_main_conf_t   *cmcf;
    ctx = ngx_pcalloc(cf->pool, sizeof(ngx_http_conf_ctx_t));
    if (ctx == NULL) {
        return NGX_CONF_ERROR;
    }
    http_ctx = cf->ctx;
//main conf  
    ctx->main_conf = http_ctx->main_conf;
    /* the server{}'s srv_conf */
//    srv loc conf.
    ctx->srv_conf = ngx_pcalloc(cf->pool, sizeof(void *) * ngx_http_max_module);
    if (ctx->srv_conf == NULL) {
        return NGX_CONF_ERROR;
    }
    /* the server{}'s loc_conf */
    ctx->loc_conf = ngx_pcalloc(cf->pool, sizeof(void *) * ngx_http_max_module);
    if (ctx->loc_conf == NULL) {
        return NGX_CONF_ERROR;
    }
............................
    /* the server configuration context */
    cscf = ctx->srv_conf[ngx_http_core_module.ctx_index];
    cscf->ctx = ctx;
    cmcf = ctx->main_conf[ngx_http_core_module.ctx_index];
//     servers,        main  。      HTTP main        srv conf.
    cscfp = ngx_array_push(&cmcf->servers);
    if (cscfp == NULL) {
        return NGX_CONF_ERROR;
    }
    *cscfp = cscf;
    /* parse inside server{} */
//  ,      type srv_conf.
    pcf = *cf;
    cf->ctx = ctx;
    cf->cmd_type = NGX_HTTP_SRV_CONF;
    rv = ngx_conf_parse(cf, NULL);
//  cf.
    *cf = pcf;
  ........................
    }
    return rv;
}

이런 것들 을 알 게 되 었 습 니 다. 우 리 는 맨 위의 코드 를 보 겠 습 니 다.
struct ngx_command_s {
    ngx_str_t             name;
    ngx_uint_t            type;
    char               *(*set)(ngx_conf_t *cf, ngx_command_t *cmd, void *conf);
//conf          .  NGX_HTTP_LOC_CONF_OFFSET
    ngx_uint_t            conf;
    ngx_uint_t            offset;
    void                 *post;
};
............................
            else if (cf->ctx) {
//     1         (HTTP  srv_offset)
                confp = *(void **) ((char *) cf->ctx + cmd->conf);
                if (confp) {
//         conf.
                    conf = confp[ngx_modules[i]->ctx_index];
                }
            }

그리고 간단 한 명령 을 어떻게 사용 하고 설정 하 는 지 살 펴 보 겠 습 니 다. 보기 전에 몇 가지 핵심 구 조 를 살 펴 보 겠 습 니 다.
typedef struct {
    void        **main_conf;
    void        **srv_conf;
    void        **loc_conf;
} ngx_http_conf_ctx_t;
//        ngx_command_t conf ,        conf   .
#define NGX_HTTP_MAIN_CONF_OFFSET  offsetof(ngx_http_conf_ctx_t, main_conf)
#define NGX_HTTP_SRV_CONF_OFFSET   offsetof(ngx_http_conf_ctx_t, srv_conf)
#define NGX_HTTP_LOC_CONF_OFFSET   offsetof(ngx_http_conf_ctx_t, loc_conf)
//             
#define ngx_http_get_module_main_conf(r, module)                             \
    (r)->main_conf[module.ctx_index]
#define ngx_http_get_module_srv_conf(r, module)  (r)->srv_conf[module.ctx_index]
#define ngx_http_get_module_loc_conf(r, module)  (r)->loc_conf[module.ctx_index]
#define ngx_http_conf_get_module_main_conf(cf, module)                        \
    ((ngx_http_conf_ctx_t *) cf->ctx)->main_conf[module.ctx_index]
#define ngx_http_conf_get_module_srv_conf(cf, module)                         \
    ((ngx_http_conf_ctx_t *) cf->ctx)->srv_conf[module.ctx_index]
#define ngx_http_conf_get_module_loc_conf(cf, module)                         \
    ((ngx_http_conf_ctx_t *) cf->ctx)->loc_conf[module.ctx_index]
#define ngx_http_cycle_get_module_main_conf(cycle, module)                    \
    (cycle->conf_ctx[ngx_http_module.index] ?                                 \
        ((ngx_http_conf_ctx_t *) cycle->conf_ctx[ngx_http_module.index])      \
            ->main_conf[module.ctx_index]:                                    \
        NULL)
#define ngx_get_conf(conf_ctx, module)  conf_ctx[module.index]

전형 적 인 설정 명령 몇 개 를 보 겠 습 니 다.
우선 env 입 니 다. DIRECT CONF 명령 입 니 다.
//     create_conf  
static ngx_core_module_t  ngx_core_module_ctx = {
    ngx_string("core"),
    ngx_core_module_create_conf,
    ngx_core_module_init_conf
};
................................
    { ngx_string("env"),
      NGX_MAIN_CONF|NGX_DIRECT_CONF|NGX_CONF_TAKE1,
      ngx_set_env,
      0,
      0,
      NULL },
static char *
ngx_set_env(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
{
//         
    ngx_core_conf_t  *ccf = conf;
.............................
    return NGX_CONF_OK;
}

그리고 http 의 루트 명령:
    { ngx_string("root"),
      NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_HTTP_LIF_CONF
                        |NGX_CONF_TAKE1,
      ngx_http_core_root,
      NGX_HTTP_LOC_CONF_OFFSET,
      0,
      NULL },
static char *
ngx_http_core_root(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
{
//      (         NGX_HTTP_LOC_CONF_OFFSET)
    ngx_http_core_loc_conf_t *clcf = conf;
.......................................
    return NGX_CONF_OK;
}

마지막 으로 왜 4 급 포인터 가 있 는 지 살 펴 보 겠 습 니 다. 이것 은 모듈 등급 과 관련 된 것 입 니 다. 1 급 모듈 만 있 으 면 2 급 포인터 만 있 으 면 됩 니 다. 하지만 아직 2 급 모듈 이 있 습 니 다. 각 1 급 모듈 의 2 급 포인터 안 에는 반드시 확장 포인터 가 있어 야 본 급 모듈 의 문맥 을 보존 해 야 합 니 다. 그러면 자 연 스 럽 게 4 급 포인터 입 니 다. 이벤트 모듈 을 자세히 볼 수 있 습 니 다.그 안 이 비교적 뚜렷 하 다.

좋은 웹페이지 즐겨찾기