> 백엔드 개발 > PHP 튜토리얼 > 4: 심층적인 Nginx 이벤트 및 연결(1부)

4: 심층적인 Nginx 이벤트 및 연결(1부)

WBOY
풀어 주다: 2016-07-28 08:29:55
원래의
830명이 탐색했습니다.

Nginx는 본질적으로 이벤트 중심 웹 서버입니다. 이벤트 처리 프레임워크가 해결해야 할 문제는 이벤트를 수집, 관리 및 배포하는 방법입니다.
이벤트는 주로

  • 네트워크 이벤트(주로 TCP 네트워크 이벤트)
  • 타이머 이벤트

Nginx는 핵심 모듈 ngx_event_module을 정의합니다. 이 블로그는 Nginx의 모듈성과 전역 보기에 대해 심층적으로 이해하고 있습니다. Nginx가 시작되면 ngx_init_cycle 메서드를 호출하여 구성 파일을 구문 분석합니다. 관심 있는 "events {}" 구성 항목이 nginx.conf에서 발견되면, ngx_event_module 모듈이 작동하기 시작합니다. 핵심 모듈 ngx_event_module의 ngx_event_core_module 모듈은 이 모듈이 사용할 이벤트 기반 메커니즘과 이벤트 관리 방법을 정의합니다.

이벤트 모듈은 새로운 모듈 유형입니다. nginx_module_t는 Nginx 모듈 인터페이스를 나타냅니다. 각 유형의 모듈에 대해 이 인터페이스는 ctx 멤버에 저장됩니다. ngx_module_t 구조의 핵심 모듈의 일반 인터페이스는 ngx_core_module_t이고 이벤트의 일반 인터페이스는 ngx_event_module_t 구조입니다.

<code><span>typedef</span><span>struct</span> {
<span>//位于文件 ngx_event.h</span><span>//事件模块 的名字</span>
    ngx_str_t              *name;
    <span>//在解析 配置前,这个回调 方法用于创建存储配置选项参数的结构体</span><span>void</span>                 *(*create_conf)(ngx_cycle_t *cycle);
    <span>// 在解析配置项完成 之后,init_conf方法会被调用,用以综合处理当前事件模块感兴趣的全部配置项</span><span>char</span>                 *(*init_conf)(ngx_cycle_t *cycle, <span>void</span> *conf);
    <span>// 对于事件驱动机制,每个事件模块需要实现10个抽象方法 </span>
    ngx_event_actions_t     actions;
} ngx_event_module_t;</code>
로그인 후 복사

ngx_event_module_t actions 멤버는 이벤트를 정의하는 핵심 메서드입니다. 구동 모듈.

<code><span>typedef</span><span>struct</span> {
    <span>/* 添加事件方法,它将负责把1个感兴趣 事件添加到操作 系统提供的事件驱动机制 */</span>
    ngx_int_t  (*add)(ngx_event_t *ev, ngx_int_t event, ngx_uint_t flags);
    <span>/*删除事件方法,它将1个已经存在于事件驱动机制中的事件移除 */</span>
    ngx_int_t  (*del)(ngx_event_t *ev, ngx_int_t event, ngx_uint_t flags);
    <span>/*启用 1个 事件,目前事件框架不会调用 这个 方法,大部分事件驱动模块对于该方法的实现都是与上面的add方法完全一致的*/</span>
    ngx_int_t  (*enable)(ngx_event_t *ev, ngx_int_t event, ngx_uint_t flags);
    <span>/*禁用1个事件,目前事件框架不会 调用这个方法 ,大部分事件驱动器对于这个方法的实现与上面的del方法完全一致*/</span>
    ngx_int_t  (*disable)(ngx_event_t *ev, ngx_int_t event, ngx_uint_t flags);
    <span>/*向事件驱动机制中添加一个新的连接,这意味着连接上的读写事件都添加到事件驱动机制中*/</span>
    ngx_int_t  (*add_conn)(ngx_connection_t *c);
    <span>/*从事件驱动机制中移除一个连接的读写事件*/</span>
    ngx_int_t  (*del_conn)(ngx_connection_t *c, ngx_uint_t flags);
    <span>/*仅在多线程环境下会被调用,目前Nginx在产品环境下还不会以多线程方式运行*/</span>
    ngx_int_t  (*notify)(ngx_event_handler_pt handler);
    <span>/*在正常的工作循环中,将调用process_events方法来 处理事件*/</span>
    ngx_int_t  (*process_events)(ngx_cycle_t *cycle, ngx_msec_t timer,
                                 ngx_uint_t flags);
   <span>/*初始化事件驱动模块的方法*/</span>
    ngx_int_t  (*init)(ngx_cycle_t *cycle, ngx_msec_t timer);
    <span>// 退出事件驱动模块前调用的方法</span><span>void</span>       (*done)(ngx_cycle_t *cycle);
} ngx_event_actions_t;</code>
로그인 후 복사

