nginx http模块初始化与处理流程

 

1,HTTP模块初始化

(1)HTTP模块配置

http 
{
  include       mime.types;
  default_type  application/octet-stream;
 
  #charset  gb2312;
      
  server_names_hash_bucket_size 128;
  client_header_buffer_size 32k;
  large_client_header_buffers 4 32k;
  client_max_body_size 8m;
      
  sendfile on;
  tcp_nopush     on;
 
  keepalive_timeout 60;
 
  tcp_nodelay on;
 
  fastcgi_connect_timeout 300;
  fastcgi_send_timeout 300;
  fastcgi_read_timeout 300;
  fastcgi_buffer_size 64k;
  fastcgi_buffers 4 64k;
  fastcgi_busy_buffers_size 128k;
  fastcgi_temp_file_write_size 128k;
 
  gzip on;
  gzip_min_length  1k;
  gzip_buffers     4 16k;
  gzip_http_version 1.0;
  gzip_comp_level 2;
  gzip_types       text/plain application/x-javascript text/css application/xml;
  gzip_vary on;
 
  #limit_zone  crawler  $binary_remote_addr  10m;
 
  server
  {
    listen       80;
    #server_name  blog.s135.com;
    index index.html index.htm index.php;
    root   /home/wwwroot/;
 
    #limit_conn   crawler  20;    
                             
    location ~ .*\.(php|php5)?$
    {      
      #fastcgi_pass  unix:/tmp/php-cgi.sock;
      fastcgi_pass  127.0.0.1:9000;
      fastcgi_index index.php;
      include fcgi.conf;
    }
    
    location ~ .*\.(gif|jpg|jpeg|png|bmp|swf)$
    {
      expires      30d;
    }
 
    location ~ .*\.(js|css)?$
    {
      expires      1h;
    }    
 
    log_format  access  '$remote_addr - $remote_user [$time_local] "$request" '
              '$status $body_bytes_sent "$http_referer" '
              '"$http_user_agent" $http_x_forwarded_for';
    access_log  /usr/local/nginx-1.4.7/logs/access.log  access;
      }
 
  server
  {
    listen  80;
    server_name  status.blog.s135.com;
    location / {
    stub_status on;
    access_log   off;
    }
  }

从上面的配置文件我们可以看到,HTTP的配置主要分为4层:

  • 最外层的http{} 模块。模块类型:NGX_CORE_MODULE (最外层的核心模块)
  • http核心模块中的main配置:http{include mine type; }。模块类型:NGX_HTTP_MODULE (全局的HTTP模块的配置信息)
  • http核心模块中的server配置:server{}。模块类型:NGX_HTTP_MODULE (主要是配置Server的信息)
  • http核心模块中的location本地信息配置:location{}。模块类型:NGX_HTTP_MODULE (主要一个server对应的本地资源信息:静态资源、反向代理端口地址、各种语言容器端口等)

最外层的http模块,类型NGX_CORE_MODULE,属于核心模块,核心模块在最开始配置文件初始化的时候,就会调用指令的命令集。所以在核心模块启动的时候就会调用http的模块配置解析指令函数:ngx_http_block

(2)HTTP核心模块的数据结构

/**
 * HTTP模块命令集
 * HTTP模块也是一个大模块,最外层为:
 * http {
 * ....
 * }
 * ngx_http_block:该方法就是回调函数
 * 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
};
 
/**
 *HTTP核心模块上下文
 */
static ngx_core_module_t  ngx_http_module_ctx = {
    ngx_string("http"),
    NULL,
    NULL
};
 
/**
 * HTTP核心模块 结构
 * 模块类型:NGX_CORE_MODULE
 * 通过调用ngx_http_block方法,解析{}中的HTTP模块配置
 */
ngx_module_t  ngx_http_module = {
    NGX_MODULE_V1,
    &ngx_http_module_ctx,                  /* module context */
    ngx_http_commands,                     /* module directives */
    NGX_CORE_MODULE,                       /* module type */
    NULL,                                  /* init master */
    NULL,                                  /* init module */
    NULL,                                  /* init process */
    NULL,                                  /* init thread */
    NULL,                                  /* exit thread */
    NULL,                                  /* exit process */
    NULL,                                  /* exit master */
    NGX_MODULE_V1_PADDING
};

从上面的结构中可以看到http{} 是NGX_CORE_MODULE,在核心模块初始化的时候,会调用ngx_http_commands命令集中的回调函数,逐个解析核心模块的配置信息。

而HTTP模块的总入口就是这个http{}命令集的回调函数:ngx_http_block

如果对配置文件如何解析有遗忘,请回顾《 Nginx源码分析 - 主流程篇 - 解析配置文件 》

(3)初始化流程及ngx_http_block函数解读

// ngx_http_core_module.h
// http 11个阶段
typedef enum {
    NGX_HTTP_POST_READ_PHASE = 0,

    NGX_HTTP_SERVER_REWRITE_PHASE,

    NGX_HTTP_FIND_CONFIG_PHASE,
    NGX_HTTP_REWRITE_PHASE,
    NGX_HTTP_POST_REWRITE_PHASE,

    NGX_HTTP_PREACCESS_PHASE,

    NGX_HTTP_ACCESS_PHASE,
    NGX_HTTP_POST_ACCESS_PHASE,

    NGX_HTTP_PRECONTENT_PHASE,

    NGX_HTTP_CONTENT_PHASE,

    NGX_HTTP_LOG_PHASE
} ngx_http_phases;

//
static ngx_command_t  ngx_http_access_commands[] = {

    { ngx_string("allow"),
      NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_HTTP_LMT_CONF
                        |NGX_CONF_TAKE1,
      ngx_http_access_rule,
      NGX_HTTP_LOC_CONF_OFFSET,
      0,
      NULL },

    { ngx_string("deny"),
      NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_HTTP_LMT_CONF
                        |NGX_CONF_TAKE1,
      ngx_http_access_rule,
      NGX_HTTP_LOC_CONF_OFFSET,
      0,
      NULL },

      ngx_null_command
};

// 
static ngx_http_module_t  ngx_http_access_module_ctx = {
    NULL,                                  /* preconfiguration */
    ngx_http_access_init,                  /* postconfiguration */

    NULL,                                  /* create main configuration */
    NULL,                                  /* init main configuration */

    NULL,                                  /* create server configuration */
    NULL,                                  /* merge server configuration */

    ngx_http_access_create_loc_conf,       /* create location configuration */
    ngx_http_access_merge_loc_conf         /* merge location configuration */
};
//
ngx_module_t  ngx_http_access_module = {
    NGX_MODULE_V1,
    &ngx_http_access_module_ctx,           /* module context */
    ngx_http_access_commands,              /* module directives */
    NGX_HTTP_MODULE,                       /* module type */
    NULL,                                  /* init master */
    NULL,                                  /* init module */
    NULL,                                  /* init process */
    NULL,                                  /* init thread */
    NULL,                                  /* exit thread */
    NULL,                                  /* exit process */
    NULL,                                  /* exit master */
    NGX_MODULE_V1_PADDING
};

ngx_init_cycle
    --ngx_conf_param
        --ngx_conf_parse
            --ngx_conf_handler
                --cmd->set(cf, cmd, conf)
                    --ngx_http_block
                        --module->create_main_conf(cf)/module->create_srv_conf(cf)/module->create_loc_conf(cf)
                        --module->preconfiguration(cf)/module->init_main_conf(cf, ctx->main_conf[mi]) //
                        --ngx_http_init_phases // 对http的11个阶段handlers分配内存空间
                        --module->postconfiguration(cf) // 设置http11个阶段的handler具体值
                            --ngx_http_access_init
                                --*h = ngx_http_access_handler;
                            --...
                            --
                        --ngx_http_init_phase_handlers // 设置http11个阶段的checker具体值


/**
 *ngx_http_commands 命令集的回调函数
 *HTTP模块初始化的入口函数
 *
 */
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;
 
    if (*(ngx_http_conf_ctx_t **) conf) {
        return "is duplicate";
    }
 
    /* the main http context */
 
    /* 分配一块内存,存放http配置上下文 */
    ctx = ngx_pcalloc(cf->pool, sizeof(ngx_http_conf_ctx_t));
    if (ctx == NULL) {
        return NGX_CONF_ERROR;
    }
 
    *(ngx_http_conf_ctx_t **) conf = ctx;
 
 
    /* count the number of the http modules and set up their indices */
 
    /* 计算http模块个数 */
    ngx_http_max_module = ngx_count_modules(cf->cycle, NGX_HTTP_MODULE);
 
 
    /* the http main_conf context, it is the same in the all http contexts */
 
    /**
     * 最外层的HTTP配置
     * http
	  {
	  include       mime.types;
	  default_type  application/octet-stream;
     */
    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
     */
    /**
     * server层的配置
     *   server
  {
    listen       80;
    #server_name  blog.s135.com;
    index index.html index.htm index.php;
    root   /home/wwwroot/;
     */
    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
     */
 
    /**
     * location 层的配置
    location ~ .*\.(php|php5)?$
    {
      #fastcgi_pass  unix:/tmp/php-cgi.sock;
      fastcgi_pass  127.0.0.1:9000;
      fastcgi_index index.php;
      include fcgi.conf;
    }
     */
    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
     */
     /**
      * 调用:create_main_conf、create_srv_conf、create_loc_conf
      * 创建配置
      */
    for (m = 0; cf->cycle->modules[m]; m++) {
        if (cf->cycle->modules[m]->type != NGX_HTTP_MODULE) {
            continue;
        }
 
        module = cf->cycle->modules[m]->ctx;
        mi = cf->cycle->modules[m]->ctx_index;
 
        if (module->create_main_conf) {
            ctx->main_conf[mi] = module->create_main_conf(cf);
            if (ctx->main_conf[mi] == NULL) {
                return NGX_CONF_ERROR;
            }
        }
 
        if (module->create_srv_conf) {
            ctx->srv_conf[mi] = module->create_srv_conf(cf);
            if (ctx->srv_conf[mi] == NULL) {
                return NGX_CONF_ERROR;
            }
        }
 
        if (module->create_loc_conf) {
            ctx->loc_conf[mi] = module->create_loc_conf(cf);
            if (ctx->loc_conf[mi] == NULL) {
                return NGX_CONF_ERROR;
            }
        }
    }
 
    pcf = *cf;
    cf->ctx = ctx;
 
    /**
     * preconfiguration 预先初始化配置信息
     */
    for (m = 0; cf->cycle->modules[m]; m++) {
        if (cf->cycle->modules[m]->type != NGX_HTTP_MODULE) {
            continue;
        }
 
        module = cf->cycle->modules[m]->ctx;
 
        if (module->preconfiguration) {
            if (module->preconfiguration(cf) != NGX_OK) {
                return NGX_CONF_ERROR;
            }
        }
    }
 
    /* 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
     */
 
    /**
     * 初始化main配置
     * 合并 server srv_conf
     * 合并location loc_conf
     */
    cmcf = ctx->main_conf[ngx_http_core_module.ctx_index];
    cscfp = cmcf->servers.elts;
 
    for (m = 0; cf->cycle->modules[m]; m++) {
        if (cf->cycle->modules[m]->type != NGX_HTTP_MODULE) {
            continue;
        }
 
        module = cf->cycle->modules[m]->ctx;
        mi = cf->cycle->modules[m]->ctx_index;
 
        /* init http{} main_conf's */
 
        if (module->init_main_conf) {
            rv = module->init_main_conf(cf, ctx->main_conf[mi]);
            if (rv != NGX_CONF_OK) {
                goto failed;
            }
        }
 
        rv = ngx_http_merge_servers(cf, cmcf, module, mi);
        if (rv != NGX_CONF_OK) {
            goto failed;
        }
    }
 
 
    /* create location trees */
 
    /**
     * 创建 location模块的trees
     */
    for (s = 0; s < cmcf->servers.nelts; s++) {
 
        clcf = cscfp[s]->ctx->loc_conf[ngx_http_core_module.ctx_index];
 
        if (ngx_http_init_locations(cf, cscfp[s], clcf) != NGX_OK) {
            return NGX_CONF_ERROR;
        }
 
        if (ngx_http_init_static_location_trees(cf, clcf) != NGX_OK) {
            return NGX_CONF_ERROR;
        }
    }
 
 
    if (ngx_http_init_phases(cf, cmcf) != NGX_OK) {
        return NGX_CONF_ERROR;
    }
 
    if (ngx_http_init_headers_in_hash(cf, cmcf) != NGX_OK) {
        return NGX_CONF_ERROR;
    }
 
 
    for (m = 0; cf->cycle->modules[m]; m++) {
        if (cf->cycle->modules[m]->type != NGX_HTTP_MODULE) {
            continue;
        }
 
        module = cf->cycle->modules[m]->ctx;
 
        if (module->postconfiguration) {
            if (module->postconfiguration(cf) != NGX_OK) {
                return NGX_CONF_ERROR;
            }
        }
    }
 
    if (ngx_http_variables_init_vars(cf) != NGX_OK) {
        return NGX_CONF_ERROR;
    }
 
    /*
     * http{}'s cf->ctx was needed while the configuration merging
     * and in postconfiguration process
     */
 
    *cf = pcf;
 
 
    if (ngx_http_init_phase_handlers(cf, cmcf) != NGX_OK) {
        return NGX_CONF_ERROR;
    }
 
 
    /* optimize the lists of ports, addresses and server names */
 
    /* ngx_http_optimize_servers 初始化listen 端口号 ip地址 服务器等监听信息*/
    if (ngx_http_optimize_servers(cf, cmcf, cmcf->ports) != NGX_OK) {
        return NGX_CONF_ERROR;
    }
 
    return NGX_CONF_OK;
 
failed:
 
    *cf = pcf;
 
    return rv;
}

    

 

