2012-11-07 129 views
15

我正在使用JUnit測試與JERSEY Client + HTTPS測試運行在Jetty上的secure web service。 的每個塊之後,我撥打wr.get(ClientResponse.class)的一個電話會掛起10秒鐘。等效的Apache client代碼在幾毫秒內運行。如果我切換Jetty to HTTP模式,則問題消失。澤西客戶端HTTPS性能問題

我使用Jersey bundle & client 1.14 and Jetty 6.1.26



的apache的客戶端工作

@Test 
public void testApacheClient() throws Exception 
{ 
    HttpClient client = new HttpClient(); 
    ProtocolSocketFactory socketFactory = new EasySSLProtocolSocketFactory(); 
    Protocol https = new Protocol("https", socketFactory, 443); 
    Protocol.registerProtocol("https", https); 

    //Finishes in < 1 second 
    for (int i = 0; i < 30; i++) 
    { 
    GetMethod getMethod = new GetMethod("https://localhost:8443/home"); 
    client.executeMethod(getMethod); 
    String entity = getMethod.getResponseBodyAsString(); 
    getMethod.releaseConnection(); 
    } 
} 



Jersey客戶端掛起

@Test 
public void testJerseyClient() throws Exception 

    HostnameVerifier hv = getHostnameVerifier(); 
    ClientConfig config = new DefaultClientConfig(); 
    SSLContext ctx = getSslContext(); 
    config.getProperties().put(HTTPSProperties.PROPERTY_HTTPS_PROPERTIES, 
     new HTTPSProperties(hv, ctx)); 

    Client jerseyClient = Client.create(config); 

    //Finishes in < 1 second 
    for (int i = 0; i < 30; i++) 
    { 
    WebResource wr = jerseyClient.resource("https://www.google.com"); 
    ClientResponse cr = wr.get(ClientResponse.class); 
    String entity = cr.getEntity(String.class); 
    cr.close(); 
    } 

    /* Pauses for 10 seconds after the 10th request, and subsequently after every 9th request. 
    Debugging shows waiting at line 'ClientResponse cr = ...' 
    */ 
    for (int i = 0; i < 30; i++) 
    { 
    WebResource wr = jerseyClient.resource("https://localhost:8443/home"); 
    ClientResponse cr = wr.get(ClientResponse.class); //10 second pause after requests 9, 18, 27 
    String entity = cr.getEntity(String.class); //This is triggering the problem 
    cr.close(); 
    } 

    //Finishes in < 1 second 
    for (int i = 0; i < 30; i++) 
    { 
    WebResource wr = jerseyClient.resource("https://localhost:8443/home"); 
    ClientResponse cr = wr.get(ClientResponse.class); 
    cr.close(); 
    } 
} 

ClientResponse檢索實體似乎s來觸發問題,但只在HTTPS模式下運行,並針對我的web服務器(而不是google, facebook, etc)運行。我在Jetty上運行Jersey ServletContainer and Struts ActionServlet,並且兩者都出現問題。我還在我的subnet上的不同機器上運行網絡服務器,並在多臺機器上測試了這些單元。



澤西HTTPS類

private HostnameVerifier getHostnameVerifier() { 
    HostnameVerifier hv = new HostnameVerifier() { 
    public boolean verify(String arg0, SSLSession arg1) { return true; } 
    }; 
    return hv; 
} 

private SSLContext getSslContext() throws Exception {  
    private final SSLContext sslContext = SSLContext.getInstance("SSL"); 
    sslContext.init(null, new TrustManager[] { new X509TrustManager() { 
     public X509Certificate[] getAcceptedIssuers() { return new X509Certificate[0]; } 
     public void checkClientTrusted(X509Certificate[] certs, String authType) {} 
     public void checkServerTrusted(X509Certificate[] certs, String authType) {} 
     } 
    }, new SecureRandom() 
); 
    return sslContext; 
} 



碼頭SSL連接器。如果我使用SelectChannelConnector和HTTP進行單元測試,問題就會消失。

<Call name="addConnector"> 
    <Arg> 
    <New class="org.mortbay.jetty.security.SslSocketConnector"> 
     <Set name="allowRenegotiate">true</Set> 
     <Set name="Port">8443</Set> 
     <Set name="reuseAddress">true</Set> 
     <Set name="Host">mgmt-int</Set> 
     <Set name="maxIdleTime">30000</Set> 
     <Set name="handshakeTimeout">2000</Set> 
     <Set name="keystore"><SystemProperty name="jetty.home" default="/usr/app/web-app"/>/conf/keystore.jetty</Set> 
     <Set name="password">OBF:1vaaaaaaaaaaaaaaaaaaaa111111111v</Set> 
     <Set name="keyPassword">OBF:1vaaaaaaaaaaaaaaaaaaaa111111111v</Set> 
    </New> 
    </Arg> 
</Call> 
+0

你handshakeTimeout過於低至2000ms。將其更改爲至少10-15秒。 – EJP

+0

我將handshakeTimeout增加到了15000ms,問題仍然存在。 – Karl

+0

你可以創建一個線程轉儲例如用'kill -3 pid'在客戶端掛起時看到發生了什麼? –

回答

1

這些運行的操作系統是什麼?

只是猜測,但它可能與執行緩慢/dev/random(通過SecureRandom)有關。

相關討論在這裏:

How to solve performance problem with Java SecureRandom?

因爲我不能總是在web應用控制JVM參數,我一直在使用這個作爲一種解決方法:

static { 
    System.setProperty("java.security.egd", "file:///dev/urandom"); 
} 

別不知道這是否嚴格建議(但它解決了我的問題)。

+0

我已經在Linux 3.0.0-12-generic和2.6.32.49上運行Jetty。我將靜態塊添加到了用Jetty加載的Java類中,並沒有幫助。 Apache HTTPS客戶端可以正常使用我的Jetty服務器,並且Jersey Client可以正常使用https google。只有當Jersey客戶端運行在我的Jetty服務器上時,問題纔會出現。 – Karl

0

試圖稍微修改您的TrustManager實現:也

TrustManager[] trustAllCerts = new TrustManager[] { 
     new X509TrustManager() { 
      public X509Certificate[] getAcceptedIssuers() { 
       return null; 
      } 

      public void checkClientTrusted(X509Certificate[] certs, String authType) { 
       // Trust always 
      } 

      public void checkServerTrusted(X509Certificate[] certs, String authType) { 
       // Trust always 
      } 
     } 
    }; 

,不要忘記調用HttpsURLConnection.setDefaultSocketFactory你getSSLContext的end()方法:

HttpsURLConnection.setDefaultSSLSocketFactory(sslContext.getSocketFactory()); 
+0

我還沒有嘗試過這個,但是我最終切換到了適合我的Apache客戶端。 – Karl