91超碰碰碰碰久久久久久综合_超碰av人澡人澡人澡人澡人掠_国产黄大片在线观看画质优化_txt小说免费全本

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

Tengine怎么查找server塊

發布時間:2021-07-30 15:39:07 來源:億速云 閱讀:104 作者:chen 欄目:云計算

這篇文章主要講解了“Tengine怎么查找server塊”,文中的講解內容簡單清晰,易于學習與理解,下面請大家跟著小編的思路慢慢深入,一起來研究和學習“Tengine怎么查找server塊”吧!

概述

本文的目標讀者是Tengine/Nginx 研發或者運維同學,如果自己對這塊邏輯非常清楚,那可以略過,如果在配置或者開發 Tengine/Nginx 過程中,有如下疑問的同學,本文或許能解答你多年的疑惑:

  1. 請求到達匹配的是哪個 server 塊?

  2. 為啥明明配置了 server 塊,還是沒有生效?

  3. 沒有這個域名的 server 塊,請求到底使用了哪個 server 塊?

  4. 要自己去匹配 server 塊的話,該從哪里入手? 
    ……

等等此類 server 塊有關的問題,在使用 Tengine 時可能經常有遇到,在配置的 server 塊較少時,比較容易識別出,但在 CDN 或者云平臺接入層這種場景下,配置的 server 塊一般都非常多,少的有幾十上百個,多的成千上萬個都有可能,所以了解 Tengine 如何查找 server 塊非常有利于日常問題排查。

配置

先來看看幾個配置:

server {    listen       10.101.192.91:80 default_server;    listen       80 default_server;    listen       8080 default_server;    server_name  www.aa.com;    default_type  text/plain;    location / {        return 200 "default-server: $server_name, host: $host";
    }
}server {    listen       10.101.192.91:80;    server_name  www.bb.com;    default_type  text/plain;    location / {        return 200 "80server: $server_name, host: $host";
    }
}server {    listen       10.101.192.91:8080;    server_name  *.bb.com;    default_type  text/plain;    location / {        return 200 "8080server: $server_name, host: $host";
    }
}server {    listen       10.101.192.91:8080;    server_name  www.bb.com;    default_type  text/plain;    location / {        return 200 "8080server: $server_name, host: $host";
    }
}

上面配置了四個 server 塊,配置也非常簡單,第一個 server 塊配置了 default_server 參數,這個表明了這個是默認 server 塊的意思(準確地說是這個 listen 的 IP:Port 進來的請求默認 server 塊),監聽了兩個端口80和8080,匹配域名為  www.aa.com,第二個是監聽了 10.101.192.91:80 和匹配域名為 www.bb.com 的 server 塊,第三個是監聽了 10.101.192.91:8080 和匹配泛域名 *.bb.com 的 server 塊,第四個是監聽了 10.101.192.91:8080 和匹配精確域名  www.bb.com 的 server 塊。下面來驗證一下:  
Tengine怎么查找server塊
可以看出:

  1. 127.0.0.1:80 和 127.0.0.1:8080 都訪問到了第一個 server 塊

    • 這是因為第一個 server 監聽了  :80 和 :8080 端口,其他 server 塊沒有監聽 127.0.0.1 相應的端口,127.0.0.1 的訪問只能匹配第一個 server 塊。

  2. 10.101.192.91:80 的訪問,域名和 server 塊匹配時使用了相應的 server 塊,不匹配時使用了第一個默認 server 塊

    • IP:Port 匹配的情況下,再匹配到域名所在的 server 塊,域名跟 server_name 不匹配則匹配默認 server 塊。

  3. 10.101.192.91:8080 的訪問,域名先精確匹配到了  www.bb.com 的 server 塊,然后再匹配到了泛域名 *.bb.com 的 server 塊,不匹配時使用了第三個隱式默認 server 塊

    • 這里涉及到泛域名和隱式默認 server 塊,泛域名的匹配是在精確域名之后,這個也比較好理解,隱式默認 server 塊是沒有在 listen 后面指定 default_server 參數的 server 塊, Tengine/Nginx 在解析配置時,每個 IP:Port 都有一個默認 server 塊,如果 listen 后面顯式指定了 default_server 參數則該 listen 所在的 server 就是這個 IP:Port 的默認 server 塊,如果沒有顯式指定 default_server 參數則該 IP:Port 的第一個 server 塊就是隱式默認 server 塊。

上面這些配置可以衍生出一些 debug 技巧:

if ($http_x_alicdn_debug_get_server = "on") {    return 200 "$server_addr:$server_port, server_name: $server_name";
}

