Squid是目前最流行的開源CACHE引擎,本文對Squid和Netshine ICS的實現機制進行分析,據此得出Netshine ICS性能為什么比Squid高的深層次的技術原因。 一、Squid存在的問題 在Internet上的應用幾乎都是事件驅動式的(event driven)。在Unix上,有兩個基本的函數用來檢測來自于網絡的事件,一個是select(),另外一個是poll()。無一例外,Squid使用poll()函數作為它的事件檢測和分派的核心。下面是poll()函數的接口原型:
其中,fds是需要檢測的文件描述符集合,nfds是這個集合的大小。 當nfds比較小時,poll()工作得非常好。但是在實際中我們發現,當nfds比較大時,poll()本身的操作就占用了CPU的絕大部分時間,換句話說,就是poll()的伸縮性(scalablity)比較弱。那么,問題出在哪兒呢? 問題就出在poll()接口的定義和實現上。對于每次poll()調用,poll()函數都要求將整個文件描述符列表傳遞給它,由于poll()是一個系統調用,因此,系統對于每次poll()調用,都必須穿透user/kernel邊界拷貝數據,同時在kernel內部還有一次malloc()調用。當nfds比較小時,這種開銷不會導致多大的性能問題,但是如果nfs大到成千上萬時,這種開銷就非常了得!實際上,在一個中等規模的環境中,比如高校,系統同時保持1萬多條連接是比較常見的事情(如擁有5000臺以上計算機的高效,最高峰達到了20000條以上的連接,平均可以達到13000條左右的連接)。另外,從應用程序的角度看,每次當poll()調用返回后,都必須遍歷整個文件描述符列表,這是一個O(n)復雜度的操作,因此伸縮性很差。同樣的,這種遍歷操作在kernel內部也必須做一遍。 總而言之,poll()低效的主要原因是,poll()做了太多的無效操作,因此浪費了大量的CPU時間: (1)無效的user->kernel方向的數據拷貝。在一個實際的應用中,很多描述符都會存在于一段時間,因此每次對拷貝所要檢測的所有文件描述符列表是一個無效的操作,因為兩次連續的poll()調用中,必定有很多文件描述符是相同的; (2)無效的kernel->user方向的數據拷貝。在實際中,盡管系統保持了很多文件描述符(套接字),但是在每個時刻,真正可readable或writable的文件描述符并不多,因此,將所有的文件描述符都拷貝給user是無效的,在一個保持了10000條連接的系統中,可能只有1000條連接上可readable或writable,因此有90%的數據拷貝是無效的。 (3)無效的應用層遍歷。根據(2),既然10000條連接中只有1000條連接是有事件的(readable或writable),那么90%的遍歷就是無效的。 影響cache系統性能的最主要兩個因素是network I/O和disk I/O。由于cache存在大量的數據讀寫操作,因此disk I/O的性能高低會極大地影響cache的整體性能。Squid為了解決這一點,在操作系統提供的文件系統的基礎上實現了一個所謂的"cache文件系統"。但是無論如何,由于這個"cache文件系統"是建立在通用文件系統的基礎之上,所以它最多只能利用內存來減少disk I/O次數以提高系統性能。由于通用文件系統并沒有利用多個磁盤I/O的獨立性,因此當系統掛接了多個磁盤時,這種方式并不能有效利用多個磁盤同時I/O的特點,所以它并不能有效提高disk I/O。 以上兩點,決定了Squid具有很差的伸縮性,也就是說,即使你硬件配置再高,它也不能有效的提升性能! 二、Netshine ICS是如何解決問題的 Netshine ICS通過以下兩個措施來解決上述問題: (1)拋棄poll。由于poll()極差的伸縮性,Netshine ICS拋棄了poll(),而使用FreeBSD的kevent機制。關于kevent機制的詳細介紹請參考相關的文檔,這里就不多述了。 (2)建立專用的文件存儲系統和內存緩存系統。為了提高disk i/o,Netshine ICS在內存中建立高效的cache文件系統的同時,還對操作系統內核進行改造,實現軟件級別的RAID和直接磁盤I/O以充分利用多個磁盤并發I/O的能力,并且,Netshine ICS在磁盤裸分區上建立了一個專用的文件存儲系統。在實踐中,這種方式證明是非常高效的,也非常穩定的! 三、Netshine ICS和Squid性能對比 (1)吞吐量和內存使用有效性比較 ![]() (2)每秒請求數比較 ![]()
|
延伸閱讀
文章來源于領測軟件測試網 http://www.kjueaiud.com/