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