四绰疤、nginx啟動(dòng)過(guò)程中的進(jìn)程創(chuàng)建(參考《深入剖析Nginx》)

  1. 通過(guò)前文(《nginx的函數(shù)調(diào)用》),已知nginx啟動(dòng)時(shí)有如下順序:

main --> ngx_master_process_cycle --> ngx_start_worker_processes

大致是先啟動(dòng)主進(jìn)程,再通過(guò)ngx_start_worker_processes啟動(dòng)子進(jìn)程。在main函數(shù)末尾伙判,有如下代碼:

 if (ngx_process == NGX_PROCESS_SINGLE) {
    ngx_single_process_cycle(cycle);
} else {
    ngx_master_process_cycle(cycle);
}

從本段代碼看,如果用戶(hù)沒(méi)有配置單進(jìn)程運(yùn)行的話(huà)值漫,就會(huì)進(jìn)入ngx_master_process_cycle()函數(shù)澳腹。該函數(shù)的參數(shù)cycle是一個(gè)ngx_cycle_s結(jié)構(gòu)體织盼,存儲(chǔ)著許多nginx運(yùn)行需要的全局信息杨何,但在本節(jié)不是重點(diǎn)專(zhuān)注的范圍。

2.下面看一看ngx_master_process_cycle()函數(shù)的內(nèi)容沥邻。該函數(shù)位于 ngx_process_cycle.c中危虱,其中有如下片段:

ccf = (ngx_core_conf_t *) ngx_get_conf(cycle->conf_ctx, ngx_core_module);       
ngx_start_worker_processes(cycle, ccf->worker_processes,NGX_PROCESS_RESPAWN);
ngx_start_cache_manager_processes(cycle, 0);

第一行代碼估計(jì)是獲取配置信息,第二行代碼便是上文nginx啟動(dòng)順序中的ngx_start_worker_processes函數(shù)唐全。該函數(shù)有三個(gè)參數(shù)埃跷,第一個(gè)參數(shù)是ngx_cycle_s結(jié)構(gòu)體,第二個(gè)參數(shù)用于指示要?jiǎng)?chuàng)建的工作進(jìn)程的個(gè)數(shù)邮利,第三個(gè)參數(shù)被定義為:
“#define NGX_PROCESS_RESPAWN -3”
這個(gè)參數(shù)大概是用來(lái)定義進(jìn)程意外終止后是否重啟的一個(gè)常量弥雹,此處不屬于重點(diǎn)關(guān)注的內(nèi)容。

3.關(guān)于ngx_start_worker_processes()函數(shù)延届。該函數(shù)也位于ngx_process_cycle.c中剪勿。其定義很簡(jiǎn)潔:

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_log_error(NGX_LOG_NOTICE, cycle->log, 0, "start worker processes");
ch.command = NGX_CMD_OPEN_CHANNEL;
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);
    }
}

在這個(gè)函數(shù)中,

  • ngx_int_t被定義為:”typedef intptr_t ngx_int_t”方庭。也就是說(shuō)厕吉,ngx_int_t也就是intptr_t類(lèi)型,而intptr_t存在的意義跨平臺(tái)械念,其長(zhǎng)度總是所在平臺(tái)的位數(shù)头朱,作用是用來(lái)存放地址。

  • ngx_channel_t 定義為

    typedef struct {
     ngx_uint_t  command;
     ngx_pid_t   pid;
     ngx_int_t   slot;
     ngx_fd_t    fd;
    } ngx_channel_t;
    

    這是nginx用于進(jìn)程間通信準(zhǔn)備的結(jié)構(gòu)體龄减。

  • for循環(huán)n次项钮,創(chuàng)建n個(gè)子進(jìn)程,也就是參數(shù)ccf->worker_processes個(gè)子進(jìn)程。而具體fork產(chǎn)生子進(jìn)程的代碼烁巫,位于循環(huán)中的ngx_spawn_process方法中鳖敷。

  1. 接下來(lái)就是子進(jìn)程的創(chuàng)建了。ngx_spawn_process函數(shù)也位于ngx_process_cycle.c中程拭,共五個(gè)參數(shù)定踱。其函數(shù)頭定義為:

    ngx_pid_t
    ngx_spawn_process(ngx_cycle_t *cycle, ngx_spawn_proc_pt proc, void *data,
    char *name, ngx_int_t respawn)
    

    其中第二個(gè)參數(shù)是函數(shù)指針,這里傳入了一個(gè)用于處理子進(jìn)程的函數(shù)ngx_worker_process_cycle∈研現(xiàn)在先看看ngx_spawn_process函數(shù)中創(chuàng)建子進(jìn)程的代碼:

     pid = fork();
     switch (pid) {
     case -1:
     ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno,
                  "fork() failed while spawning \"%s\"", name);
     ngx_close_channel(ngx_processes[s].channel, cycle->log);
     return NGX_INVALID_PID;
     case 0:
        ngx_pid = ngx_getpid();
        proc(cycle, data);
        break;
     default:
        break;
    

    定義很清晰崖媚,使用fork產(chǎn)生子進(jìn)程:

    • 若出錯(cuò)則處理錯(cuò)誤。
    • 若為父進(jìn)程則直接退出switch語(yǔ)句恤浪,繼續(xù)往下運(yùn)行畅哑,直到ngx_spawn_process末尾,將子函數(shù)的pid返回水由。
    • 若為子進(jìn)程荠呐,則先獲取pid,然后執(zhí)行 proc(cycle, data),而proc就是上文中傳入ngx_spawn_process的函數(shù)指針ngx_worker_process_cycle砂客。

