2.5.1 磁盤I/O優化
1. 性能檢測ios
2. 提高I/O性能緩存
2.5.2 TCP網絡參數調優網絡
要可以創建一個TCP鏈接,必須知道對方的IP和一個未被使用的端口號,因爲32位操做系統的端口號一般由兩個字節表示,也就是隻有2^16=65535個,因此一臺主機可以同時創建的鏈接數是有限的,固然操做系統還有一些端口0~1024是受保護的,如80端口、22端口,這些端口都不能被隨意佔用。併發
在Linux中能夠經過查看/proc/sys/net/ipv4/ip_local_port_range文件來知道當前這個主機可使用的端口範圍,如圖2-22所示。
異步
圖2-22表示可使用的端口爲61000-42768=18232。若是能夠分配的端口號偏少,在遇到大量併發請求時就會成爲瓶頸,因爲端口有限致使大量請求等待創建鏈接,這樣性能就會壓不上去。另外若是發現有大量的TIME_WAIT的話,能夠設置/proc/sys/net/ipv4/tcp_fin_timeout爲更小的值來快速釋放請求。咱們經過另一個主機ab -c 30 -n 1000000 10.232.101.208.8080/來壓測這臺機器,看看網絡的鏈接狀況,如圖2-23所示。
tcp
能夠看出TIME_WAIT的鏈接有26364個,咱們設置sudo sh -c "echo 3 > /proc/sys/net/ipv4/tcp_fin_timeout"後再進行測試,如圖2-24所示。
函數
調整後TIME_WAIT的數量明顯減小。除了增大端口範圍以外,還可讓TCP鏈接複用等,這些調優參數如表2-4所示。
工具
注意,以上設置都是臨時性的,系統從新啓動後就會丟失。另外iain,Linux還提供了一些工具可用於查看當前的TCP統計信息,以下所示。性能
2.5.3 網絡I/O優化測試
網絡I/O優化一般有以下一些基本處理原則。
減小網絡交互的次數。
減小網絡傳輸數據量的大小。
儘可能減小編碼。
根據應用場景設計合適的交互方式。所謂的交互場景主要包括同步與異步、阻塞與非阻塞方式,下面進行詳細介紹。
1. 同步與異步
2. 阻塞與非阻塞
3. 兩種方式的組合
組合的方式有4鍾,分別是同步阻塞、同步非阻塞、異步阻塞、異步非阻塞,如表2-5所示。
雖然異步和非阻塞可以提高I/O的性能,可是也會帶來一些額外的性能成本,例如,會增長線程數量從而增長CPU的消耗,同時也會致使程序設計複雜度的上升。
下面舉一些異步和阻塞的操做實例。
在Cassandra中要查詢數據一般會向多個數據節點發送查詢命令,可是要檢查每一個節點返回數據的完整性,就須要一個異步查詢同步結果的應用場景,部分代碼以下:
class AsyncResult implements IAsyncResult { private byte[] result_; private AtomicBoolean done = new AtomicBoolean(false); private Lock lock_ = new ReentrentLock(); private Condition condition_; private long startTime_; public AsyncResult() { condition_ = lock_.newCondition();//建立一個鎖 startTime_ = System.currentTimeMillis(); } //檢查須要的數據是否已經返回,若是沒有返回阻塞 public byte[] get() { lock_.lock(); try { if (!done_.get()) { condition_.await(); } } catch (InterruptedException ex) { throw new AssertionError(ex); } finally { lock_.unlock(); } return result_; } //檢查須要的數據是否已經返回 public boolean isDone() { return done_.get();} //檢查在指定的時間內須要的數據是否已經返回,若是沒有返回,拋出超時異常 public byte[] get (long timeout, TimeUnit tu) throws TimeoutException { lock_.lock(); try { boolean bVal = true; try { if ( !done_.get() ) { long overall_timeout = timeout - (System.currentTimeMillis() - startTime_); if (overall_timeout > 0) //設置等待超時的時間 bVal = condition_.await(overall_timeout, TimeUnit.MILLISECONDS); else bVal = false; } } catch (InterruptedException ex) { throw new AssertionError(ex); } if (!bVal && !done_.get()) { //拋出超時異常 throw new TimeoutException("Operation timed out."); } } finally { lock_.unlock(); } return result_; } //該函數供另一個線程設置要返回的數據,並喚醒在阻塞的線程 public void result(Message response) { try { lock_.lock(); if (!done_.get()) { result_ = response.getMessageBody();//設置返回的數據 done_.set(true); condition_.signal(); //喚醒阻塞的線程 } } finally { lock_.unlock(); } } }