近來有空閱讀了一下高性能開源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的處理方式。