无疑,在nginx的核心服务中,http服务占据了相当大的份量。那么,要想多了解nginx多一点,则必须要了解其http模块的工作机制。

  而在上一篇文章中,我们已完全了解了nginx的worker工作机制,以及它是如何接入http服务的,但很明显那很粗,我们需要更深入点理解http模块的工作原理。

  而本身nginx对模块的支持又是复杂的,至少我们认为有两个大方向,正向代理和反向代理。正向代理实际上就是一个http服务器,明显简单些,所以,我们本篇就来说说nginx的正向代理实现吧。

 

0. 整体时序图

  如果你对nginx的http模块工作原理有过深入理解,相信只需要这一张时序图就够。为了节省大家宝贵时,可以先一览宏图。

Nginx(三):http模块的处理流程解析之正向代理

 

1. 异步io事件的交接

  我们知道,nginx的核心是事件io机制的使用,当外部网络io就绪时,内核会回应nginx, 而nginx则会通过accept(), receive(), fd_set 等方法,将事件接入进来,从而转交到http服务模块。其中select模块我们上一篇中已经讲过,此时再简单回顾下:(需要的话)

// event/modules/ngx_select_module.c
// io 事件监听
static ngx_int_t
ngx_select_process_events(ngx_cycle_t *cycle, ngx_msec_t timer,
    ngx_uint_t flags) {
    int                ready, nready;
    ngx_err_t          err;
    ngx_uint_t         i, found;
    ngx_event_t       *ev;
    ngx_queue_t       *queue;
    struct timeval     tv, *tp;
    ngx_connection_t  *c;
    // 获取 max_fd, 系统传值需要
    if (max_fd == -1) {
        for (i = 0; i < nevents; i++) {
            c = event_index[i]->data;
            if (max_fd < c->fd) {
                max_fd = c->fd;
            }
        }

        ngx_log_debug1(NGX_LOG_DEBUG_EVENT, cycle->log, 0,
                       "change max_fd: %i", max_fd);
    }

#if (NGX_DEBUG)
    if (cycle->log->log_level & NGX_LOG_DEBUG_ALL) {
        for (i = 0; i < nevents; i++) {
            ev = event_index[i];
            c = ev->data;
            ngx_log_debug2(NGX_LOG_DEBUG_EVENT, cycle->log, 0,
                           "select event: fd:%d wr:%d", c->fd, ev->write);
        }

        ngx_log_debug1(NGX_LOG_DEBUG_EVENT, cycle->log, 0,
                       "max_fd: %i", max_fd);
    }
#endif

    if (timer == NGX_TIMER_INFINITE) {
        tp = NULL;

    } else {
        tv.tv_sec = (long) (timer / 1000);
        tv.tv_usec = (long) ((timer % 1000) * 1000);
        tp = &tv;
    }

    ngx_log_debug1(NGX_LOG_DEBUG_EVENT, cycle->log, 0,
                   "select timer: %M", timer);

    work_read_fd_set = master_read_fd_set;
    work_write_fd_set = master_write_fd_set;
    // 在此处交由内核进行处理网络事件,epoll 机制,至少有一个事件到来时返回
    // tp 代表是否要超时退出
    ready = select(max_fd + 1, &work_read_fd_set, &work_write_fd_set, NULL, tp);

    err = (ready == -1) ? ngx_errno : 0;

    if (flags & NGX_UPDATE_TIME || ngx_event_timer_alarm) {
        // 事件结束后,先尝试更新gmtTime 时间信息
        ngx_time_update();
    }

    ngx_log_debug1(NGX_LOG_DEBUG_EVENT, cycle->log, 0,
                   "select ready %d", ready);

    if (err) {
        ngx_uint_t  level;

        if (err == NGX_EINTR) {

            if (ngx_event_timer_alarm) {
                ngx_event_timer_alarm = 0;
                return NGX_OK;
            }

            level = NGX_LOG_INFO;

        } else {
            level = NGX_LOG_ALERT;
        }

        ngx_log_error(level, cycle->log, err, "select() failed");

        if (err == NGX_EBADF) {
            ngx_select_repair_fd_sets(cycle);
        }

        return NGX_ERROR;
    }

    if (ready == 0) {
        if (timer != NGX_TIMER_INFINITE) {
            return NGX_OK;
        }

        ngx_log_error(NGX_LOG_ALERT, cycle->log, 0,
                      "select() returned no events without timeout");
        return NGX_ERROR;
    }

    nready = 0;
    // 遍历所有事件
    for (i = 0; i < nevents; i++) {
        ev = event_index[i];
        c = ev->data;
        found = 0;
        // 写事件处理
        if (ev->write) {
            if (FD_ISSET(c->fd, &work_write_fd_set)) {
                found = 1;
                ngx_log_debug1(NGX_LOG_DEBUG_EVENT, cycle->log, 0,
                               "select write %d", c->fd);
            }

        } 
        // 读或accept事件
        else {
            if (FD_ISSET(c->fd, &work_read_fd_set)) {
                found = 1;
                ngx_log_debug1(NGX_LOG_DEBUG_EVENT, cycle->log, 0,
                               "select read %d", c->fd);
            }
        }
        // 读写就绪事件 found 都为1
        if (found) {
            ev->ready = 1;
            ev->available = -1;
            // 如果是 accept 事件则取 ngx_posted_accept_events 队列
            // 否则取 ngx_posted_events 队列
            queue = ev->accept ? &ngx_posted_accept_events
                               : &ngx_posted_events;
            // 将事件插入到相应队列尾部
            ngx_post_event(ev, queue);
            // 有效就绪事件+1
            nready++;
        }
    }
    // 如果两个值不相等,则需要修正下
    if (ready != nready) {
        ngx_log_error(NGX_LOG_ALERT, cycle->log, 0,
                      "select ready != events: %d:%d", ready, nready);

        ngx_select_repair_fd_sets(cycle);
    }

    return NGX_OK;
}
View Code

相关文章:

  • 2021-05-16
  • 2021-10-17
  • 2021-09-21
  • 2022-01-01
  • 2021-05-31
  • 2021-06-07
  • 2022-01-07
猜你喜欢
  • 2022-12-23
  • 2021-07-30
  • 2021-08-03
  • 2022-01-07
  • 2022-01-07
  • 2022-12-23
相关资源
相似解决方案