2012-07-06 67 views
0

編輯下面的第一條評論問題。多線程http/https中間代理服務器,Socket性能

我的問題主要是Java套接字的性能,特別是從目標服務器讀取。

該服務器是用於從火狐

主要問題每個連接創建客戶線程的簡單的ServerSocket.accept()循環是插座輸入流中讀取,對於巨大量的時間塊。

客戶線程如下:

//Take an httpRequest (hc.apache.org), raw string http request, and the firefox socket outputstream 
private void handle(httpRequest req, String raw, Outputstream out) 
{ 

     InputStream targetIn =null; 
     OutputStream targetOut = null; 
     Socket target = null; 

     try { 
     System.out.println("HANDLE HTTP"); 
      String host = req.getHeaders("Host")[0].getValue(); 
      URI uri = new URI(req.getRequestLine().getUri()); 
      int port = uri.getPort() != -1 ? uri.getPort() : 80; 
      target = new Socket(host, port); 


//**I have tried to play around with these but cannot seem to get a difference in performance** 

      target.setTcpNoDelay(true); 
//   target.setReceiveBufferSize(1024 *1024); 
//   target.setSendBufferSize(1024 * 1024); 


//Get your plain old in/out streams   
      targetIn = target.getInputStream(); 
      targetOut = target.getOutputStream(); 

//Send the request to the target 
      System.out.println("---------------Start response---------------"); 
      targetOut.write(raw.getBytes()); 
      System.out.println("request sent to target"); 

     ////Same as membrane    
      byte[] buffer = new byte[8 * 1024]; 
      int length = 0; 
      try { 
       while((length = targetIn.read(buffer)) > 0) { 
        out.write(buffer, 0, length); 
        out.flush(); 
       } 
      } catch(Exception e) { 
       e.printStackTrace(); 
      } 

      System.out.println("closing out + target socket"); 


//IOUTILS 
//   long count = IOUtils.copyLarge(targetIn, out, 0L, 1048576L); 
//   int count = IOUtils.copy(targetIn, out); 
//   System.out.println("transfered : " + count); 


//CHANNEL COPY 
// 
//   ReadableByteChannel input = Channels.newChannel(targetIn); 
//   WritableByteChannel output = Channels.newChannel(out); 
//   
//   ChannelTools.fastChannelCopy(input, output); 
//   
//   input.close(); 
//   output.close(); 


//CHAR TO CHAR COPY   
//   int c; 
//   while ((c = targetIn.read()) != -1) { 
//    out.write(c); 
//   } 


      target.close(); 
      out.close(); 

      System.out.println("-------------------- end response ------------------------------"); 
     } 
     catch (Exception e) { 
      // TODO Auto-generated catch block 
      e.printStackTrace(); 
     } 
    } 

的主要問題在於在適當的方法對目標的InputStream複製到客戶端(Firefox)的輸出流。

我用來測試這個網站是http://www.ouest-france.fr(新的網站與負載的圖像和負載的請求)。

從工作站平安到達目標:10ms的

在iceweasel正常負載(火狐的debian,螢火蟲時間):14秒,這背後代理2.5MB

加載:14分鐘(螢火蟲網面板是全假404s和中止的請求,在一段時間後回到黑色,負載的請求處於阻塞或等待模式)

現在,當執行我加載視覺虛擬機,啓動分析沒有類過濾器(看到哪裏應用程序真的花費時間),並且它在java.net.SocketInputStream.read(byte。)中花費了99%的時間[],int,int),它讀取目標套接字輸入流。

我想我已經完成了我的功課,並且正在尋找一個測試不同的解決方案,在任何地方我都可以。

但表現似乎從未改善。

我什麼,我已經嘗試過:

-Putting輸入和輸出流進他們的緩衝版本,在所有

-int沒有變化爲int副本,一點變化都沒有,

- 經典的byte []陣列拷貝可變大小陣列,根本沒有任何變化

擺弄settcpnodelay,setsendbuffersize,setreceivebuffersize,無法得到任何改變。

正在考慮嘗試使用nio套接字通道,但無法找到一種方法來對sslsocket進行套接字劫持。

所以目前我有點卡住和尋找解決方案。

我看着開源代理的源代碼,似乎無法找到邏輯的根本區別,所以我完全失去了這一點。

嘗試了其它試驗:

出口HTTP_PROXY = 「本地主機:4242」 的wget debiandvd.iso

吞吐量到達2MB/s的。 和線程似乎要花費66%的時間從目標讀取的33%的時間寫客戶端

我想,也許我有多個線程運行,但在www.google.com上運行測試要少得多請求貫通進入但仍然是同樣的問題www.ouest-france.fr

隨着debian iso測試我想我必須運行多個線程(ouest-france約270請求),但谷歌測試(10請求)測試似乎以確認線程號碼不是問題。

任何幫助將不勝感激。

環境是Debian的,太陽的java 1.6,偏差用eclipse和VisualVM的

根據需要我可以提供的代碼的其餘部分。

謝謝您發現

+3

對不起,但這個問題太長了。請編輯它以減少一些簡潔的問題。就目前而言,它太長太漫長。 – Gray 2012-07-06 15:29:35

回答

0

部分解決:

不是一個非常乾淨的解決方案,但工程。

我仍然有吞吐量問題。

我所做的是將套接字定時器設置爲正常超時(30000ms)。

當第一次讀取進入循環時,我將計時器重新設置爲更低的值(此時爲1000毫秒)。

這使我可以等待服務器開始發送數據,如果我得到1秒而沒有任何新數據傳入,我認爲傳輸已完成。

響應時間仍然很慢,但方式更好。