只要帶上請求頭  X-Alicdn-Debug-Get-Server: on 即可知道請求命中的是哪個 server 塊,這個配置對 server 塊非常多的系統 debug 非常有用,需要注意的是這個配置需要放到一個配置文件和用 server_auto_include 加載,然后 tengine 會自動在所有 server 塊生效(nginx 沒有類似的配置命令)。

數據結構

我們再來看看 http 核心模塊 server 塊的配置在數據結構上怎么關聯的,其數據結構是:

typedef struct {    /* array of the ngx_http_server_name_t, "server_name" directive */
    ngx_array_t                 server_names;    /* server ctx */
    ngx_http_conf_ctx_t        *ctx;
    u_char                     *file_name;    ngx_uint_t                  line;    ngx_str_t                   server_name;#if (T_NGX_SERVER_INFO)
    ngx_str_t                   server_admin;#endif
    size_t                      connection_pool_size;    size_t                      request_pool_size;    size_t                      client_header_buffer_size;    ngx_bufs_t                  large_client_header_buffers;    ngx_msec_t                  client_header_timeout;    ngx_flag_t                  ignore_invalid_headers;    ngx_flag_t                  merge_slashes;    ngx_flag_t                  underscores_in_headers;    unsigned                    listen:1;#if (NGX_PCRE)
    unsigned                    captures:1;#endif
    ngx_http_core_loc_conf_t  **named_locations;
} ngx_http_core_srv_conf_t;

這里不細說這些字段是干嘛用的,主要看 ngx_http_core_srv_conf_t 怎么與其他數據結構關聯,從上面的配置可以知道 server 是與 IP:Port 有關聯的,在 tengine/nginx 里的關系如下:

typedef struct {    ngx_http_listen_opt_t      opt;    ngx_hash_t                 hash;    ngx_hash_wildcard_t       *wc_head;    ngx_hash_wildcard_t       *wc_tail;#if (NGX_PCRE)
    ngx_uint_t                 nregex;    ngx_http_server_name_t    *regex;#endif
    /* the default server configuration for this address:port */
    ngx_http_core_srv_conf_t  *default_server;    ngx_array_t                servers;  /* array of ngx_http_core_srv_conf_t */} ngx_http_conf_addr_t;

可以看出,IP:Port 的核心數據結構 ngx_http_conf_addr_t 里面有默認 server 塊 default_server,以及該 IP:Port 關聯的所有 server 塊數組 servers,其他幾個字段不細展開了。tengine 把所有的 IP:Port 按 Port 拆分后將  ngx_http_conf_addr_t 放到了 ngx_http_conf_port_t 里面了:

typedef struct {    ngx_int_t                  family;    in_port_t                  port;    ngx_array_t                addrs;     /* array of ngx_http_conf_addr_t */} ngx_http_conf_port_t;

為什么將 IP:Port 拆分呢,這是因為 listen 的 Port 如果沒有指定 IP,比如  listen 80; ,那 tengine/nginx 在創建監聽 socket 時的地址是 0.0.0.0 ,如果還有其他配置 listen 了精確 ip 和端口,比如  listen 10.101.192.91:80; ,那在內核是沒法創建這個 socket 的,第2節配置里面的幾個 listen 在內核是這樣監聽的: 
image.png
雖然 listen 了 80 和 10.101.192.91:80,但在內核都是 0.0.0.0:80,所以 tengine 需要用  ngx_http_conf_port_t 來記錄該端口的所有精確地址。但這個結構只是使用在配置階段,在監聽 socket 時轉換成了結構  ngx_http_port_t 和  ngx_http_in_addr_t(這是因為 ip:port 和 server 塊是多對多的關系,需要重新組織和優化):

typedef struct {    /* ngx_http_in_addr_t or ngx_http_in6_addr_t */
    void                      *addrs;    ngx_uint_t                 naddrs;
} ngx_http_port_t;typedef struct {    in_addr_t                  addr;    ngx_http_addr_conf_t       conf;
} ngx_http_in_addr_t;
typdef  ngx_http_addr_conf_s ngx_http_addr_conf_t;struct ngx_http_addr_conf_s {    /* the default server configuration for this address:port */
    ngx_http_core_srv_conf_t  *default_server;    ngx_http_virtual_names_t  *virtual_names;    unsigned                   ssl:1;    unsigned                   http2:1;    unsigned                   proxy_protocol:1;
};

其中, ngx_http_port_t 記錄了該端口的所有精確地址和對應的 server 塊。而  ngx_http_port_t 放到了監聽的 socket 核心結構 ngx_listening_t 中:

