天天看點

NAPI模式--中斷和輪詢的折中以及一個負載均衡的問題

處理外部事件是cpu必須要做的事,因為cpu和外設的不平等性導緻外設的事件被cpu 當作是外部事件,其實它們是平等的,隻不過馮氏機器不這麼認為罷了,既然要處理外部事件,那麼就需要一定的方法,方法不止一種,大緻有中斷和輪詢以及一種 混雜又複雜的方式,也就是DMA方式。中斷是cpu被動處理的一種方式,也就是說cpu不知道何時中斷,隻要有了中斷就會通知cpu,而cpu此時必須停 下一切來處理,而輪詢是cpu主動查詢并處理的過程,cpu隔一會查詢一下外設看有沒有事情可做。 

我們看一下這兩種方式,中斷看似很高效,但是卻會遺漏一些資料,避免遺漏的機制要麼由硬體實作要麼由上層的軟體實作,而輪詢就沒有中斷高效了,它會做很多 徒勞的操作,而且必須引入暫存機制,就是說由于cpu不可能在每次查詢硬體的時候正好有事情可做,為了不使請求遺漏,随時到來的請求必須暫存在一個私有的 區域内,隻要這些都做好了,輪詢是不會造成請求遺漏的,中斷在很多中斷高頻觸發的時候會造成大量遺漏和競争,畢竟隻有一個cpu,同一個時間點隻能有一個 請求被處理,而輪詢由于是cpu分批打包處理請求的,是以不會遺漏。 

以上的論述有點像我讨論過的inotify和rsync實作的檔案同步,inotify的實作就是中斷,很顯然有遺漏,而rsync實作的就是輪詢,顯然 沒有遺漏,cpu主動做的事情它自己最明白了,但是它要是被動應對就不會這麼明白了,它隻是按照規則應對罷了,絲毫不會存在任何政策。如果中斷過于頻繁也 是不好的,因為cpu必須進行中斷,這會導緻cpu沒有時間做正經事,此時最好用輪詢,但是外設活動很緩和的時候,用輪詢就不合适了,因為詢也是白詢,此 時比較适合用中斷,可是系統怎麼知道何時外設活躍何時外設緩和呢?啊哈,可以用智能預測算法嘛,以曆史值為依據!不,不能那樣的,因為這是在核心,核心不 是秀算法的地方,我另外的文章強調過這一點。那麼怎麼辦?好辦,還是約定,就是将中斷和輪詢相結合,這就是linux網卡驅動中的NAPI的方式,它的設 計十分巧妙,就是在第一個包到來的時候中斷,然後關閉中斷開始輪詢,等某一次輪詢完畢後發現沒有資料了,那麼核心預設此次資料已經傳輸完畢,短時間内不會 再有資料了,那麼停止輪詢,重新開啟中斷,這樣會減少很多次的中斷,雖然某次輪詢完畢發現沒有資料并不能代表1ms以後不會再有資料,但是剛才說了,要想 使算法簡單,必須做一個合理的約定,人性化的約定,如果說加上判定什麼情況下百分之九十五的可能不需要輪詢了并不是不可能,隻是維護那個算法的開銷太大, 它直接抵消了算法帶來的優勢。用人的思想考慮,如果一個飯店的服務員不停的從廚房接菜然後送到餐桌,注意是不停的,10秒一趟,但是突然隔了半分鐘沒有廚 房的人吆喝接菜,如果你是服務員,難道你還會去視窗等菜嗎?反正我不會,我會蹲下來稍微休息一下,即使剛蹲下來就會有新活我也願意賭一把,雖然輸得可能性 很大很大。 

如此一來,我們看一下NAPI解決了什麼問題,第一,它限制了中斷的數量,一旦有中斷過來就停掉中斷改為輪詢,這樣就不會造成cpu被頻繁中斷,第 二,cpu不會做無用功,就是所謂的無用的輪詢,因為隻有在中斷來了才改為輪詢,中斷來了說明有事可做,看看NAPI将中斷和輪詢結合的是多麼巧妙啊。以 往的實作中,在硬體網卡中斷中将skb排入隊,然後在軟中斷中出隊并交由上層處理,一切配合的看起來那麼好,可是在遇到突發快速小包傳輸的時候就會導緻頻 繁中斷,因為是突發的包,是以不能用輪詢,因為是快速小包,是以不适合用中斷,最終二者巧妙結合,各取優勢,優勢互補,絕了!這個架構适合一切的網卡模 式,是以就将傳統的網卡收發機制也納入到了NAPI架構,很簡單,就是用原來的邏輯實作dev的poll回調函數即可,至于傳統的非NAPI方案,完全可 以用一個樁子代替。 

 本文轉自 dog250 51CTO部落格,原文連結:http://blog.51cto.com/dog250/1274140

繼續閱讀