nginx 是如何處理過期事件的?
什麼是過期事件
對於不需要加入到 post 隊列 延後處理的事件,nginx 的事件都是通過 ngx_epoll_process_events 函數進行處理的
舉例:假如 epoll_wait 一次性返回 3 個事件,在第一個事件關閉了一個連接對應的正好是第三個事件的連接,第二個事件 accept 了一個連接,正好使用的是第二個事件的文件描述符
如圖所示:

那麼如果僅僅判斷是否使用的同一個描述符或者描述符是否被置為 -1,就不能判斷是否是同一個連接
上面的這個問題,稱之為事件過期問題
nginx 是如何處理過期事件的?
nginx 中的指針的最後一位一定是 0 ,於是,nginx 就使用這最後一位用來表示是否過期
深入理解nginx中,第9章中有一句:利用指針的最後一位一定是0的特性。能解釋一下這個特性?
看下面程式碼中取出與判斷 instance 位的操作
nginx 會在每次 accept 一個連接的時候,將 instance 位取反,那麼只需要判斷 instance 位是否一直就能判斷事件是否過期了
// nginx-1.9.2/src/core/ngx_connection.c
// ngx_get_connection
instance = rev->instance;
ngx_memzero(rev, sizeof(ngx_event_t));
ngx_memzero(wev, sizeof(ngx_event_t));
rev->instance = !instance;
wev->instance = !instance
// nginx-1.9.2/src/event/modules/ngx_epoll_module.c
// ngx_epoll_process_events
//遍曆本次epoll_wait返回的所有事件
for (i = 0; i < events; i++) { //和ngx_epoll_add_event配合使用
/*
對照著上面提到的ngx_epoll_add_event方法,可以看到ptr成員就是ngx_connection_t連接的地址,但最後1位有特殊含義,需要把它屏蔽掉
*/
c = event_list[i].data.ptr; //通過這個確定是那個連接
instance = (uintptr_t) c & 1; //將地址的最後一位取出來,用instance變數標識, 見ngx_epoll_add_event
/*
無論是32位還是64位機器,其地址的最後1位肯定是0,可以用下面這行語句把ngx_connection_t的地址還原到真正的地址值
*/ //注意這裡的c有可能是accept前的c,用於檢測是否客戶端發起tcp連接事件,accept返回成功後會重新創建一個ngx_connection_t,用來讀寫客戶端的數據
c = (ngx_connection_t *) ((uintptr_t) c & (uintptr_t) ~1);
rev = c->read; //取出讀事件 //注意這裡的c有可能是accept前的c,用於檢測是否客戶端發起tcp連接事件,accept返回成功後會重新創建一個ngx_connection_t,用來讀寫客戶端的數據
if (c->fd == -1 || rev->instance != instance) { //判斷這個讀事件是否為過期事件
//當fd套接字描述符為-l或者instance標誌位不相等時,表示這個事件已經過期了,不用處理
/*
* the stale event from a file descriptor
* that was just closed in this iteration
*/
ngx_log_debug1(NGX_LOG_DEBUG_EVENT, cycle->log, 0,
"epoll: stale event %p", c);
continue;
}
// 還有程式碼,但是不貼這麼多了
......
}
那麼你可能也跟我有一樣的疑問,如果是下面兩種情形怎麼辦?


這樣 instance 位又成了 1,那 e 事件處理的豈不是 3 連接的事件了,這樣過期事件並沒有解決啊
首先,第二張圖片中的情況不可能存在,因為 epoll 中的事件是有順序的,c 事件必然是再 e 事件之後
那麼第一張圖片中的情況還是沒有解決過期事件啊
於是我就翻閱很多資料(主要靠百度)
看到有人遇到過這個疑問:
如果覺得上面文章太長可以看我的講解:
意思呢就是
nginx accept 連接之後,會立刻將連接放到 post 延遲處理隊列中,不會出現 accept 之後立刻 close 的情況
於是呢,nginx 就完美的解決了事件過期的情況
參考資料
《深入理解 Nginx》
深入理解nginx中,第9章中有一句:利用指針的最後一位一定是0的特性。能解釋一下這個特性?
github 項目:reading-code-of-nginx-1.9.2