2,HTTP处理流程概述

ngx_http_init_connection
    ngx_http_wait_request_handler
        ngx_http_wait_request_handler
            ngx_http_process_request_line和ngx_http_process_request_headers
                --ngx_http_process_request // 在接收到完整的HTTP头部后,已经有足有的必要信息开始在业务上处理HTTP请求了。这里开始11阶段。
                    --ngx_http_handler
                        --ngx_http_core_run_phases //处理http的11个阶段。根据ngx_http_core_main_conf初始化的checker,调用各阶段checker,各checker中会调用handler。
                          //其中:1,config_phase阶段是一个关键阶段,不可跳过。作用是根据rewrite_phase步骤重写后的URL检索出匹配的locaion。
                          //其中:2,content_phase阶段用于真正处理请求的内容是核心阶段。
                          //其一,content_phase以上9个阶段专注于4件基础性工作:rewrite重写URL,找到location配置块、判断是否有访问权限、try_files优先读取静态文件。                            
                          //其二,content_phase与其他阶段都不同的是,他向http模块提供两种接入该阶段的方式:第一种与其他10阶段相同,
                          //通过在全局的ngx_http_core_main_conf_t结构体中phases数组添加ngx_http_handler_pt处理方法来实现(也是http
                          //模块介入其他10阶段的唯一方法,是通过在必定会被调用的postconfiguration方法项全局gx_http_core_main_conf_t的
                          //phases[NGX_HTTP_CONTENT_PHASE]动态数组添加ngx_http_handler_pt处理方法来达成,这个处理方法将会应用于全部的HTTP请求)。
                          //而第二种是content_phase阶段独有,把handler处理方法设置到ngx_http_core_loc_conf_t中的handler指针中,
                          //如果请求匹配的location块下没有配置HTTP模块处理请求,那么这个handler为NULL(每个location对应一个
                          //独立的ngx_http_core_loc_conf_t,不必在postconfiguration设置handler,而是在ngx_command_t的某个配置项(如第3章
                          //中的mytest配置项)的回调方法中添加处理方法handler,好处是:不再应用于所有的http请求,仅仅当用户
                          //请求匹配了location时才会被调用)。
                            --ngx_http_core_find_config_phase
                                --ngx_http_core_find_location
                                --ngx_http_update_location_config{
                                            if (clcf->handler) {
                                                r->content_handler = clcf->handler;
                                            }
                                    }
                            --ngx_http_core_content_phase{
                                    ...
                                    if (r->content_handler) {
                                           r->write_event_handler = ngx_http_request_empty_handler;
                                            ngx_http_finalize_request(r, r->content_handler(r));
                                            return NGX_OK;
                                    }

                                    rc = ph->handler(r);
                                    ...
                                }
    


 

