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结构体,并加入到与监听端口对应的动态数组中。总体示意图如下:

nginx端口复用配置及原理_第1张图片

        再回头看刚开始的疑问,实际上当开始处理一个http请求时,会拿到http头部的host值,这个host就存储了访问的域名,拿到域名也就是server_name值后,也不是遍历servers动态数组,因为如果server{}过多,则会影响效率,http框架是使用了散列表来存放虚拟主机,其中每个元素的keyserver_name字符串,value就是ngx_http_core_srv_conf_t结构体的指针。这样就能够快速响应客户端过来的请求。

 

 

你可能感兴趣的:(运维)