天天看點

ngx ------ngx_cache_manager_process_cycle

ngx ------ngx_cache_manager_process_cycle
static void  
ngx_cache_manager_process_cycle(ngx_cycle_t *cycle, void *data)
{-----------------------------------
    /*
     * Set correct process type since closing listening Unix domain socket
     * in a master process also removes the Unix domain socket file.
     */
    ngx_process = NGX_PROCESS_HELPER;

    ngx_close_listening_sockets(cycle);

    /* Set a moderate number of connections for a helper process. */
    cycle->connection_n = 512;
//work 程序 初始化
    ngx_worker_process_init(cycle, -1);

    ngx_memzero(&ev, sizeof(ngx_event_t));
    ev.handler = ctx->handler; //ngx_cache_manager_process_handler  ngx_cache_loader_process_handler
    ev.data = ident;
    ev.log = cycle->log;
    ident[3] = (void *) -1;

    ngx_use_accept_mutex = 0;

    ngx_setproctitle(ctx->name);

    ngx_add_timer(&ev, ctx->delay, NGX_FUNC_LINE); //ctx->dealy秒執行ctx->handler;
    
    for ( ;; ) {

        if (ngx_terminate || ngx_quit) {
            ngx_log_error(NGX_LOG_NOTICE, cycle->log, 0, "exiting");
            exit(0);
        }

        if (ngx_reopen) {
            ngx_reopen = 0;
            ngx_log_error(NGX_LOG_NOTICE, cycle->log, 0, "reopening logs");
            ngx_reopen_files(cycle, -1);
        }
------------//work 程序 循環處理 fd  io 以及 timer------------------------------------------------------
        ngx_process_events_and_timers(cycle);
    }
}      
void
ngx_process_events_and_timers(ngx_cycle_t *cycle)  
{
    ngx_uint_t  flags;
    ngx_msec_t  timer, delta;
    
    ---------------------------------------
    ngx_use_accept_mutex = 1;
   //ngx_use_accept_mutex表示是否需要通過對accept加鎖來解決驚群問題。當nginx worker程序數>1時且配置檔案中打開accept_mutex時,這個标志置為1   
    if (ngx_use_accept_mutex) {
        /*
              ngx_accept_disabled表示此時滿負荷,沒必要再處理新連接配接了,我們在nginx.conf曾經配置了每一個nginx worker程序能夠處理的最大連接配接數,
          當達到最大數的7/8時,ngx_accept_disabled為正,說明本nginx worker程序非常繁忙,将不再去處理新連接配接,這也是個簡單的負載均衡
              在目前使用的連接配接到達總連接配接數的7/8時,就不會再處理新連接配接了,同時,在每次調用process_events時都會将ngx_accept_disabled減1,
          直到ngx_accept_disabled降到總連接配接數的7/8以下時,才會調用ngx_trylock_accept_mutex試圖去處理新連接配接事件  如果ngx_accept_disabled大于了0,就表示該程序接受的
連接配接過多,是以就放棄一次争搶accept mutex的機會,同時将 自己減1。然後,繼續處理已有連接配接上的事件。Nginx就借用 此變量實作了程序關于連接配接的基本負載均衡。 
      
*/
        if (ngx_accept_disabled > 0) { //為正說明可用連接配接用了超過八分之七,則讓其他的程序在下面的else中來accept
            ngx_accept_disabled--;

        } else {
            /*
                 如果ngx_trylock_accept_mutex方法沒有擷取到鎖,接下來調用事件驅動子產品的process_events方法時隻能處理已有的連接配接上的事件;
                 如果擷取到了鎖,調用process_events方法時就會既處理已有連接配接上的事件,也處理新連接配接的事件。
              
                如何用鎖來避免驚群?
                   嘗試鎖accept mutex,隻有成功擷取鎖的程序,才會将listen  
                   套接字放入epoll中。是以,這就保證了隻有一個程序擁有  
                   監聽套接口,故所有程序阻塞在epoll_wait時,不會出現驚群現象。  
                   這裡的ngx_trylock_accept_mutex函數中,如果順利的擷取了鎖,那麼它會将監聽端口注冊到目前worker程序的epoll當中   

               獲得accept鎖,多個worker僅有一個可以得到這把鎖。獲得鎖不是阻塞過程,都是立刻傳回,擷取成功的話ngx_accept_mutex_held被置為1。
               拿到鎖,意味着監聽句柄被放到本程序的epoll中了,如果沒有拿到鎖,則監聽句柄會被從epoll中取出。 
              */
        /*
           如果ngx_use_accept_mutex為0也就是未開啟accept_mutex鎖,則在ngx_worker_process_init->ngx_event_process_init 中把accept連接配接讀事件統計到epoll中
           否則在ngx_process_events_and_timers->ngx_process_events_and_timers->ngx_trylock_accept_mutex中把accept連接配接讀事件統計到epoll中;
---------------------------嘗試鎖accept mutex,隻有成功擷取鎖的程序,才會将listen 套接字放入epoll中。是以,這就保證了隻有一個程序擁有  監聽套接口,故所有程序阻塞在epoll_wait時,不會出現驚群現象。 
      
*/
            if (ngx_trylock_accept_mutex(cycle) == NGX_ERROR) { //不管是擷取到鎖還是沒擷取到鎖都是傳回NGX_OK
                return;
            }

            /*
                拿到鎖的話,置flag為NGX_POST_EVENTS,這意味着ngx_process_events函數中,任何事件都将延後處理,會把accept事件都放到
                ngx_posted_accept_events連結清單中,epollin|epollout事件都放到ngx_posted_events連結清單中 ---
 擷取鎖的程序,将添加一個NGX_POST_EVENTS标志, 此标志的作用是将所有産生的事件放入一個隊列中, 等釋放鎖後,再慢慢來處理事件。
因為,處理事件可能 會很耗時,如果不先釋放鎖再處理的話,該程序就長 時間霸占了鎖,導緻其他程序無法擷取鎖,這樣accept 的效率就低了。             
               */
            if (ngx_accept_mutex_held) {
                flags |= NGX_POST_EVENTS;

            } else {
                /*
                    拿不到鎖,也就不會處理監聽的句柄,這個timer實際是傳給epoll_wait的逾時時間,修改為最大ngx_accept_mutex_delay意味
                    着epoll_wait更短的逾時傳回,以免新連接配接長時間沒有得到處理   
                    */
                if (timer == NGX_TIMER_INFINITE
                    || timer > ngx_accept_mutex_delay)
                {   //如果沒擷取到鎖,則延遲這麼多ms重新擷取說,繼續循環,也就是技術鎖被其他程序獲得,本程序最多在epoll_wait中睡眠0.5s,然後傳回
                    timer = ngx_accept_mutex_delay; //保證這麼多時間逾時的時候出發epoll_wait傳回,進而可以更新記憶體時間
                }
            }
        }
    }

    delta = ngx_current_msec;

    /*
    1.如果程序獲的鎖,并擷取到鎖,則該程序在epoll事件發生後會觸發傳回,然後得到對應的事件handler,加入延遲隊列中,然後釋放鎖,然
    後在執行對應handler,同時更新時間,判斷該程序對應的紅黑樹中是否有定時器逾時,
    2.如果沒有擷取到鎖,則預設傳給epoll_wait的逾時時間是0.5s,表示過0.5s繼續擷取鎖,0.5s逾時後,會跟新目前時間,同時判斷是否有過期的
      定時器,有則指向對應的定時器函數
    */

/*
1.ngx_event_s可以是普通的epoll讀寫事件(參考ngx_event_connect_peer->ngx_add_conn或者ngx_add_event),通過讀寫事件觸發

2.也可以是普通定時器事件(參考ngx_cache_manager_process_handler->ngx_add_timer(ngx_event_add_timer)),通過ngx_process_events_and_timers中的
epoll_wait傳回,可以是讀寫事件觸發傳回,也可能是因為沒擷取到共享鎖,進而等待0.5s傳回重新擷取鎖來跟新事件并執行逾時事件來跟新事件并且判斷定
時器連結清單中的逾時事件,逾時則執行進而指向event的handler,然後進一步指向對應r或者u的->write_event_handler  read_event_handler

3.也可以是利用定時器expirt實作的讀寫事件(參考ngx_http_set_write_handler->ngx_add_timer(ngx_event_add_timer)),觸發過程見2,隻是在handler中不會執行write_event_handler  read_event_handler
*/
    
    //linux下,普通網絡套接字調用ngx_epoll_process_events函數開始處理,異步檔案i/o設定事件的回調方法為ngx_epoll_eventfd_handler
    (void) ngx_process_events(cycle, timer, flags);

    delta = ngx_current_msec - delta; //(void) ngx_process_events(cycle, timer, flags)中epoll等待事件觸發過程花費的時間

    ngx_log_debug1(NGX_LOG_DEBUG_EVENT, cycle->log, 0, "epoll_wait timer range(delta): %M", delta);
             
    //當感應到來自于用戶端的accept事件,epoll_wait傳回後加入到post隊列,執行完所有accpet連接配接事件後,立馬釋放ngx_accept_mutex鎖,這樣其他程序就可以立馬獲得鎖accept用戶端連接配接
//* 這裡完成對隊列中的accept事件的處理,實際就是調用 ngx_event_accept函數來擷取一個新的連接配接,然後放入 epoll中。  
    ngx_event_process_posted(cycle, &ngx_posted_accept_events); //一般執行ngx_event_accept 
    
    //釋放鎖後再處理下面的EPOLLIN EPOLLOUT請求   --------------所有accept事件處理完成,如果擁有鎖的話,就趕緊釋放了。 其他程序還等着搶了。
    if (ngx_accept_mutex_held) {
        ngx_shmtx_unlock(&ngx_accept_mutex);
    }

    if (delta) {
        ngx_event_expire_timers(); //處理紅黑樹隊列中的逾時事件handler
    }
    
    /*
     然後再處理正常的資料讀寫請求。因為這些請求耗時久,是以在ngx_process_events裡NGX_POST_EVENTS标志将事件都放入ngx_posted_events
     連結清單中,延遲到鎖釋放了再處理。 
     */
    ngx_event_process_posted(cycle, &ngx_posted_events); //普通讀寫事件放在釋放ngx_accept_mutex鎖後執行,提高用戶端accept性能
}      
ngx ------ngx_cache_manager_process_cycle

https://yikun.github.io/2014/03/26/nginxevent/

http代理伺服器(3-4-7層代理)-網絡事件庫公共元件、核心kernel驅動 攝像頭驅動 tcpip網絡協定棧、netfilter、bridge 好像看過!!!!

但行好事 莫問前程

--身高體重180的胖子