nginx http模块初始化与处理流程

  • accept阶段(ngx_http_init_connection):
  1. 分配ngx_http_connection_t结构体;
  2. 根据fd的端口和地址,为hc->addr_conf赋值,以供后续server块查询;
  3. 新的fd加入epoll,设置读超时,超时时间为post_accept_timeout,设置连接可重用。

rev:ngx_http_wait_request_handler (此时没有读取任何数据。) wev:
ngx_http_empty_handler

  • 首次读阶段(ngx_http_wait_request_handler):
  1. 分配c->buffer(cscf->client_header_buffer_size大小)用于存储客户端包头;
  2. recv调用接收包头;
  3. 创建ngx_http_request_t。

rev:ngx_http_process_request_line (循环接收请求行,解析请求行)
wev:ngx_http_empty_handler

  • 请求行阶段(ngx_http_process_request_line):
  1. 循环recv,放入r->header_in(c->buffer);
  2. 解析uri,包括r->uri、r->args、r->exten;
  3. 请求行处理结束。

rev:ngx_http_process_request_headers; (循环接收请求头,解析请求头)
wev:ngx_http_empty_handler

  • 请求头阶段(ngx_http_process_request_headers):
  1. 循环recv,放入r->header_in(c->buffer);
  2. 解析请求头,保存在r->headers_in.headers;
  3. 解析请求头结束后,调用ngx_http_process_request,进行11阶段和子请求处理。

