LINux網絡的NAPI機制詳解一


在查看NAPI機制的時候發現一篇介紹NAPI引入初衷的文章寫的很好,通俗易懂,就想要分享下,重要的是博主還做了可以在他基礎上任意修改,而並不用注明出處的聲明,着實令我敬佩,不過還是附上原文鏈接!

http://blog.csdn.net/dog250/article/details/5302853

處理外部事件是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方案,完全可 以用一個樁子代替。 
      cpu利用率和頻繁的中斷問題通過NAPI機制解決了,但是這又引入了一個新的問題,就是這可能造成cpu利用率的失衡,這個怎么理解呢?NAPI啟動之 后,網卡的中斷就會變得很少,要知道中斷balance的目前實現是基於中斷數量的均衡,它根本不管中斷數量均衡之后引起的softirq導致的cpu使 用率是否均衡,softirq的均衡也是一樣,比如一個是磁盤softirq,一個是網卡的NAPI的softirq,前者瞬間就可以完成但是來得頻繁, 而后者要輪詢網卡並且處理協議棧很耗時但是來得不頻繁,可是balancer不管這么多,它只是覺得磁盤的softirq太多了而為了數量均衡會將更多的 softirq發布到softiqr少的cpu上,它根本不在乎這些更多的softirq是否會帶來更高的cpu負載。NAPI削弱了中斷/軟中斷均衡的 作用,畢竟它的主導在輪詢,輪詢會占用很多的處理器資源,而中斷和軟中斷數量很少。中斷或者軟中斷特別是軟中斷數量在cpu間的均衡可能造成各個cpu負 載的嚴重不均衡,因為各個硬中斷幾乎都是瞬間完成的,硬中斷不能耽擱太久的,但是各個不同軟中斷的任務量缺是千差萬別的,因此絕對不能按照數量來均衡軟中 斷,然而一般都是硬中斷觸發軟中斷,它們都在同一個cpu上,因此如果想簡單的實現NAPI在多cpu上的cpu使用率均衡,那么必須重新實現硬件的負載 均衡機制,這樣可以嗎?不!因此這樣會使得兩個部分耦合過重,因此必須讓硬中斷的均衡和cpu的均衡解耦合,其實現在的內核就是這么做的,所以才會造成 cpu不均衡,硬件中斷的均衡和cpu均衡的解耦合帶來的好處就是我們可以對軟中斷均衡做文章,而硬中斷的負載均衡還是用數量均衡實現,軟中斷徹底從硬件 中斷中解放出來,不再是在處理硬中斷的cpu上觸發軟中斷,而是可以在任何cpu上觸發軟中斷,由於不同軟中斷的任務量千差萬別,因此我們定義一個軟中斷 的“權值”,然后按照不同軟中斷這個權值和數量的積的和來均衡軟中斷,這樣的話,我想各個cpu的負載就均衡了,現在問題是,各個不同的軟中斷的“權值” 的計算問題,呵呵。累了,有時間再說。一個論壇上一哥們兒寫了一個patch,很有創意,比我這里的軟中斷均衡的粒度要小得多,這個補丁不是均衡軟中斷, 而是將軟中斷進一步也分成了上下兩部分,和cpu相關的上半部必須加急處理,這樣不會對cpu造成太大負載,仍然用硬件中斷均衡,因為硬件中斷的cpu觸 發軟件中斷,這部分不變,但是軟中斷的下半部就需要均衡了,該補丁為每一個cpu創立了一個工作隊列,然后將ip_rcv 這種操作的cpu相關的工作放到軟中斷的上半部,其實就是從一個cpu的skb隊列中抽取一個skb,然后將這個skb隨機放到這些工作隊列中進行處理, 和整個軟中斷均衡有何不同嗎?大大不同。軟中斷均衡針對的是一個poll_list里面的所有的skb,而這哥們兒的補丁針對的是一個skb,粒度十分 小,但是沒有測試,是不是太小了呢?這其實也是一個模式方法,逐步的將粒度精細化,類似將中斷分成上半部和下半部的做法是放之四海而皆准的,這是一種哲 學,也是一種風格。 
如果你說你沒有見過linux的方式,那么只要你上過枯燥的計算機課或者讀過枯燥的教科書或者你是天才你就知道一個叫做生產者/消費者的模型,它其實和 linux的中斷的上半部和下半部很類似,上半部是生產者,只管將環境搭建好,數據准備好,然后觸發下半部,其實就是喚醒消費者,這個思想在多線程並發中 很著名,而並發就是為了提高系統吞吐量,在SMP環境中也是為了並發,因此我們何嘗不用用生產者/消費者模型呢?它也是一種低耦合的各司其職的模型。如果 你想不到NAPI的中斷+輪詢的方式,那么你聽說過linux下怎樣做文件同步的嗎?rsync+inotify的方式聽說過嗎?如果沒有就趕快 google一下吧。rsync+inotify其實就是中斷+輪詢,rsync是輪詢,而inotify是中斷,這個同步方案十分高效,保證只有在 inotify監控到文件變化的時候才開始輪詢,平時就睡覺,inotify不再需要監控到具體的文件,因為它只負責告知事件,具體工作由rsync完 成,inotify只需要告訴一端文件變化了即可,那豈不是要全部同步了即使你只改了一個字符,別忘了rsync的算法,這就是另一篇文章了。所以不要再 覺得linux內核深不可測了,它的特點只有一個就是簡單,比起用戶應用那些復雜的算法,內核的算法一向簡單易懂,其實內核的每一個機制,都可以在用戶空 間找到原型的。 
可是cpu對NAPI處理的均衡真的有意義嗎?用戶難道就不能忍受一個cpu占用100%而另一個0%嗎?表面上看是那樣的,但是如果考慮cache或者 切換代價的話就不一樣了,性能因素不僅僅是cpu使用率還有別的,如果一件事的開銷過大,即使cpu使用率再均衡也是划不來的。這就好像初學者用free 命令看內存時總是嚇一大跳。特別是NAPI的網絡數據包操作,比如TCP的IP包的分段重組問題,一旦亂序就要重傳,這種情況下,一個linux主機如果只是作為一台路由器的話,那 么進入系統的一個TCP包的不同分段如果被不同的cpu處理並向一個網卡轉發了,那么同步問題會很麻煩的,如果你不做同步處理,那么很可能后面的段被一個 cpu先發出去了,那么在真正的接收方接收到亂序的包后就會請求重發,這是不希望的,因此還是一個cpu串行處理好,這也許是TCP/IP協議棧的缺陷, 但是沒有辦法,協議是那樣的,只能那樣去應對。在大流量下,由於napi的緣故,網卡的中斷被關閉了,此時那個第一次被中斷的cpu正在poll這個網卡,因此所有的流量都會聚集到這個cpu上,這可能是一個設計的缺陷吧。


 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM