nginx端口複用配置及原理

        前陣子在nginx中配置服務時,發現服務器只對外開放了80端口,若想服務器提供多項服務,就得考慮端口如何複用了。這裏是通過域名也就是server_name字段來區分各項服務的。配置如下:

http {  
     ...
    server {
        listen       80;
        server_name  blog.cn;
        root /home/www/blog;
        ...
    }

    server {
        listen       80;
        server_name  laravel.cn;
        root /home/www/laravel/public;
        ...
    }
}

        上面只是配置的一個簡版,我們也只需要關注這些就夠了。配置了兩個虛擬主機,監聽同一個端口。然後在本地host文件中配置域名:

30.96.xx.xx    blog.cn
39.96.xx.xx    laravel.cn

        39.96.xx.xx是服務器的外網地址,這樣輸入各個域名就能跳轉到對應的服務了。

        到這裏算是實現了端口複用,但是就產生了一個疑問:一般服務器監聽的是套接字,也就是ip地址和端口號,nginx是怎麼識別到域名的呢?以及如果nginx提供的服務過多,查找服務時會不會影響效率呢?下面我們看下原理。

        其實nginx中每起一個監聽的端口號,都會分配一個ngx_http_conf_port_t結構體:

typedef struct {
    //socket地址家族
    ngx_int_t family;
    //監聽端口
    in_port_t port;
    //監聽的端口下對應着所有的ngx_http_conf_addr_t地址
    ngx_array_t addrs;
} ngx_http_conf_port_t;

        看結構體成員可以知道除了有ip地址和端口號,還維護了一個ngx_http_conf_addr_t類型的動態數組。這個動態數組的類型也是一個結構體,定義如下:

typedef struct {
    //監聽套接字的各種屬性
    ngx_http_listen_opt_t opt;
    //完全匹配server_name的散列表
    ngx_hash_t hash;
    
    ...

    //servers動態數組中的成員將指向ngx_http_core_srv_conf_t結構體
    ngx_array_t servers;
} ngx_http_conf_addr_t;

        中間也省去了部分成員,可以看到ngx_http_conf_addr_t結構體重維護了一個servers動態數組,這個數組類型是ngx_http_core_srv_conf_t結構體,而這個結構體與每一個虛擬主機配置是一一對應的,就是說我們每在配置文件中定義一個虛擬主機server{},nginx就會生成一個ngx_http_core_srv_conf_t結構體,並加入到與監聽端口對應的動態數組中。總體示意圖如下:

        再回頭看剛開始的疑問,實際上當開始處理一個http請求時,會拿到http頭部的host值,這個host就存儲了訪問的域名,拿到域名也就是server_name值後,也不是遍歷servers動態數組,因爲如果server{}過多,則會影響效率,http框架是使用了散列表來存放虛擬主機,其中每個元素的keyserver_name字符串,value就是ngx_http_core_srv_conf_t結構體的指針。這樣就能夠快速響應客戶端過來的請求。

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章