rev:ngx_http_request_handler
——read_event_handler->ngx_http_block_reading (主请求读停止,子请求处理)
wev:ngx_http_request_handler
——write_event_handler->ngx_http_core_run_phases (11阶段,子请求处理)

  • 十一阶段:(读触发)
  1. 在r->content_handler存在情况下,调用content_handler。

rev:ngx_http_request_handler
——read_event_handler->ngx_http_block_reading (子请求处理)
wev:ngx_http_request_handler
——write_event_handler->ngx_http_request_empty_handler (子请求处理)

  • content_handler阶段:(ngx_http_proxy_handler)
  1. 分配ngx_http_upstream_t结构体,并根据上游的协议类型,为upstream分配不同的回调函数,例如:
    create_request:创建上游请求
    process_header:处理上游响应
    finalize_request:结束上游请求
    input_filter_init:input_filter初始化
    input_filter:上游响应的处理函数
  2. 无请求体情况,直接进入上游初始化(ngx_http_upstream_init);
  3. 调用u->create_request将全部请求放入u->request_bufs(ngx_chain_t);
  4. 建立上游连接(ngx_http_upstream_connect)。

rev:ngx_http_upstream_handler
——read_event_handler->ngx_http_upstream_process_header (处理上游响应)
wev:ngx_http_upstream_handler
——write_event_handler->ngx_http_upstream_send_request_handler
(向上游发送请求)

  • request_body_no_buffering=0的情况(缓存请求体):
    1.不调用ngx_http_upstream_init建立上游;
    2.读事件触发请求体接收,直至请求体读取完成;
    3.回调rb->post_handler,即建立上游。