5.至此泥张,父子進(jìn)程開(kāi)始同時(shí)運(yùn)行。

  • 下面先看看ngx_worker_process_cycle函數(shù)中子進(jìn)程的運(yùn)行模式鞠值,下面ngx_worker_process_cycle函數(shù)的大致結(jié)構(gòu):

     ngx_worker_process_init(cycle, 1);
     #if (NGX_THREADS){
     ...
     }
    #endif
     for ( ;; ) {
      ...//事件處理
     }  
    

    在ngx_worker_process_cycle函數(shù)中媚创,先執(zhí)行了子進(jìn)程的初始化函數(shù),之后會(huì)進(jìn)入無(wú)限for循環(huán)彤恶,在for循環(huán)中進(jìn)行工作钞钙。

  • 而在父進(jìn)程中,將會(huì)結(jié)束ngx_spawn_process声离,返回子進(jìn)程的pid芒炼,回到ngx_start_worker_processes函數(shù)的for循環(huán)中,也就是

    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);
    }
    

    父進(jìn)程在對(duì)子進(jìn)程的信息做一下記錄和處理后术徊,又會(huì)進(jìn)行下一次循環(huán)本刽,產(chǎn)生新的子進(jìn)程,直到產(chǎn)生的子進(jìn)程數(shù)量達(dá)到參數(shù)ccf->worker_processes個(gè)弧关。

6.當(dāng)所有子進(jìn)程創(chuàng)建完畢后盅安,父進(jìn)程將結(jié)束ngx_start_worker_processes,回到ngx_master_process_cycle函數(shù)中世囊,也就是如下代碼段中繼續(xù)運(yùn)行:

ccf = (ngx_core_conf_t *) ngx_get_conf(cycle->conf_ctx, ngx_core_module);       
ngx_start_worker_processes(cycle, ccf->worker_processes,NGX_PROCESS_RESPAWN);
ngx_start_cache_manager_processes(cycle, 0);
...
for ( ;; ) {
...//信號(hào)處理
}

顯然别瞭,父進(jìn)程也進(jìn)入了無(wú)限for循環(huán),在循環(huán)中工作株憾。

7.總結(jié)一下nginx啟動(dòng)時(shí)的進(jìn)程創(chuàng)建過(guò)程蝙寨。從調(diào)用函數(shù)的順序上看晒衩,若配置為只產(chǎn)生一個(gè)工作進(jìn)程,則大致如下:


一個(gè)主進(jìn)程墙歪,一個(gè)工作進(jìn)程
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末听系,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子虹菲,更是在濱河造成了極大的恐慌靠胜,老刑警劉巖,帶你破解...
    沈念sama閱讀 221,888評(píng)論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件毕源,死亡現(xiàn)場(chǎng)離奇詭異浪漠,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)霎褐,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,677評(píng)論 3 399
  • 文/潘曉璐 我一進(jìn)店門(mén)址愿,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人冻璃,你說(shuō)我怎么就攤上這事响谓。” “怎么了省艳?”我有些...
    開(kāi)封第一講書(shū)人閱讀 168,386評(píng)論 0 360
  • 文/不壞的土叔 我叫張陵娘纷,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我拍埠,道長(zhǎng)失驶,這世上最難降的妖魔是什么土居? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 59,726評(píng)論 1 297
  • 正文 為了忘掉前任枣购,我火速辦了婚禮,結(jié)果婚禮上擦耀,老公的妹妹穿的比我還像新娘棉圈。我一直安慰自己,他們只是感情好眷蜓,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,729評(píng)論 6 397
  • 文/花漫 我一把揭開(kāi)白布分瘾。 她就那樣靜靜地躺著,像睡著了一般吁系。 火紅的嫁衣襯著肌膚如雪德召。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 52,337評(píng)論 1 310
  • 那天汽纤,我揣著相機(jī)與錄音上岗,去河邊找鬼。 笑死蕴坪,一個(gè)胖子當(dāng)著我的面吹牛肴掷,可吹牛的內(nèi)容都是我干的敬锐。 我是一名探鬼主播,決...
    沈念sama閱讀 40,902評(píng)論 3 421
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼呆瞻,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼台夺!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起痴脾,我...
    開(kāi)封第一講書(shū)人閱讀 39,807評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤颤介,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后赞赖,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體买窟,經(jīng)...
    沈念sama閱讀 46,349評(píng)論 1 318
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,439評(píng)論 3 340
  • 正文 我和宋清朗相戀三年薯定,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了始绍。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,567評(píng)論 1 352
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡话侄,死狀恐怖亏推,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情年堆,我是刑警寧澤吞杭,帶...
    沈念sama閱讀 36,242評(píng)論 5 350
  • 正文 年R本政府宣布,位于F島的核電站变丧,受9級(jí)特大地震影響芽狗,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜痒蓬,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,933評(píng)論 3 334
  • 文/蒙蒙 一童擎、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧攻晒,春花似錦顾复、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 32,420評(píng)論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至给梅,卻和暖如春假丧,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背动羽。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,531評(píng)論 1 272
  • 我被黑心中介騙來(lái)泰國(guó)打工包帚, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人曹质。 一個(gè)月前我還...
    沈念sama閱讀 48,995評(píng)論 3 377
  • 正文 我出身青樓婴噩,卻偏偏與公主長(zhǎng)得像擎场,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子几莽,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,585評(píng)論 2 359

推薦閱讀更多精彩內(nèi)容