typedef struct ngx_listening_s  ngx_listening_t;struct ngx_listening_s {    ngx_socket_t        fd;    struct sockaddr    *sockaddr;    socklen_t           socklen;    /* size of sockaddr */
    size_t              addr_text_max_len;    ngx_str_t           addr_text;    // 省略……
    /* handler of accepted connection */
    ngx_connection_handler_pt   handler;    void               *servers;  /* array of ngx_http_in_addr_t, for example */
    // 省略……};struct ngx_connection_s {    // 省略……
    ngx_listening_t    *listening;    // 省略……};

所以一個連接可以從 c->listening->servers 來查找匹配的 server 塊。

tengine 中 ip:port 和 server 的大體關聯關系如下:  
Tengine怎么查找server塊
(可以通過這個圖來理解一下 tengine 如何查找 server 塊)

從請求到 server 塊

上面講了 ip:port 和 server 的一些關系和核心數據結構,這一節來講講 tengine 從處理請求到匹配 server 的邏輯。ngx_http_init_connection 是初始化連接的函數,在這個函數里面我們看到有這樣的邏輯:

void
ngx_http_init_connection(ngx_connection_t *c)
{    // 省略……
    ngx_http_port_t        *port;
    ngx_http_in_addr_t     *addr;
    ngx_http_connection_t  *hc;    // 省略……
    /* find the server configuration for the address:port */
    port = c->listening->servers;    if (port->naddrs > 1) {            // 省略……
            sin = (struct sockaddr_in *) c->local_sockaddr;
            addr = port->addrs;            /* the last address is "*" */
            for (i = 0; i < port->naddrs - 1; i++) {                if (addr[i].addr == sin->sin_addr.s_addr) {                    break;
                }
            }
            hc->addr_conf = &addr[i].conf;            // 省略……
    } else {            // 省略……
            addr = port->addrs;
            hc->addr_conf = &addr[0].conf;            // 省略……
    }    /* the default server configuration for the address:port */
    hc->conf_ctx = hc->addr_conf->default_server->ctx;    // 省略……}

可以看出,初始化時,拿到了 socket 的 ip:port 后去匹配了最合適的配置,存到了 hc->addr_conf 指針中,這個就是上面講到的數據結構  ngx_http_addr_conf_t 指針,這里面存了該 ip:port 關聯的所有 server 塊核心配置,在之后收到 HTTP 請求頭處理請求行或者處理 Host 頭時,再根據域名去 hc->addr_conf 里面匹配出真實的 server 塊:

static ngx_int_t
ngx_http_set_virtual_server(ngx_http_request_t *r, ngx_str_t *host)
{    // 省略……
    ngx_http_connection_t     *hc;
    ngx_http_core_srv_conf_t  *cscf;    // 省略……
    hc = r->http_connection;    // 省略……
    rc = ngx_http_find_virtual_server(r->connection,
                                      hc->addr_conf->virtual_names,
                                      host, r, &cscf);    //創建 r 時,r->srv_conf 和 r->loc_conf 是 hc->conf_ctx 的默認配置
    //查不到匹配的 server 塊則不需要設置 r->srv_conf 和 r->loc_conf
    if (rc == NGX_DECLINED) {        return NGX_OK;
    }    // 查到匹配的 server,使用真實 server 塊的配置
    r->srv_conf = cscf->ctx->srv_conf;
    r->loc_conf = cscf->ctx->loc_conf;    // 省略……}

函數  ngx_http_find_virtual_server 是查找域名對應的 server 塊接口(這個函數還有另一個地方調用是在處理 SSL 握手遇到 SNI 時,這是因為在握手時也需要找到匹配的 server 塊里面配置的證書)。 
至此,server 塊配置的查找邏輯結束,后續其他模塊處理時可以從 r->srv_conf 和 r->loc_conf 查到自己模塊的 server/location 塊配置了。

感謝各位的閱讀,以上就是“Tengine怎么查找server塊”的內容了,經過本文的學習后,相信大家對Tengine怎么查找server塊這一問題有了更深刻的體會,具體使用情況還需要大家實踐驗證。這里是億速云,小編將為大家推送更多相關知識點的文章,歡迎關注!

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

瑞安市| 兴宁市| 乌拉特中旗| 临潭县| 河源市| 特克斯县| 平山县| 嘉峪关市| 和田市| 德化县| 布尔津县| 泗洪县| 景谷| 鹿邑县| 渭源县| 兴文县| 盘锦市| 弋阳县| 察隅县| 土默特右旗| 增城市| 灵武市| 博客| 专栏| 东辽县| 黑河市| 陵川县| 肥西县| 宁武县| 芷江| 美姑县| 富宁县| 即墨市| 涟水县| 和林格尔县| 天祝| 介休市| 同仁县| 晋江市| 苏尼特左旗| 平罗县|