2012-11-07 27 views
15

Sto utilizzando un test JUnit con JERSEY Client + HTTPS per testare un secure web service in esecuzione su Jetty. Una delle mie chiamate a wr.get(ClientResponse.class) si blocca per 10 secondi dopo ogni blocco di 9-10 requests. Il codice Apache client equivalente viene eseguito in pochi millisecondi. Se cambio modalità Jetty to HTTP il problema scompare.Problema di prestazioni client HTTPS Jersey

Sto usando Jersey bundle & client 1.14 and Jetty 6.1.26



Il cliente apache funziona

@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(); 
    } 
} 
cliente



The Jersey pende

@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(); 
    } 
} 

Recupero l'entità da ClientResponse sembrano s per attivare il problema, ma solo nella modalità HTTPS e in esecuzione contro il mio server Web (non google, facebook, etc). Ho eseguito Jersey ServletContainer and Struts ActionServlet su Jetty e il problema si verifica con entrambi. Ho anche eseguito il server web su diversi computer sul mio subnet e sull'unità testata da più macchine.



classi HTTPS Jersey

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; 
} 



connettore Jetty SSL. Se utilizzo un SelectChannelConnector e un'unità test con HTTP, il problema scompare.

<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

tuo handshakeTimeout è di gran lunga troppo basso a 2000 ms. Cambialo per almeno 10-15 secondi. – EJP

+0

Ho aumentato l'handshakeTimeout a 15000ms e il problema si verifica ancora. – Karl

+0

Puoi creare una discarica di thread, ad es. con 'kill -3 pid' sul client mentre si blocca per vedere dove succede? –

risposta

1

Quali sistemi operativi funzionano?

Solo un'ipotesi, ma potrebbe essere correlato a un'implementazione lenta /dev/random (via SecureRandom).

discussione correlati qui:

How to solve performance problem with Java SecureRandom?

Dal momento che non si può sempre controllare i parametri JVM in una web app, ho usato questo come una soluzione alternativa:

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

Don' so se questo è strettamente raccomandato (ma risolve il problema per me).

+0

Ho eseguito Jetty su Linux 3.0.0-12-generic e 2.6.32.49.Ho aggiunto il blocco statico a una classe Java che viene caricata con Jetty e non ha aiutato. Il client Apache HTTPS funziona perfettamente con il mio server Jetty e il client Jersey funziona correttamente con https google. È solo quando il client Jersey viene eseguito contro il mio server Jetty, ma il problema si presenta. – Karl

0

Cercando di modificare l'implementazione TrustManager leggermente:

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 
      } 
     } 
    }; 

Inoltre, non dimenticare di chiamare HttpsURLConnection.setDefaultSocketFactory alla fine del vostro getSSLContext() metodo:

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

Non ho provato questo, ma ho finito per passare al client Apache che funziona bene per me. – Karl