• <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>

            那誰(shuí)的技術(shù)博客

            感興趣領(lǐng)域:高性能服務(wù)器編程,存儲(chǔ),算法,Linux內(nèi)核
            隨筆 - 210, 文章 - 0, 評(píng)論 - 1183, 引用 - 0
            數(shù)據(jù)加載中……

            Nginx0.7.61代碼分析(二)--worker子進(jìn)程之間的負(fù)載均衡

            緊跟著上一節(jié)所講的,Nginx里面worker子進(jìn)程之間相互獨(dú)立,各自接收新的連接,接收數(shù)據(jù)報(bào)文,處理請(qǐng)求,等等。

            但是,由于監(jiān)聽(tīng)socket是由父進(jìn)程創(chuàng)建的,所以在子進(jìn)程調(diào)用accept函數(shù)接收新的連接時(shí)可能會(huì)出現(xiàn)所謂的驚群(thundering herd), 其實(shí)這個(gè)現(xiàn)象即使出現(xiàn),我個(gè)人認(rèn)為對(duì)性能的影響也不會(huì)太大,不就是一次accept操作失敗么。另外呢,子進(jìn)程之間雖然是獨(dú)立工作的,但是,也可能出現(xiàn)不同的子進(jìn)程之間負(fù)載不均衡的情況,比如某些子進(jìn)程處理1000個(gè)連接,有的子進(jìn)程處理100個(gè)連接,差了十倍。

            Nginx里面,針對(duì)上面提到的兩點(diǎn),對(duì)程序進(jìn)行了一些優(yōu)化。來(lái)看看ngx_process_events_and_timers 函數(shù)里面的代碼,這個(gè)函數(shù)是worker子進(jìn)程中服務(wù)器主循環(huán)每次循環(huán)都會(huì)調(diào)用的函數(shù):

                // 如果使用了accept mutex 
               
            if (ngx_use_accept_mutex) {
                    // 如果當(dāng)前禁止accept操作的計(jì)數(shù)還大于0
                    
            if (ngx_accept_disabled > 0) {
                        // 將這個(gè)計(jì)數(shù)減一
                        ngx_accept_disabled
            --;

                    } 
            else {
                        // 嘗試獲取accept鎖
                        
            if (ngx_trylock_accept_mutex(cycle) == NGX_ERROR) {
                            
            return;
                        }
                      
                        // 如果獲取到了accept鎖
                        
            if (ngx_accept_mutex_held) {
                            flags 
            |= NGX_POST_EVENTS;

                        } 
            else {
                            // 否則, 如果滿足下面兩個(gè)條件,將定時(shí)器置為ngx_accept_mutex_delay, 這個(gè)值是一個(gè)配置參數(shù)指定的
                            
            if (timer == NGX_TIMER_INFINITE
                                
            || timer > ngx_accept_mutex_delay)
                            {
                                timer 
            = ngx_accept_mutex_delay;
                            }
                        }
                    }
                }

                // 記下當(dāng)前時(shí)間點(diǎn)
                delta 
            = ngx_current_msec;

                //  處理事件
                (
            void) ngx_process_events(cycle, timer, flags);

                // 得到處理事件所用的時(shí)間
                delta 
            = ngx_current_msec - delta;

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

                // 如果有accept事件發(fā)生, 就去處理accept事件,其實(shí)最后就是調(diào)用accept函數(shù)接收新的連接
                
            if (ngx_posted_accept_events) {
                    ngx_event_process_posted(cycle, 
            &ngx_posted_accept_events);
                }

                // 已經(jīng)處理完接收新連接的事件了,如果前面獲取到了accept鎖,那就解鎖
                
            if (ngx_accept_mutex_held) {
                    ngx_shmtx_unlock(
            &ngx_accept_mutex);
                }

                
            if (delta) {
                    ngx_event_expire_timers();
                }

                ngx_log_debug1(NGX_LOG_DEBUG_EVENT, cycle
            ->log, 0,
                               
            "posted events %p", ngx_posted_events);

                // 除了accepet事件之外的其他事件放在這個(gè)隊(duì)列中, 如果隊(duì)列不為空,就去處理相關(guān)的事件
                
            if (ngx_posted_events) {
                    
            if (ngx_threaded) {
                        ngx_wakeup_worker_thread(cycle);

                    } 
            else {
                        ngx_event_process_posted(cycle, 
            &ngx_posted_events);
                    }
                }

            上面的代碼中,ngx_accept_disabled變量是在函數(shù)ngx_event_accept中被賦值的:
                    ngx_accept_disabled = ngx_cycle->connection_n / 8
                                          
            - ngx_cycle->free_connection_n;
            簡(jiǎn)單的理解,當(dāng)前已經(jīng)接收的連接(connection_n)越多,可用的空閑連接(free_connection_n)越少,這個(gè)值越大。

            所以呢,假如某個(gè)子進(jìn)程,當(dāng)前已經(jīng)接收了一定數(shù)量的連接,那么這個(gè)計(jì)數(shù)值就會(huì)相應(yīng)的大,也就是說(shuō),這個(gè)子進(jìn)程將會(huì)暫緩(注意,不是暫停)接收新的連接,而去專注于處理當(dāng)前已經(jīng)接收的連接;反之,如果某子進(jìn)程當(dāng)前處理的連接數(shù)量少,那么這個(gè)計(jì)數(shù)就會(huì)相應(yīng)的小,于是這個(gè)較為空閑的子進(jìn)程就會(huì)更多的接收新的連接請(qǐng)求。這個(gè)策略,確保了各個(gè)worker子進(jìn)程之間負(fù)載是相對(duì)均衡的,不會(huì)出現(xiàn)某些子進(jìn)程接收的連接特別多,某些又特別少。

            同樣的,在這段代碼中,看到了即使現(xiàn)在子進(jìn)程可以接收新的連接,也需要去競(jìng)爭(zhēng)以獲取accept鎖,只有獲得了這個(gè)鎖才能接收新的連接,所以避免了前面提到的驚群現(xiàn)象的發(fā)生。

            另外,在linux的新版內(nèi)核中,加入了一個(gè)所謂的"cpu affinity"的特性,利用這個(gè)特性,你可以指定哪些進(jìn)程只能運(yùn)行在哪些CPU上面,我對(duì)這個(gè)不太熟悉,查看了一些資料,提到的說(shuō)法是,有了這個(gè)特性,比如進(jìn)程A在CPU1上面運(yùn)行,那么在CPU1上面會(huì)cache一些與該進(jìn)程相關(guān)的數(shù)據(jù),那么再次調(diào)用的時(shí)候性能方面就會(huì)高效一些,反之,如果頻繁的切換到不同的CPU上面去運(yùn)行,那么之前在別的CPU上面的cache就會(huì)失效。

            Nginx里面針對(duì)Linux內(nèi)核的這個(gè)特性做了一些優(yōu)化,它也可以在配置文件中指定哪些子進(jìn)程可以運(yùn)行在哪些CPU上面,這個(gè)優(yōu)化與配置選項(xiàng)worker_cpu_affinity有關(guān)。可以在 http://wiki.nginx.org/NginxCoreModule 找到關(guān)于這個(gè)配置相關(guān)的信息。


            posted on 2009-12-08 21:48 那誰(shuí) 閱讀(7462) 評(píng)論(7)  編輯 收藏 引用 所屬分類: 服務(wù)器設(shè)計(jì)Nginx

            評(píng)論

            # re: Nginx0.7.61代碼分析(二)--worker子進(jìn)程之間的負(fù)載均衡  回復(fù)  更多評(píng)論   

            很好,不錯(cuò),
            沒(méi)研究過(guò)nginx, 根據(jù)你的描述有兩個(gè)問(wèn)題問(wèn)一下
            1. 主進(jìn)程listen, listen_fd 可讀了,通知子進(jìn)程,或者子進(jìn)程自己能檢測(cè)到
            如果子進(jìn)程正在處理事件呢?好,就算全都是非阻塞的,那么循環(huán)很快轉(zhuǎn)
            回來(lái),處理accept或檢查listen_fd是否可讀,那這樣就不算是事件驅(qū)動(dòng)
            了,每次都是自己主動(dòng)是檢測(cè)?
            2. 如果子進(jìn)程沒(méi)有事件怎么樣?會(huì)不會(huì)空轉(zhuǎn)? 睡眠機(jī)制是什么?
            2009-12-09 11:45 | cui

            # re: Nginx0.7.61代碼分析(二)--worker子進(jìn)程之間的負(fù)載均衡  回復(fù)  更多評(píng)論   

            你的http://code.google.com/p/commoncache/wiki/demo這個(gè)工程,代碼高亮是怎么弄的呀???
            2009-12-09 21:41 | hlysh

            # re: Nginx0.7.61代碼分析(二)--worker子進(jìn)程之間的負(fù)載均衡  回復(fù)  更多評(píng)論   

            http://code.google.com/p/commoncache/wiki/demo
            2009-12-09 21:41 | hlysh

            # re: Nginx0.7.61代碼分析(二)--worker子進(jìn)程之間的負(fù)載均衡  回復(fù)  更多評(píng)論   

            @cui
            1)父進(jìn)程不用通知子進(jìn)程,因?yàn)樽舆M(jìn)程是繼承了從父進(jìn)程里創(chuàng)建的監(jiān)聽(tīng)socket
            2)沒(méi)有事件的時(shí)候子進(jìn)程將會(huì)阻塞在select/poll操作上。
            2009-12-09 23:14 | 那誰(shuí)

            # re: Nginx0.7.61代碼分析(二)--worker子進(jìn)程之間的負(fù)載均衡  回復(fù)  更多評(píng)論   

            @hlysh
            http://code.google.com/p/support/wiki/WikiSyntax#Code
            2009-12-09 23:15 | 那誰(shuí)

            # re: Nginx0.7.61代碼分析(二)--worker子進(jìn)程之間的負(fù)載均衡  回復(fù)  更多評(píng)論   

            看了下代碼,所有的work子進(jìn)程都可以accept 父進(jìn)程創(chuàng)建的listenning socket?
            很少見(jiàn)過(guò)這樣的用法阿
            wirelesser[at]hotmail.com
            2010-04-13 17:51 | ww

            # re: Nginx0.7.61代碼分析(二)--worker子進(jìn)程之間的負(fù)載均衡[未登錄](méi)  回復(fù)  更多評(píng)論   

            http://simohayha.javaeye.com/說(shuō)得好
            2010-07-22 16:08 | 111
            综合人妻久久一区二区精品| 久久高清一级毛片| 99re这里只有精品热久久| 丁香五月综合久久激情| 久久精品国产男包| 国产福利电影一区二区三区久久老子无码午夜伦不 | 亚洲AV乱码久久精品蜜桃| 青青草国产精品久久久久| 色播久久人人爽人人爽人人片AV | 国产福利电影一区二区三区久久老子无码午夜伦不 | 久久久久亚洲av综合波多野结衣 | 久久伊人中文无码| 国产精品一久久香蕉国产线看观看| 久久精品国产亚洲Aⅴ香蕉| 久久综合给合久久狠狠狠97色69| 精品久久久久久无码中文野结衣 | 久久精品国产精品亚洲人人 | 亚洲欧洲久久久精品| 色成年激情久久综合| 精品国际久久久久999波多野 | 久久精品国产精品亚洲人人 | 日本加勒比久久精品| 精品一区二区久久久久久久网站| 久久久久久久免费视频| 久久久久国产视频电影| 18岁日韩内射颜射午夜久久成人 | 午夜不卡888久久| 久久久久亚洲av无码专区 | 国产精品gz久久久| 人人狠狠综合久久亚洲88| 国产亚洲欧美精品久久久| 人妻无码久久一区二区三区免费| 久久久久久亚洲精品影院| 亚洲国产成人久久一区久久 | 久久国产精品一区二区| 亚洲AV无码久久精品狠狠爱浪潮 | 久久国产精品99国产精| 亚洲国产欧美国产综合久久| 久久精品国产久精国产果冻传媒| 亚洲精品第一综合99久久| 久久九九久精品国产免费直播|