ThreadSafeClientConnManager nicht multithreading

Ich wurde gebeten, zu reparieren, ein Servlet ist, das sitzt zwischen zwei Anwendungen. Es ist Zweck ist, zu konvertieren SAML Autorisierungsanfrage an und aus SAML v2.0 /SAML-1.1. So ist es:

  • erhält eine HTTP SAML v2.0 Zulassung Anfrage von einer app
  • wandelt die Anfrage in SAML v1.1
  • sendet die Anfrage an die zweite app
  • empfängt das SAML v1.1 Antwort aus der zweiten app
  • konvertiert die Antwort in SAML v2.0
  • sendet die Antwort zurück an den ersten app

Mach dir keine sorgen über das SAML-Zeug, es ist die HTTP-Sachen das ist das problem. Der code tut seinen job, aber es leidet stark unter Last. Ich habe festgestellt, durch die Prüfung, dass obwohl der code nutzt eine ThreadSafeClientConnManager von Apache httpcomponents, wird jede Anforderung, die auf die servlet behandelt wird, in einer single-threaded Weise. Um es genauer, der zweite code erreicht die HTTPClient.execute() Methode der erste thread, der eine Verbindung erstellen, die ausgeführt wird durch den gesamten rest des Prozesses vor einem anderen thread beginnt zu arbeiten. Zum Beispiel:

  • 15 Anfragen trifft das servlet zur gleichen Zeit
  • servlet laicht 15 threads, um die Anforderungen
  • alle 15 threads abrufen Ihrer jeweiligen request-Daten
  • alle 15 threads konvertieren Ihre jeweiligen Daten aus SAML v2.0-SAML v1.1
  • Thread 1 ruft HTTPClient.execute()
    • Thread 1 sendet die Anforderung an die zweite app
    • Thread 1 erhält die Antwort von der zweiten app
    • Thread 1 decodiert die Antwort und wandelt es von SAML v1.1 zu SAML v2.0
    • Thread 1 sendet die Antwort zurück an den ersten app
  • Thread 2 ruft HTTPClient.execute()
  • ... und so weiter ...

Ich habe den folgenden code ein. Von was ich sehen kann, alle notwendigen Elemente vorhanden sind. Kann jemand sehen, dass etwas falsch ist oder fehlt, dass würde verhindern, dass dieses servlet von Wartungsarbeiten mehrere Anfragen zur gleichen Zeit?

public class MappingServlet extends HttpServlet {

private HttpClient client;
private String pdp_url;

public void init() throws ServletException {
    org.opensaml.Configuration.init();
    pdp_url = getInitParameter("pdp_url");

    ThreadSafeClientConnManager cm = new ThreadSafeClientConnManager();
    HttpRoute route = new HttpRoute(new HttpHost(pdp_url));
    cm.setDefaultMaxPerRoute(100);
    cm.setMaxForRoute(route, 100);
    cm.setMaxTotal(100);
    client = new DefaultHttpClient(cm);
}

protected void doPost(HttpServletRequest request, HttpServletResponse response)
    throws ServletException, IOException {

    long threadId = Thread.currentThread().getId();
    log.debug("[THREAD " + threadId + "] client request received");

    //Get the input entity (SAML2)
    InputStream in = null;
    byte[] query11 = null;
    try {
        in = request.getInputStream();
        query11 = Saml2Requester.convert(in);
        log.debug("[THREAD " + threadId + "] client request SAML11:\n" + query11);
    } catch (IOException ex) {
        log.error("[THREAD " + threadId + "]\n", ex);
        return;
    } finally {
        if (in != null) {
            try {
                in.close();
            } catch (IOException ioe) {
                log.error("[THREAD " + threadId + "]\n", ioe);
            }
        }
    }

    //Proxy the request to the PDP
    HttpPost httpPost = new HttpPost(pdp_url);
    ByteArrayEntity entity = new ByteArrayEntity(query11);
    httpPost.setEntity(entity);
    HttpResponse httpResponse = null;
    try {
        httpResponse = client.execute(httpPost);
    } catch (IOException ioe) {
        log.error("[THREAD " + threadId + "]\n", ioe);
        httpPost.abort();
        return;
    }

    int sc = httpResponse.getStatusLine().getStatusCode();
    if (sc != HttpStatus.SC_OK) {
        log.error("[THREAD " + threadId + "] Bad response from PDP: " + sc);
        httpPost.abort();
        return;
    }

    //Get the response back from the PDP
    InputStream in2 = null;
    byte[] resp = null;
    try {
        HttpEntity entity2 = httpResponse.getEntity();
        in2 = entity2.getContent();
        resp = Saml2Requester.consumeStream(in2);
        EntityUtils.consumeStream(in2);
        log.debug("[THREAD " + threadId + "] client response received, SAML11: " + resp);
    } catch (IOException ex) {
        log.error("[THREAD " + threadId + "]", ex);
        httpPost.abort();
        return;
    } finally {
        if (in2 != null) {
            try {
                in2.close();
            } catch (IOException ioe) {
                log.error("[THREAD " + threadId + "]", ioe);
            }
        }
    }

    //Convert the response from SAML1.1 to SAML2 and send back
    ByteArrayInputStream respStream = null;
    byte[] resp2 = null;
    try {
        respStream = new ByteArrayInputStream(resp);
        resp2 = Saml2Responder.convert(respStream);
    } finally {
        if (respStream != null) {
            try {
                respStream.close();
            } catch (IOException ioe) {
                log.error("[THREAD " + threadId + "]", ioe);
            }
        }
    }
    log.debug("[THREAD " + threadId + "] client response SAML2: " + resp2);

    OutputStream os2 = null;
    try {
        os2 = response.getOutputStream();
        os2.write(resp2.getBytes());
        log.debug("[THREAD " + threadId + "] client response forwarded");
    } catch (IOException ex) {
        log.error("[THREAD " + threadId + "]\n", ex);
        return;
    } finally {
        if (os2 != null) {
            try {
                os2.close();
            } catch (IOException ioe) {
                log.error("[THREAD " + threadId + "]\n", ioe);
            }
        }
    }
}

public void destroy() {
    client.getConnectionManager().shutdown();
    super.destroy();
}

}

Vielen Dank im Voraus!

InformationsquelleAutor Legs | 2011-09-29
Schreibe einen Kommentar