资讯专栏INFORMATION COLUMN

【Nginx源码分析】Nginx的listen处理流程分析

yuanzhanghu / 983人阅读

摘要:四监听套接字的使用假设此处我们使用作为事件处理模块在增加事件时用户可以使用中的字段当事件发生时该字段也会带回。在创建监听套接字时将结构分为级监听套接字地址各级都是一对多的关系。

施洪宝

一. 基础

nginx源码采用1.15.5

后续部分仅讨论http中的listen配置解析以及优化流程

1.1 概述

假设nginx http模块的配置如下

http{
    server {
        listen 127.0.0.1:8000;
        server_name www.baidu.com;
        root html;
        location /{
            index index.html;
        }
    }
    server {
        listen 10.0.1.1:8000;
        server_name www.news.baidu.com;
        root html;
        location /{
            index index.html;
        }
    }
    server {
        listen 8000; #相当于0.0.0.0:8000
        server_name www.tieba.baidu.com;
        root html;
        location /{
            index index.html;
        }
    }
    server {
        listen 127.0.0.1:8000;
        server_name www.zhidao.baidu.com;
        location / {
            root html;
            index index.html;
        }
    }
}

端口, 地址, server的关系


端口是指一个端口号, 例如上面的8000端口

地址是ip+port, 例如127.0.0.1:8000, 10.0.1.1:8000, 0.0.0.0:8000, listen后配置的是一个地址。

每个地址可以放到多个server中, 例如上面的127.0.0.1:8000

总而言之, 一个端口可以有多个地址, 每个地址可以有多个server

1.2 存在的问题

是否需要在读取完http块中所有的server才能建立监听套接字, 绑定监听地址?

是的, 因为允许配置通配地址, 故而必须将http块中的server全部读取完后, 才能知道如何建立监听套接字。

一个端口可以对应多个地址, 如何建立监听套接字, 如何绑定地址?

通常情况下, 每个地址只能绑定一次(只考虑tcp协议), 这种情况下, 我们只能选择部分地址创建监听套接字, 绑定监听地址。

当配置中存在通配地址(0.0.0.0:port)时, 只需要创建一个监听套接字, 绑定这个通配地址即可, 但需要能够依据该监听套接字找到该端口配置的其他地址, 这样当客户端发送请求时, 可以根据客户端请求的地址, 找到对应地址下的相关配置。

当配置中不存在通配地址时, 需要对每个地址都创建一个监听套接字, 绑定监听地址。

一个地址多个server的情况下, 如何快速找到客户端请求的server?

比较合适的方案是通过hash表。

为了快速找到客户端请求的server, nginx以server_name为key, 每个server块的配置(可以理解为一个指针, 该指针指向整个server块的配置)为value, 放入到哈希表。

由于server_name中可以出现正则匹配等情况, nginx将server_name具体分为4类进行分别处理(www.baidu.com, *baidu.com, www.baidu*, ~*baidu)。

1.3 nginx listen解析的流程

总体而言分为2步,

将所有http模块内的配置解析完成, 将listen的相关配置暂存(主要存储监听端口以及监听地址)。

根据上一步暂存的监听端口以及监听地址, 创建监听套接字, 绑定监听地址

二. 配置解析

nginx http块解析完成后, 会存储配置文件中配置的监听端口以及监听地址, 其核心结构图如下,

总体而言, 结构可以分为3级, 端口->地址->server

2.1 源码

listen的处理流程:

ngx_http_core_listen: 读取配置文件配置

ngx_http_add_listen: 查看之前是否出现过当前监听的端口, 没有则新建, 否则追加

ngx_http_add_address: 查看之前该端口下是否监听过该地址, 没有则新建, 否则追加。

ngx_http_add_server: 查看server之前是否出现过, 没有则新建, 否则报错(重复定义)。

三. 创建监听套接字

nginx最终创建的监听套接字及其相关的结构图如下,


每个ngx_listening_t结构对应一个监听套接字, 绑定一个监听地址

每个ngx_listening_t结构后面需要存储地址信息, 地址可能不止一个, 因为这个监听套接字可能绑定的是通配地址, 这个端口下的其他地址都会放在这个监听套接字下。例如, 1.1节的配置中, 只会创建一个ngx_listening_t结构, 其他地址的配置都会放到这个通配地址下。

每个监听地址可能对应多个域名(配置文件中的server_name), 需要将这些域名放到哈希表中, 以供后续使用

总体而言, 结构分为3级, 监听套接字->监听地址->server

3.1 源码