ngx_event_core_module 및 9개의 이벤트 기반 모듈은 ngx_event_module_t 인터페이스

<code><span>struct</span> ngx_event_s {
    <span>/*事件相关的对象,通常data指向ngx_connection_t连接对象。开启文件异步I/O 时,它可能会指向*/</span><span>void</span>            *data;
     <span>/* 标志位,标识事件可写,意味着对应的TCP连接可写,也即连接处于发送网络包状态 */</span><span>unsigned</span>         write:<span>1</span>;
     <span>/* 标志位,标识可建立新的连接,一般是在ngx_listening_t对应的读事件中标记 */</span><span>unsigned</span>         accept:<span>1</span>;
     <span>/*检测当前事件是否是过期的,它仅仅是给驱动模块使用的,而事件消费模块可以不用关心 */</span><span>/* used to detect the stale events in kqueue and epoll */</span><span>unsigned</span>         instance:<span>1</span>;

    <span>/*
     * the event was passed or would be passed to a kernel;
     * in aio mode - operation was posted.
     */</span><span>unsigned</span>         active:<span>1</span>;

    <span>unsigned</span>         disabled:<span>1</span>;

    <span>/* the ready event; in aio mode 0 means that no operation can be posted */</span><span>unsigned</span>         ready:<span>1</span>;

    <span>unsigned</span>         oneshot:<span>1</span>;

    <span>/* aio operation is complete */</span><span>unsigned</span>         complete:<span>1</span>;

    <span>unsigned</span>         eof:<span>1</span>;
    <span>unsigned</span>         error:<span>1</span>;

    <span>unsigned</span>         timedout:<span>1</span>;
    <span>unsigned</span>         timer_set:<span>1</span>;

    <span>unsigned</span>         delayed:<span>1</span>;

    <span>unsigned</span>         deferred_accept:<span>1</span>;

    <span>/* the pending eof reported by kqueue, epoll or in aio chain operation */</span><span>unsigned</span>         pending_eof:<span>1</span>;

    <span>unsigned</span>         posted:<span>1</span>;

    <span>unsigned</span>         closed:<span>1</span>;

    <span>/* to test on worker exit */</span><span>unsigned</span>         channel:<span>1</span>;
    <span>unsigned</span>         resolver:<span>1</span>;

    <span>unsigned</span>         cancelable:<span>1</span>;

<span>#if (NGX_WIN32)</span><span>/* setsockopt(SO_UPDATE_ACCEPT_CONTEXT) was successful */</span><span>unsigned</span>         accept_context_updated:<span>1</span>;
<span>#endif</span><span>#if (NGX_HAVE_KQUEUE)</span><span>unsigned</span>         kq_vnode:<span>1</span>;

    <span>/* the pending errno reported by kqueue */</span><span>int</span>              kq_errno;
<span>#endif</span><span>/*
     * kqueue only:
     *   accept:     number of sockets that wait to be accepted
     *   read:       bytes to read when event is ready
     *               or lowat when event is set with NGX_LOWAT_EVENT flag
     *   write:      available space in buffer when event is ready
     *               or lowat when event is set with NGX_LOWAT_EVENT flag
     *
     * epoll with EPOLLRDHUP:
     *   accept:     1 if accept many, 0 otherwise
     *   read:       1 if there can be data to read, 0 otherwise
     *
     * iocp: TODO
     *
     * otherwise:
     *   accept:     1 if accept many, 0 otherwise
     */</span><span>#if (NGX_HAVE_KQUEUE) || (NGX_HAVE_IOCP)</span><span>int</span>              available;
<span>#else</span><span>unsigned</span>         available:<span>1</span>;
<span>#endif</span>    ngx_event_handler_pt  handler;


<span>#if (NGX_HAVE_IOCP)</span>
    ngx_event_ovlp_t ovlp;
<span>#endif</span>    ngx_uint_t       index;

    ngx_log_t       *<span>log</span>;

    ngx_rbtree_node_t   timer;

    <span>/* the posted queue */</span>
    ngx_queue_t      <span>queue</span>;

<span>#if 0</span><span>/* the threads support */</span><span>/*
     * the event thread context, we store it here
     * if $(CC) does not understand __thread declaration
     * and pthread_getspecific() is too costly
     */</span><span>void</span>            *thr_ctx;

<span>#if (NGX_EVENT_T_PADDING)</span><span>/* event should not cross cache line in SMP */</span>    uint32_t         padding[NGX_EVENT_T_PADDING];
<span>#endif</span><span>#endif</span>
};