rev:ngx_http_request_handler
——read_event_handler->ngx_http_read_client_request_body_handler(读取过程中)
——read_event_handler->ngx_http_block_reading(读取结束后) (读取请求体)
wev:ngx_http_request_handler
——write_event_handler->ngx_http_request_empty_handler (子请求处理)

  • request_body_no_buffering=1的情况(不缓存请求体):

1.第一次读取结束后,设置r->reading_body = 1;
2.立即建立上游;
3.上游写事件触发时,将判断r->reading_body位,并不断读取请求体并发送至上游,直至请求体读取完成。

rev:ngx_http_request_handler
——read_event_handler->ngx_http_block_reading
(请求体下游读取一次后,后续的请求体不再由下游套接字触发接收,而是由上游的写事件触发。子请求处理)
wev:ngx_http_request_handler
——write_event_handler->ngx_http_request_empty_handler (子请求处理)

  • r->discard_body = 1的情况:

rev:ngx_http_request_handler
——read_event_handler->ngx_http_discarded_request_body_handler
(请求体只读不发) wev:ngx_http_request_handler
——write_event_handler->ngx_http_request_empty_handler (子请求处理)

  • 上游请求发送阶段:(ngx_http_upstream_send_request)
  1. 对于首次请求发送(!u->request_sent),调用ngx_output_chain,发送u->request_bufs和r->request_body->bufs中的请求,直到请求发送完毕;
  2. 非首次发送,只需要发送r->request_body->bufs。
  3. 如果request_body_no_buffering = 0,发送一次就结束。否则,将循环读取下游包体,并循环发送。

