2012-11-07 126 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