读取完http块后, 需要创建监听套接字绑定监听地址, 处理函数ngx_http_optimize_servers, 该函数的处理流程:

遍历所有监听端口, 针对每个监听端口, 执行以下3步

对该端口下所有监听地址排序(listen后配置bind的放在前面, 通配地址放在后面)

遍历该端口下的所有地址, 将每个地址配置的所有server, 放到该地址的哈希表中。

为该端口建立监听套接字, 绑定监听地址。

四. 监听套接字的使用

假设此处我们使用epoll作为事件处理模块

epoll在增加事件时, 用户可以使用epoll_event中的data字段, 当事件发生时, 该字段也会带回。

nginx中的epoll_event指向的是ngx_connection_t结构, 事件发生时, 调用ngx_connection_t结构中的读写事件, 负责具体处理事件, 参见下图。

//c is ngx_connection_t
rev = c->read;
rev->hadler(rev);
wev = c->write;
wev->handler(wev);

每个监听套接字对应一个ngx_connection_t, 该结构的读事件回调函数为ngx_event_accept, 当用户发起tcp握手时, 通过ngx_event_accept接受客户端的连接请求。

ngx_event_accept会接受客户端请求, 初始化一个新的ngx_connection_t结构, 并将其加入到epoll中进行监听, 最后会调用ngx_connection_t对应的ngx_listening_t的处理函数(http块对应ngx_http_init_connection, mail块ngx_mail_init_connection, stream块对应ngx_stream_init_connection)

五. 总结

nginx在读取listen相关的配置时, 将结构分为3级, 端口->地址->server, 各级都是一对多的关系。

nginx在创建监听套接字时, 将结构分为3级, 监听套接字->地址->server, 各级都是一对多的关系。

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/40187.html

相关文章

  • [转载] PHP升级导致系统负载过高问题分析

    摘要:分析的结果,发现内存,基本没有什么大的变化,网卡流量明显降低,上下文切换明显升高。网卡流量降低可以理解,因为当前系统已不能正常返回响应,但上下文切换升高却不知道什么原因。 原文:http://chuansongme.com/n/797172 背景 据XX部门兄弟反应, 其在将PHP从5.3.8 升级到5.5.13 时, 开始运行正常, 运行一段时间后, 系统负载变高,达到200%以...

    mmy123456 评论0 收藏0
  • [转载] PHP升级导致系统负载过高问题分析

    摘要:分析的结果,发现内存,基本没有什么大的变化,网卡流量明显降低,上下文切换明显升高。网卡流量降低可以理解,因为当前系统已不能正常返回响应,但上下文切换升高却不知道什么原因。 原文:http://chuansongme.com/n/797172 背景 据XX部门兄弟反应, 其在将PHP从5.3.8 升级到5.5.13 时, 开始运行正常, 运行一段时间后, 系统负载变高,达到200%以...

    awokezhou 评论0 收藏0
  • Nginx源码分析Nginx中http2浅析

    摘要:主要涉及到的协议以及的处理流程。并且中必须建立在协议之上。所以对协议的服务发起请求时,一般浏览器会建立条连接,并行的去请求不同的资源。表明该字段是否使用了编码。 运营研发 张仕华 本文通过一个小例子串一遍nginx处理http2的流程。主要涉及到http2的协议以及nginx的处理流程。 http2简介 http2比较http1.1主要有如下五个方面的不同: 二进制协议 http1....

    孙吉亮 评论0 收藏0
  • docker进阶,nginx部署几个重要点详解以及开发流程---持续更新

    摘要:无论这个连接是外部主动建立的,还是内部建立的。协议有表示层数据的表示安全压缩。在整个发展过程中的所有思想和着重点都以一种称为的文档格式存在。 部署基础知识url:协议://网站地址:端口(/)路径地址?参数eg: http://www.baidu.com:80/abc/dd/ www.baidu.com找服务器 80端口:找服务器上提供服务的应用 nginx uri:/ab...

    KunMinX 评论0 收藏0
  • docker进阶,nginx部署几个重要点详解以及开发流程---持续更新

    摘要:无论这个连接是外部主动建立的,还是内部建立的。协议有表示层数据的表示安全压缩。在整个发展过程中的所有思想和着重点都以一种称为的文档格式存在。 部署基础知识url:协议://网站地址:端口(/)路径地址?参数eg: http://www.baidu.com:80/abc/dd/ www.baidu.com找服务器 80端口:找服务器上提供服务的应用 nginx uri:/ab...

    ytwman 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<