之前在分析ligty的時(shí)候提到,它的
超時(shí)處理模型大致如下:
注冊(cè)一個(gè)處理alarm信號(hào)的回調(diào)函數(shù),然后每秒鐘觸發(fā)一次
回調(diào)函數(shù)每次被觸發(fā)之后,置某個(gè)標(biāo)志位
在服務(wù)器的主循環(huán)中,每次循環(huán)都會(huì)檢查這個(gè)標(biāo)志位有沒有被置位,如果有,說明一秒鐘已經(jīng)過去,這時(shí)輪詢所有當(dāng)前處理的連接,刪除超時(shí)的連接。
這個(gè)模型,最大的問題在于,它的效率與當(dāng)前連接數(shù)量有很大關(guān)系,數(shù)量大了,輪詢一次的成本很高。
Nginx里面,處理超時(shí)連接的模型比之ligty高效了很多:
當(dāng)前所有可能被觸發(fā)的定時(shí)器被保存在紅黑樹這種數(shù)據(jù)結(jié)構(gòu)中,通過紅黑樹,你可以很快的得到距離當(dāng)前最快發(fā)生的定時(shí)器事件的時(shí)間差。
將這個(gè)時(shí)間差作為select/poll/epoll等函數(shù)的參數(shù),也就是,最多等待這么長(zhǎng)時(shí)間就返回。
當(dāng)函數(shù)返回時(shí),得到函數(shù)調(diào)用總共花費(fèi)了多少時(shí)間,根據(jù)這個(gè)時(shí)間取出紅黑樹的根節(jié)點(diǎn)比較查看是否應(yīng)該觸發(fā)該定時(shí)器時(shí)間,如果可以則將該定時(shí)器從紅黑樹中刪除,然后繼續(xù)查看新的成為樹根的定時(shí)器節(jié)點(diǎn),這個(gè)過程一直進(jìn)行下去直到?jīng)]有定時(shí)器滿足被觸發(fā)的條件,也就是還沒有到被觸發(fā)的事件。
Nginx里面,新接收了一個(gè)連接,會(huì)保存這個(gè)連接上來的時(shí)間,并且以這個(gè)時(shí)間來加入紅黑樹定時(shí)器中。
可以看到,因?yàn)橐肓思t黑樹這個(gè)數(shù)據(jù)結(jié)構(gòu),所有的定時(shí)器都可以按照順序來依次取出,這樣不用輪詢所有事件來查看是否超時(shí)了;而以距離當(dāng)前最快發(fā)生的定時(shí)器事件時(shí)間差作為輪詢的定時(shí),又可以不用使用alarm信號(hào)來觸發(fā)定時(shí),一舉兩得。
這個(gè)處理超時(shí)事件的模型,與我之前分析過的
libevent的模型,大體相同,只不過,在那里紅黑樹被堆代替了。