1、master進程初始化:
nginx是 master-worker多進程模型,程序啓動時首先啓動 master進程,由 master進程根據配置啓動 worker進程,在 master函數中處理代碼如下:
void ngx_master_process_cycle(ngx_cycle_t *cycle) {
// ..
ccf = (ngx_core_conf_t *) ngx_get_conf(cycle->conf_ctx, ngx_core_module);
// 根據配置啓動指定數量的worker進程
ngx_start_worker_processes(cycle, ccf->worker_processes, NGX_PROCESS_RESPAWN);
ngx_start_cache_manager_processes(cycle, 0);
for ( ;; ) {
// ...
}
}
2、啓動n個worker子進程ngx_start_worker_processes:
ngx_start_worker_processes函數會根據配置參數創建指定數量的 worker子進程,函數首先調用 ngx_spawn_process創建好一個 worker子進程。
因爲一個 master父進程下會有很多個 worker子進程,所以 master父進程每創建一個 worker子進程,都需要把剛創建的 worker子進程信息保存在 master父進程和之前已經創建的所有 worker子進程中,這樣才能保持進程間數據一致性。
所以 master進程每創建一個 worker子進程,都會把當前 worker子進程的信息通過 channel進程間通信告知其他 worker子進程(ngx_pass_open_channel函數)。
static void ngx_start_worker_processes(ngx_cycle_t *cycle, ngx_int_t n, ngx_int_t type) {
ngx_int_t i;
ngx_channel_t ch;
ngx_memzero(&ch, sizeof(ngx_channel_t));
// 傳遞給其他進程的命令 打開通信通道
ch.command = NGX_CMD_OPEN_CHANNEL;
// 創建n個子進程
for (i = 0; i < n; i++) {
ngx_spawn_process(cycle, ngx_worker_process_cycle, (void *) (intptr_t) i, "worker process", type);
// 保存當前worker進程的相關信息 ngx_process_slot是全局的最新worker進程下標
ch.pid = ngx_processes[ngx_process_slot].pid;
ch.slot = ngx_process_slot;
ch.fd = ngx_processes[ngx_process_slot].channel[0];
// 現在還是master進程 向已經創建的worker子進程廣播 當前創建的worker子進程 讓所有worker子進程保持信息同步
ngx_pass_open_channel(cycle, &ch);
}
}
3、創建新進程 ngx_spawn_process:
創建子進程時,會調用 ngx_spawn_process函數,函數會根據參數在 ngx_processes數組中找到一個可用的位置存儲新子進程的信息。如果子進程不和父進程分離,會在父子進程間創建 unit socket用於父子進程間通信,目前是父進程發送消息,子進程接收消息。
在 fork子進程後,會執行參數 proc函數,傳入參數 data;如果創建的是 worker子進程,這裏 proc就是 ngx_worker_process_cycle函數。
ngx_pid_t ngx_spawn_process(ngx_cycle_t *cycle, ngx_spawn_proc_pt proc, void *data, char *name, ngx_int_t respawn) {
// ...
if (respawn >= 0) {
// 進程ngx_processes[respawn] 重用該數組內部分進程信息
s = respawn;
} else {
// 在ngx_processes數組中找一個可以使用的位置
for (s = 0; s < ngx_last_process; s++) {
if (ngx_processes[s].pid == -1) {
break;
}
}
if (s == NGX_MAX_PROCESSES) {
return NGX_INVALID_PID;
}
}
if (respawn != NGX_PROCESS_DETACHED) {
if (socketpair(AF_UNIX, SOCK_STREAM, 0, ngx_processes[s].channel) == -1) {
return NGX_INVALID_PID;
}
// ... 設置ngx_processes[s].channel[0][1]的socket屬性
ngx_channel = ngx_processes[s].channel[1];
} else {
// 即將生成的子進程爲NGX_PROCESS_DETACHED類型 不需要和master進程通信 所以channel設置爲-1即可
ngx_processes[s].channel[0] = -1;
ngx_processes[s].channel[1] = -1;
}
ngx_process_slot = s;
pid = fork();
switch (pid) {
case -1:
return NGX_INVALID_PID;
case 0:
// 子進程 調用函數進行處理
ngx_parent = ngx_pid;
ngx_pid = ngx_getpid();
proc(cycle, data);
break;
default:
break;
}
ngx_processes[s].pid = pid;
ngx_processes[s].exited = 0;
// respawn大於0 說明重新該進程 無需設置相關參數
if (respawn >= 0) {
return pid;
}
// ... 設置ngx_processes[s]進程的相關屬性
return pid;
}
4、子進程處理函數 ngx_worker_process_cycle worker:
fork進程後,worker子進程會進行初始化然後進行循環處理客戶端請求。
static void ngx_worker_process_cycle(ngx_cycle_t *cycle, void *data) {
ngx_int_t worker = (intptr_t) data;
ngx_process = NGX_PROCESS_WORKER;
ngx_worker = worker;
ngx_worker_process_init(cycle, worker);
ngx_setproctitle("worker process");
for ( ;; ) {
// ... worker子進程處理信號、請求流程
}
}
5、子進程初始化函數 ngx_worker_process_init:
worker子進程初始化函數主要根據配置設置進程的一些參數。然後調用所有模塊的 init_process初始化進程函數,對所有模塊進行初始化。
因爲 worker子進程創建時繼承了父進程的 全局 ngx_processes數組,所以當前 worker子進程擁有所有 worker子進程的全部信息,這裏關閉除當前 worker子進程外的所有 worker子進程的 channel[0],即關閉其他 worker子進程的監聽socket,保留其他 worker子進程的 channel[1],可以向其他 worker子進程寫入數據。
然後關閉當前 worker子進程的 channel[1],天劍 channel[0]的 epoll監控,等待 master進程向當前 worker子進程發送信號,進行相應處理。
這裏當前 worker進程在創建的時候就已經知道其他 worker子進程的信息了(從 master進程繼承過來的)。如果後續再創建新的 worker子進程的話,會在開始創建 worker子進程的 ngx_start_worker_processes函數中,創建完 worker子進程後,把當前 worker子進程的信息通過 channel發送給已經存在的 所有 worker子進程。這樣保證了進程間信息的一致性。
static void ngx_worker_process_init(ngx_cycle_t *cycle, ngx_int_t worker) {
// ... 根據配置初始化一些基本參數
for (i = 0; cycle->modules[i]; i++) {
if (cycle->modules[i]->init_process) {
if (cycle->modules[i]->init_process(cycle) == NGX_ERROR) {
exit(2);
}
}
}
// 關閉不使用的socket
for (n = 0; n < ngx_last_process; n++) {
if (ngx_processes[n].pid == -1) {
continue;
}
// 跳過當前worker進程
if (n == ngx_process_slot) {
continue;
}
if (ngx_processes[n].channel[1] == -1) {
continue;
}
// 關閉其他worker進程的channel[1] 保留其他worker進程的channel[0] 可以向其他進程寫數據
if (close(ngx_processes[n].channel[1]) == -1) {
ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno, "close() channel failed");
}
}
// 關閉當前worker進程的channel[0] 保留當前worker進程的chanel[1] 監聽本進程數據
if (close(ngx_processes[ngx_process_slot].channel[0]) == -1) {
ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno,"close() channel failed");
}
// 監聽當前worker進程的channel[1]可讀事件 worker進程和master進程通信使用
if (ngx_add_channel_event(cycle, ngx_channel, NGX_READ_EVENT, ngx_channel_handler) == NGX_ERROR) {
exit(2);
}
}