• <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>

            那誰的技術博客

            感興趣領域:高性能服務器編程,存儲,算法,Linux內核
            隨筆 - 210, 文章 - 0, 評論 - 1183, 引用 - 0
            數據加載中……

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

            緊跟著上一節所講的,Nginx里面worker子進程之間相互獨立,各自接收新的連接,接收數據報文,處理請求,等等。

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

            Nginx里面,針對上面提到的兩點,對程序進行了一些優化。來看看ngx_process_events_and_timers 函數里面的代碼,這個函數是worker子進程中服務器主循環每次循環都會調用的函數:

                // 如果使用了accept mutex 
               
            if (ngx_use_accept_mutex) {
                    // 如果當前禁止accept操作的計數還大于0
                    
            if (ngx_accept_disabled > 0) {
                        // 將這個計數減一
                        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 {
                            // 否則, 如果滿足下面兩個條件,將定時器置為ngx_accept_mutex_delay, 這個值是一個配置參數指定的
                            
            if (timer == NGX_TIMER_INFINITE
                                
            || timer > ngx_accept_mutex_delay)
                            {
                                timer 
            = ngx_accept_mutex_delay;
                            }
                        }
                    }
                }

                // 記下當前時間點
                delta 
            = ngx_current_msec;

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

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

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

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

                // 已經處理完接收新連接的事件了,如果前面獲取到了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事件之外的其他事件放在這個隊列中, 如果隊列不為空,就去處理相關的事件
                
            if (ngx_posted_events) {
                    
            if (ngx_threaded) {
                        ngx_wakeup_worker_thread(cycle);

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

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

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

            同樣的,在這段代碼中,看到了即使現在子進程可以接收新的連接,也需要去競爭以獲取accept鎖,只有獲得了這個鎖才能接收新的連接,所以避免了前面提到的驚群現象的發生。

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

            Nginx里面針對Linux內核的這個特性做了一些優化,它也可以在配置文件中指定哪些子進程可以運行在哪些CPU上面,這個優化與配置選項worker_cpu_affinity有關。可以在 http://wiki.nginx.org/NginxCoreModule 找到關于這個配置相關的信息。


            posted on 2009-12-08 21:48 那誰 閱讀(7463) 評論(7)  編輯 收藏 引用 所屬分類: 服務器設計Nginx

            評論

            # re: Nginx0.7.61代碼分析(二)--worker子進程之間的負載均衡  回復  更多評論   

            很好,不錯,
            沒研究過nginx, 根據你的描述有兩個問題問一下
            1. 主進程listen, listen_fd 可讀了,通知子進程,或者子進程自己能檢測到
            如果子進程正在處理事件呢?好,就算全都是非阻塞的,那么循環很快轉
            回來,處理accept或檢查listen_fd是否可讀,那這樣就不算是事件驅動
            了,每次都是自己主動是檢測?
            2. 如果子進程沒有事件怎么樣?會不會空轉? 睡眠機制是什么?
            2009-12-09 11:45 | cui

            # re: Nginx0.7.61代碼分析(二)--worker子進程之間的負載均衡  回復  更多評論   

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

            # re: Nginx0.7.61代碼分析(二)--worker子進程之間的負載均衡  回復  更多評論   

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

            # re: Nginx0.7.61代碼分析(二)--worker子進程之間的負載均衡  回復  更多評論   

            @cui
            1)父進程不用通知子進程,因為子進程是繼承了從父進程里創建的監聽socket
            2)沒有事件的時候子進程將會阻塞在select/poll操作上。
            2009-12-09 23:14 | 那誰

            # re: Nginx0.7.61代碼分析(二)--worker子進程之間的負載均衡  回復  更多評論   

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

            # re: Nginx0.7.61代碼分析(二)--worker子進程之間的負載均衡  回復  更多評論   

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

            # re: Nginx0.7.61代碼分析(二)--worker子進程之間的負載均衡[未登錄]  回復  更多評論   

            http://simohayha.javaeye.com/說得好
            2010-07-22 16:08 | 111
            亚洲日韩欧美一区久久久久我| 国产精品女同久久久久电影院| 国内精品久久久久久久涩爱| 国产精品美女久久久久av爽| 日本国产精品久久| 人妻精品久久无码区| 精品久久久久久无码中文字幕| 伊人久久大香线蕉AV一区二区| 国内精品久久久久影院一蜜桃| 国产一区二区三精品久久久无广告| 香港aa三级久久三级老师2021国产三级精品三级在 | 偷偷做久久久久网站| 精品综合久久久久久888蜜芽| 久久精品国产只有精品2020| 久久久无码精品亚洲日韩京东传媒 | 久久久久国产| 青青草国产精品久久| 日本强好片久久久久久AAA| 国产精品美女久久久久AV福利| 久久人人爽爽爽人久久久| 欧美激情精品久久久久久| 97r久久精品国产99国产精| 亚洲一区精品伊人久久伊人| 国产成人久久777777| 久久99精品国产麻豆| 婷婷伊人久久大香线蕉AV| 久久乐国产综合亚洲精品| 丰满少妇人妻久久久久久4| 久久99国产精品久久久| 国产精品久久精品| 久久精品人人做人人爽97| 亚洲国产精品无码久久一区二区| 久久人妻少妇嫩草AV蜜桃| 精品久久久久中文字幕一区| 亚洲成人精品久久| 国产精品永久久久久久久久久| 久久综合久久综合九色| 91精品国产91久久久久久青草| 国产精品久久精品| 欧美亚洲国产精品久久蜜芽| 99久久精品国产一区二区三区|