Nginx原始碼分析 過期事件和驚群事件的處理

2021-06-27 06:41:12 字數 2081 閱讀 4746

nginx原始碼分析—過期事件和驚群事件的處理

過期事件:每個事件的date域都是乙個結構體ngx_connection_t結構體,表示對應的連線。對於乙個結構體struct epoll_event 中的data.ptr成員儲存的是ngx_connection_t連線,這裡使用instance標誌位來標識,下面就配合ngx_epoll_process_events方法說明他的用法。

data.ptr (void* )((uintptr_t) c  |  ev->instance); 這事新增事件的使用對ptr進行的初始化。

那麼在檢查的時候怎麼使用它呢?

遍歷epoll_wait返回的所有事件,對照上面提到的ngx_epoll_add_event方法,可以看到ptr成員就是ngx_connection_t連線的位址,但最後一位有特殊含義,需要把他遮蔽到。

c= event_list[i].data.ptr;

//將位址的最後一位取出來,用instace變數標識

instance= (uintptr_t) c &1;

/*五路是32位還是64位機器,其位址的最後一位肯定是0.可以用下面的這行語句把ngx_connection_t的位址還原到真正的位址值*/

c = (ngx_connection_t*) ((uintptr_t) c& (uintptr_t)  ~1);

//取出事件

rev= c->read;

//判斷這個度事件是否為過期事件

if(c->fd== -1 || wev->instance != instance)

//當fd套接字描述符為-1 或者instance標誌位不相等是,表示這個事件已經過期了,不用處理

instance標誌位為什麼可以判斷事件是否過期?從上面的**可以看出,instance標誌位的使用其實很簡單,它利用了指標的最後一位是0這個特性,既然最後一位始終為0,那麼不用不如用來表示instance,這樣,在使用ngx_epoll_add_event方法向epoll中新增事件時,就把epoll_event中聯合成員data的ptr成員指向ngx_connection_t連線的位址,同時把最後一位置為這個事件的instance標誌。而在ngx_epoll_process_events方法中取出指向連線的ptr位址時,先把最後一位instance取出來,再把ptr還原成正常的位址賦給ngx_connection_t連線,這樣,instance究竟放在何處的問題也就解決了

那麼,過期事件又是怎麼回事呢?舉個例子,epoll_wait一次放回3個事件,在第乙個事件的處理過程總,由於業務的需要,所以關閉了乙個連線,而這個連線恰好對應第三個事件,這樣的話,在處理到第三個事件時,這個時間就已經是過期事件了,一旦處理必然出錯。既然如此,把關閉的這個連線的fd套接字置為-1能解決問題麼?答案是不能處理所有出錯。

假設第三個事件對應的ngx_connection_t連線中的fd套接字原先是50,處理第乙個事件時把這個連線的套接字關閉了,同時置為-1,並且呼叫ngx_free_connection將該連線歸還給連線池,在ngx_epoll_process_events方法的迴圈中開始處理第二個事件,恰好第二個事件時建立新連線誒事件,呼叫ngx_get_connection從連線池中取出的連線非常可能及時剛才釋放的第三個事件對應的連線,由於套接字50剛剛被釋放,linux核心非常有可能把剛剛釋放的套接字50又分配給新建立的連線。因此,在迴圈中處理第三個事件時,這個事件就是過期了,它對應的事件時關閉的連線,而不是新建立的連線。

如何解決這個問題?依靠instance標誌位,當呼叫ngx_get_connection從連線池中獲取乙個新連線時,instance標誌位就會置反,

ngx_get_connection(s,log)

rev = c->read;

wev = c->write;

instane = rev->instance;

//將instance 標誌位置為原來的相反值

rev->instance = !instance;

wev->instance = !instance;

這樣,當這個ngx_connection_t連線重複使用時,他的instance標誌位一定是不同的。因此,在ngx_epoll_process_events方法中一旦判斷instance發生了變化,就認為這是過期事件而不處理。

Nginx原始碼分析 事件迴圈

經過前面相關博文的介紹,我們了解到master程序建立好乙個worker程序後,worker程序還會進行乙個初始化工作,然後才會陷入 死 迴圈中。這個 死迴圈 也就是本文將談及的事件迴圈,也就是上圖中的黃色部分。整個黃色部份是由乙個迴圈構成的,實際上,這個迴圈裡將會做很多的事情,但本文將只關注圖中紅...

nginx 原始碼分析

近期準備研究一下nginx原始碼,此處記錄一下。計畫 1 了解evan miller 的文章 2 了解nginx的組織架構 3 了解nginx的基本資料結構 4 熟悉nginx的主要module及執行機制,主要是core http event os 5 簡單的module開發及測試 一 準備 為了方...

nginx原始碼分析 從原始碼看nginx框架總結

nginx原始碼總結 1 中沒有特別繞特別彆扭的編碼實現,從變數的定義呼叫函式的實現封裝,都非常恰當,比如從函式命名或者變數命名就可以看出來定義的大體意義,函式的基本功能,再好的架構實現在編碼習慣差的人實現也會黯然失色,如果透徹理解 的實現,領悟架構的設計初衷,覺得每塊 就想經過耐心雕琢一樣,不僅僅...