標籤:
轉自:
http://blog.csdn.net/mindfloating/article/details/8622930
流行 NIO Framework netty 和 mina 效能測評與分析測試方法採用 mina 和 netty 各實現一個 基於 nio 的EchoServer,測試在不同大小網路報文下的效能表現 測試環境用戶端-服務端: model name: Intel(R) Core(TM) i5-2320 CPU @ 3.00GHz cache size: 6144 KB cpu cores: 4 jdk: 1.6.0_30-b12 network: 1000Mb memory: -Xms256m -Xmx256m Linux: centos 5.7, kernel 2.6.18-274.el5 測試載入器: jmeter v2.4 版本: mina 2.0.7 netty 3.6.2.Final 配置: mina io-processor cpu 核心數 executor cpu 核心數 buffer 初始 buffer 大小,設定為 2048(2k) netty boss netty 預設配置 1 worker cpu 核心數 executor cpu 核心數 其實,從理論上來說, echo 型的應用不配置 executor 業務執行線程池會獲得更好的效能和更低的消耗,但考慮在真實業務應用中,真實的業務情境處理通常涉及各種複雜邏輯計算,緩衝、資料庫、外部介面訪問,為避免業務執行延時阻塞 io 線程執行導致吞吐降低,通常都會分離 io 處理線程 和 業務處理線程,因此我們的測試案例中也配置了業務執行線程池考查它們線程池的調度效能。 mina 線程池設定 io processor: IoAcceptor acceptor = new NioSocketAcceptor(Integer.parseInt(ioPool)); executor: acceptor.getFilterChain().addLast("threadPool", new ExecutorFilter(Integer.parseInt(executorPool))); netty 線程池設定 io worker: new NioWorkerPool(Executors.newCachedThreadPool(), Integer.parseInt(ioPool)) executor: new OrderedMemoryAwareThreadPoolExecutor(Integer.parseInt(executorPool), 0, 0) 測試結果
| mina |
tps |
cpu |
network io |
art(average response time) |
90%rt(90% response time) |
| 1k |
45024/sec |
150% |
50MB/sec |
< 1ms |
1ms |
| 2k |
35548/sec |
170% |
81MB/sec |
< 1ms |
1ms |
| 5k |
10155/sec |
90% |
55MB/sec |
3 ms |
1ms |
| 10k |
8740/sec |
137% |
98MB/sec |
3ms |
4ms |
| 50k |
1873/sec |
128% |
100MB/sec |
16ms |
19ms |
| 100k |
949/sec |
128% |
100MB/sec |
33ms |
43ms |
| netty |
tps |
cpu |
network io |
art(average response time) |
90%rt(90% response time) |
| 1k |
44653/sec |
155% |
50MB/sec |
< 1ms |
1ms |
| 2k |
35580/sec |
175% |
81MB/sec |
< 1ms |
1ms |
| 5k |
17971/sec |
195% |
98MB/sec |
3 ms |
1ms |
| 10k |
8806/sec |
195% |
98MB/sec |
3ms |
4ms |
| 50k |
1909/sec |
197% |
100MB/sec |
16ms |
18ms |
| 100k |
964/sec |
197% |
100MB/sec |
32ms |
45ms |
測試點評mina 和 netty 在 1k、2k、10k、50k、100k 報文大小時 tps 接近mina 在 5k 報文時有個明顯的異常(紅色標註),tps 較低,網路 io 吞吐較低,比較 netty 在 5k 報文的網路 io 吞吐 98MB/sec(基本接近前兆網卡極限)5k 報文以上基本都能壓滿網路 io,瓶頸在 io,所以 tps 和 回應時間基本相差不大。 疑問,為什麼 mina 會在 5k 報文時 io 吞吐出現明顯降低? 測試分析通過分析 mina 和 netty 的源碼,發現處理 io 讀事件時 buffer 分配策略上,兩個架構有一些區別。在網路 io 處理上,程式每次調用 socket api 從 tcp buffer 讀取的位元組數是隨時變化的,它會受到報文大小,作業系統 tcp buffer 大小、tcp 協議演算法實現、網路鏈路頻寬各種因素影響。因此 NIO 架構在處理每個讀事件時,也需要每次動態分配一個 buffer 來臨時存放讀到的位元組,buffer 分配的效能是影響網路 io 架構程式效能表現的關鍵因素。 下面分別分析下 mina 和 netty buffer 的動態分配實現mina buffer 分配方式: 預設實現採用了 HeapByteBuffer,每次都是直接調用 ByteBuffer.allocate(capacity) 直接分配 buffer 分配大小預測: 根據每次讀事件實際讀到的位元組數計算分配 buffer 的大小,若實際讀到位元組將 ByteBuffer 裝滿,說明來自網路的資料量可能較大而分配 buffer 容量不足,則擴大 buffer 一倍。 若連續 2 次讀到的實際位元組數小於 buffer 容量的一半,則縮小 buffer 為原來的一半 netty buffer 分配方式 預設實現採用了 DirectByteBuffer,並且實現了 buffer cache,只要 buffer 大小不改變會重複利用已經分配的 buffer buffer 分配大小預測: 初始化了一張 buffer size 靜態分配表如下(截取部分),假如當前預設 buffer 為 2048 [1024, 1152, 1280, 1408, 1536, 1664, 1792, 1920, 2048, 2304, 2560, 2816, 3072, 3328, 3584, 3840, 4096] | | | | A D B C 根據每次讀事件實際讀到的位元組數,進行預測下一次應該分配的 buffer 大小。 若實際讀到的位元組數大於等於當前 buffer( B 位置) 則將當前 buffer 增大到示 C 位置,每次增大步進為 4 若連續 2 次實際讀到的位元組數小於等於 A 位置指示的 buffer 大小,則縮小 buffer 到 D 位置 從上面的對比分析可以看出,mina 採用了相對簡單的 buffer 分配和預測方式,buffer 的增長和縮小比例相同。而 netty 採用了一種相對複雜點的 buffer 分配方式,buffer increment faster decrement slower。事實證明 netty 的分配方式更有效避免的 buffer 分配中的抖動問題(忽大忽小),而 buffer 分配抖動正是影響 io 吞吐的罪魁禍首。mina 測試中 5k 報文正好產生了 buffer 分配抖動導致 io 吞吐大受影響,通過修改 mina 源碼採用固定 buffer 大小來測試則有效避免了 buffer 抖動,io 吞吐也恢複正常。但實際情況下,固定 buffer 肯定不是有效方式,不能很好的適應各種網路環境的複雜性,但採用動態 buffer 分配時演算法需首要考慮避免抖動。 另外可以看出 netty 的 cpu 消耗明顯高出 mina 不少,懷疑 netty 採用的 executor 實現(OrderedMemoryAwareThreadPoolExecutor)存在比較多的鎖競爭和線程環境切換。下面是一組不使用 executor 時 netyy 的測試資料,其他指標都差不多但 cpu 明顯下降不少
| netty |
cpu |
| 1k |
75% |
| 2k |
125% |
| 5k |
126% |
| 10k |
126% |
| 50k |
118% |
| 100k |
116% |
測試總結mina: 需進一步最佳化其 buffer 分配,避免分配抖動導致的 io 吞吐波動netty: 需進一步最佳化預設 executor 的實現,降低 cpu 消耗 其實 netty2 和 mina 都出自同一人 Trustin Lee,後來他轉投 apache 項目組將 netty 交給了社區繼續維護,之後重新設計 mina 這個架構。從使用者感受上來說 mina 的 api 介面設計明顯比 netty 更優雅。
(轉)netty、mina效能對比分析