<span>#if (NGX_HAVE_FILE_AIO)</span><span>struct</span> ngx_event_aio_s {
    <span>void</span>                      *data;
    ngx_event_handler_pt       handler;
    ngx_file_t                *file;

<span>#if (NGX_HAVE_AIO_SENDFILE)</span>
    ssize_t                  (*preload_handler)(ngx_buf_t *file);
<span>#endif</span>    ngx_fd_t                   fd;

<span>#if (NGX_HAVE_EVENTFD)</span>
    int64_t                    res;
<span>#endif</span><span>#if !(NGX_HAVE_EVENTFD) || (NGX_TEST_BUILD_EPOLL)</span>
    ngx_err_t                  err;
    size_t                     nbytes;
<span>#endif</span>    ngx_aiocb_t                aiocb;
    ngx_event_t                event;
};

<span>#endif</span></code>
로그인 후 복사

Nginx 연결

수동 연결

이러한 종류의 연결은 클라이언트가 시작하고 서버가 수동적으로 수락하는 연결을 의미합니다

<code><span>//在 文件ngx_connection.h中</span><span>struct</span> ngx_connection_s {
  <span>/*  连接未使用时,data成员用于充当连接池中空闲链表中的next指针。当连接被使用时,data的意义由使用它的Nginx模块而定。在HTTP模块中,data指向ngx_http_request_t请求*/</span><span>void</span>               *data;
    <span>// 连接对应的读事件 </span>
    ngx_event_t        *read;
    <span>// 连接对应的写事件 </span>
    ngx_event_t        *write;
    <span>// 套接字句柄 </span>
    ngx_socket_t        fd;
    <span>//直接接收网络字符流的方法</span>
    ngx_recv_pt         recv;
    <span>// 直接发送网络字符流的办法</span>
    ngx_send_pt         send;
    <span>// 以ngx_chain_t链表为 参数来 接收 网络 字符流的方法 </span>
    ngx_recv_chain_pt   recv_chain;
    <span>// 以ngx_chain_t链表为 参数来 发送 网络 字符流的方法 </span>
    ngx_send_chain_pt   send_chain;
    <span>/*这个连接对应的ngx_listening_t监听对象,此连接由listening监听端口的事件建立*/</span>
    ngx_listening_t    *listening;
    <span>//这个连接上已经发送出去的字节数</span>
    off_t               sent;
    <span>// 可以记录日志的ngx_log_t对象</span>
    ngx_log_t          *<span>log</span>;
    <span>/* 内存池。一般在accept一个新连接时,会创建一个 内存池,而在这个 连接结束时会销毁内存池。所有的ngx_connectionn_t结构 体都是预分配,这个内存池的大小将由上面的listening 监听对象中的 pool_size成员决定*/</span>
    ngx_pool_t         *pool;

    <span>int</span>                 type;
    <span>// 连接客户端的sockaddr结构体</span><span>struct</span> sockaddr    *sockaddr;
    <span>// 连接 sockaddr结构体的 长度</span>
    socklen_t           socklen;
    <span>// 连接客户端字符串形式的IP地址</span>
    ngx_str_t           addr_text;

    ngx_str_t           proxy_protocol_addr;

    in_port_t           proxy_protocol_port;

<span>#if (NGX_SSL)</span>
    ngx_ssl_connection_t  *ssl;
<span>#endif</span><span>/*本机监听端口 对应 的sockaddr结构 体 ,也就是listening监听对象中的sock
    addr成员*/</span><span>struct</span> sockaddr    *local_sockaddr;
    socklen_t           local_socklen;
     <span>/*用于接收、缓存客户端 发来的字节流,每个事件消费模块可自由决定从连接池中分配多大空间给 buffer这个 缓存字段*/</span>
    ngx_buf_t          *buffer;

    ngx_queue_t         <span>queue</span>;
    <span>// 连接使用次数。ngx_connection_t结构体每次建立一条来自客户端的连接,或者主动向后端服务器发起连接时,number都会加1*/</span>
    ngx_atomic_uint_t   number;
    <span>// 处理 请求次数</span>
    ngx_uint_t          requests;

    <span>unsigned</span>            buffered:<span>8</span>;

    <span>unsigned</span>            log_error:<span>3</span>;     <span>/* ngx_connection_log_error_e */</span><span>unsigned</span>            timedout:<span>1</span>;
    <span>unsigned</span>            error:<span>1</span>;
    <span>unsigned</span>            destroyed:<span>1</span>;

    <span>unsigned</span>            idle:<span>1</span>;
    <span>unsigned</span>            reusable:<span>1</span>;
    <span>unsigned</span>            close:<span>1</span>;
    <span>unsigned</span>            shared:<span>1</span>;

    <span>unsigned</span>            sendfile:<span>1</span>;
    <span>unsigned</span>            sndlowat:<span>1</span>;
    <span>unsigned</span>            tcp_nodelay:<span>2</span>;   <span>/* ngx_connection_tcp_nodelay_e */</span><span>unsigned</span>            tcp_nopush:<span>2</span>;    <span>/* ngx_connection_tcp_nopush_e */</span><span>unsigned</span>            need_last_buf:<span>1</span>;

