nginx網絡層分析

近來有空閱讀了一下高性能開源http服務器nginx的源代碼,因爲整個代碼有接近10w行,所以只能先分析一下我比較關心的網絡層的連接處理。


首先從主函數main進去,前面的配置初始化先略過,看到如下代碼:

    if (ngx_process == NGX_PROCESS_SINGLE) {
        ngx_single_process_cycle(cycle);

    } else {
        ngx_master_process_cycle(cycle);
    }
一般來說使用多進程進行處理,也就是執行ngx_master_process_cycle(cycle);然後進去函數裏面看到這句代碼:

    ngx_start_worker_processes(cycle, ccf->worker_processes,
                               NGX_PROCESS_RESPAWN);

就是啓動worker子進程,nginx是使用多個worker進程來處理連接,然後有master主進程進行管理的。進入函數裏:

    for (i = 0; i < n; i++) {

        cpu_affinity = ngx_get_cpu_affinity(i);

        ngx_spawn_process(cycle, ngx_worker_process_cycle, NULL,
                          "worker process", type);

        ch.pid = ngx_processes[ngx_process_slot].pid;
        ch.slot = ngx_process_slot;
        ch.fd = ngx_processes[ngx_process_slot].channel[0];

        ngx_pass_open_channel(cycle, &ch);
    }
看到ngx_spawn_process(cycle, ngx_worker_process_cycle, NULL,  "worker process", type);函數,創建若干個worker進程,ngx_worker_process_cycle通過函數指針傳入是worker實際工作的函數。

接着進入ngx_worker_process_cycle函數裏:

#if (NGX_THREADS)
    {
    ngx_int_t         n;
    ngx_err_t         err;
    ngx_core_conf_t  *ccf;

    ccf = (ngx_core_conf_t *) ngx_get_conf(cycle->conf_ctx, ngx_core_module);

    if (ngx_threads_n) {
        if (ngx_init_threads(ngx_threads_n, ccf->thread_stack_size, cycle)
            == NGX_ERROR)
        {
            /* fatal */
            exit(2);
        }

        err = ngx_thread_key_create(&ngx_core_tls_key);
        if (err != 0) {
            ngx_log_error(NGX_LOG_ALERT, cycle->log, err,
                          ngx_thread_key_create_n " failed");
            /* fatal */
            exit(2);
        }

        for (n = 0; n < ngx_threads_n; n++) {

            ngx_threads[n].cv = ngx_cond_init(cycle->log);

            if (ngx_threads[n].cv == NULL) {
                /* fatal */
                exit(2);
            }

            if (ngx_create_thread((ngx_tid_t *) &ngx_threads[n].tid,
                                  ngx_worker_thread_cycle,
                                  (void *) &ngx_threads[n], cycle->log)
                != 0)
            {
                /* fatal */
                exit(2);
            }
        }
    }
    }
#endif

如果進程裏使用多線程的處理方式,調用的是ngx_worker_thread_cycle進行處理。

再看回函數裏面,然後函數進入循環,看到循環裏面的ngx_process_events_and_timers(cycle);函數,裏面就是進程處理各種事件的位置了。進到函數裏看到如下代碼:

    if (ngx_use_accept_mutex) {
        if (ngx_accept_disabled > 0) {
            ngx_accept_disabled--;

        } else {
            if (ngx_trylock_accept_mutex(cycle) == NGX_ERROR) {
                return;
            }

            if (ngx_accept_mutex_held) {
                flags |= NGX_POST_EVENTS;

            } else {
                if (timer == NGX_TIMER_INFINITE
                    || timer > ngx_accept_mutex_delay)
                {
                    timer = ngx_accept_mutex_delay;
                }
            }
        }
    }

這裏是linux2.6以下爲了避免“驚羣”對accept進行上鎖的處理。

得到鎖後就進行accept處理,然後釋放鎖

    if (ngx_posted_accept_events) {
        ngx_event_process_posted(cycle, &ngx_posted_accept_events);
    }

    if (ngx_accept_mutex_held) {
        ngx_shmtx_unlock(&ngx_accept_mutex);
    }

最後處理各種事件(void) ngx_process_events(cycle, timer, flags);

    if (ngx_posted_events) {
        if (ngx_threaded) {
            ngx_wakeup_worker_thread(cycle);

        } else {
            ngx_event_process_posted(cycle, &ngx_posted_events);
        }
    }
至此,基本能看到nginx的整個網絡層大概處理連接的方式,既預分配多個進程同時accept的處理方式。





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