rev:ngx_http_upstream_handler
——read_event_handler->ngx_http_upstream_process_header (处理上游响应)
wev:ngx_http_upstream_handler
——write_event_handler->ngx_http_upstream_dummy_handler
(因请求发送完成,所以上游写事件不再处理)

  • 响应头阶段:(ngx_http_upstream_process_header)
    1.循环recv,放入u->buffer;
    2.u->process_header解析响应行和响应头,解析结果保存在u->headers_in;
    3.将响应头放入r->headers_out;
    4.ngx_http_send_header发送响应头。

上游:
——read_event_handler->ngx_http_upstream_process_non_buffered_upstream-读,最终调用函数同下游写 (接收处理发送上游响应体) ——write_event_handler->ngx_http_upstream_dummy_handler
(不处理) 下游: ——read_event_handler->ngx_http_block_reading (不处理)
——write_event_handler->ngx_http_upstream_process_non_buffered_downstream-写,最终调用函数同上游读
(下游发送响应体)

  • 响应体阶段:
    即ngx_http_upstream_process_non_buffered_request调用
    1.循环recv,放入u->buffer;
    2.调用ngx_http_output_filter过滤及发送。

 

 

参考:

https://initphp.blog.csdn.net/article/details/53704137?utm_medium=distribute.pc_relevant_t0.none-task-blog-BlogCommendFromMachineLearnPai2-1.control&depth_1-utm_source=distribute.pc_relevant_t0.none-task-blog-BlogCommendFromMachineLearnPai2-1.control

https://blog.csdn.net/u013032097/article/details/91383546?utm_medium=distribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-1.control&depth_1-utm_source=distribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-1.control

上一篇:nginx正向代理https,zabbix内网实现企业微信告警


下一篇:Nginx极客时间:编译出适合自己的Nginx