<span>#if (NGX_HAVE_IOCP)</span><span>unsigned</span>            accept_context_updated:<span>1</span>;
<span>#endif</span><span>#if (NGX_HAVE_AIO_SENDFILE)</span><span>unsigned</span>            busy_count:<span>2</span>;
<span>#endif</span><span>#if (NGX_THREADS)</span>
    ngx_thread_task_t  *sendfile_task;
<span>#endif</span>
};</code>
로그인 후 복사
능동 연결

웹 서버로서 Nginx는 활성 연결을 나타내기 위해

구조를 사용하여 다른 서버에 대한 연결도 시작해야 합니다. 대기 중인 연결의 많은 특성은 수동 연결 ngx_connection_t에 정의되어 있으므로 ngx_peer_connection_t 구조는 ngx_connection_t를 참조합니다. 구조. ngx_peer_connection_t

<code><span>// 当使用长连接与上游服务器通信时,可通过该方法由连接池获取 一个新的连接</span><span>typedef</span> ngx_int_t (*ngx_event_get_peer_pt)(ngx_peer_connection_t *pc,
    <span>void</span> *data);
<span>// 当 使用长连接与上游服务器通信时,通过该方法 将使用完毕 的连接释放给连接池</span><span>typedef</span><span>void</span> (*ngx_event_free_peer_pt)(ngx_peer_connection_t *pc, <span>void</span> *data,
    ngx_uint_t state);
<span>struct</span> ngx_peer_connection_s {
    <span>/*一个主动连接实际 上也需要ngx_connection_t结构体的大部分成员,并且处于重用的考虑 而定义 了connecion*/</span>
    ngx_connection_t                *connection;
    <span>// 远端服务器的socketaddr</span><span>struct</span> sockaddr                 *sockaddr;
    <span>// sockaddr地址长度</span>
    socklen_t                        socklen;
    <span>// 远端服务器的名称 </span>
    ngx_str_t                       *name;
    <span>// 表示在连接 一个 远端服务器,当前连接出现 异常失败后可以重试的次数,也就是允许的最多失败的次数</span>
    ngx_uint_t                       tries;
    ngx_msec_t                       start_time;

    ngx_event_get_peer_pt            get;
    ngx_event_free_peer_pt           <span>free</span>;
    <span>void</span>                            *data;

<span>#if (NGX_SSL)</span>
    ngx_event_set_peer_session_pt    set_session;
    ngx_event_save_peer_session_pt   save_session;
<span>#endif</span><span>// 本机地址信息 </span>
    ngx_addr_t                      *local;

    <span>int</span>                              type;
    <span>// 套接字的接收缓冲区大小</span><span>int</span>                              rcvbuf;
    <span>// 记录日志的ngx_log_t对象</span>
    ngx_log_t                       *<span>log</span>;

    <span>unsigned</span>                         cached:<span>1</span>;
<span>#if (NGX_HAVE_TRANSPARENT_PROXY)</span><span>unsigned</span>                         transparent:<span>1</span>;
<span>#endif</span><span>/* ngx_connection_log_error_e */</span><span>unsigned</span>                         log_error:<span>2</span>;
};</code>
로그인 후 복사
').addClass('pre-numbering').hide(); $(this).addClass('has-numbering').parent().append($numbering); for (i = 1; i ').text(i)); }; $numbering.fadeIn(1700); }); }); 위에서 내용의 측면을 포함하여 4부: 심층적인 Nginx 이벤트 및 연결(1부)을 소개했습니다. PHP 튜토리얼에 관심이 있는 친구들에게 도움이 되기를 바랍니다.

관련 라벨:
원천:php.cn
본 웹사이트의 성명
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.
인기 튜토리얼
더>
최신 다운로드
더>
웹 효과
웹사이트 소스 코드
웹사이트 자료
프론트엔드 템플릿