Frage

Ich baue einen Java-Server, der skaliert werden muss.Eines der Servlets wird in Amazon S3 gespeicherte Bilder bereitstellen.

Kürzlich ging mir unter Last der Speicher in meiner VM aus, nachdem ich den Code zum Bereitstellen der Bilder hinzugefügt hatte. Ich bin mir also ziemlich sicher, dass das Streamen größerer Servlet-Antworten meine Probleme verursacht.

Meine Frage ist :Gibt es eine bewährte Methode zum Codieren eines Java-Servlets, um eine große Antwort (> 200.000) zurück an einen Browser zu streamen, wenn sie aus einer Datenbank oder einem anderen Cloud-Speicher gelesen wird?

Ich habe darüber nachgedacht, die Datei auf ein lokales temporäres Laufwerk zu schreiben und dann einen weiteren Thread zu erzeugen, der das Streaming übernimmt, damit der Tomcat-Servlet-Thread wiederverwendet werden kann.Das scheint, als wäre es sehr schwer.

Alle Gedanken wären willkommen.Danke.

War es hilfreich?

Lösung

Wenn möglich, sollten Sie den gesamten Inhalt einer Datei im Speicher bedient werden nicht gespeichert werden. Stattdessen einen Inputstream für die Daten, aquire und die Daten an das Servlet in Output Stücke kopieren. Zum Beispiel:

ServletOutputStream out = response.getOutputStream();
InputStream in = [ code to get source input stream ];
String mimeType = [ code to get mimetype of data to be served ];
byte[] bytes = new byte[FILEBUFFERSIZE];
int bytesRead;

response.setContentType(mimeType);

while ((bytesRead = in.read(bytes)) != -1) {
    out.write(bytes, 0, bytesRead);
}

// do the following in a finally block:
in.close();
out.close();

ich mit toby einverstanden, sollten Sie stattdessen "sie auf die S3-URL verweisen."

Wie für die OOM Ausnahme, sind Sie sicher, dass es mit dazu dient, die Bilddaten zu tun hat? Lassen Sie uns sagen, dass Ihre JVM 256 MB „extra“ Speicher für die Bedienung von Bilddaten zu verwenden hat. Mit Google-Hilfe „256MB / 200KB“ = 1310. Für 2GB „extra“ Speicher (in diesen Tagen eine sehr vernünftige Menge) über 10.000 gleichzeitige Clients unterstützt werden könnte. Trotzdem ist 1300 Clients gleichzeitig eine ziemlich große Zahl. Ist dies die Art der Last, die Sie erlebt haben? Wenn nicht, müssen Sie an anderer Stelle für die Ursache der OOM Ausnahme betrachten.

Bearbeiten - In Bezug auf:

  

In diesem Anwendungsfall die Bilder sensible Daten enthalten können ...

Wenn ich durch die S3-Dokumentation lesen vor ein paar Wochen, bemerkte ich, dass Sie Zeit ablaufenden Schlüssel generieren können, die S3 URLs befestigt werden kann. Also, würden Sie nicht die Dateien auf S3 für die Öffentlichkeit öffnen müssen. Mein Verständnis der Technik ist:

  1. Initial HTML-Seite hat Download-Links zu Ihrem Webapp
  2. Benutzer klickt auf einen Download-Link
  3. Ihre Webapp erzeugt eine S3-URL, die einen Schlüssel, lässt ausläuft umfasst, sagen, nur 5 Minuten.
  4. Senden Sie eine HTTP mit der URL aus Schritt 3 an den Client umgeleitet werden.
  5. Der Benutzer lädt die Datei aus dem S3. Dies funktioniert auch, wenn der Download mehr als 5 Minuten in Anspruch nimmt -. Sobald ein Download beginnt es bis zum Abschluss fortsetzen

Andere Tipps

Warum würden Sie nicht nur sie auf die S3-URL verweisen? ein Artefakt aus S3 nehmen und diese dann über einen eigenen Server zu mir Streaming besiegt den Zweck der Verwendung von S3, die die Bandbreite und Verarbeitung dienen, die Bilder, die auf Amazon abzuladen ist.

Ich habe eine Menge von Code wie john-vasilef des (derzeit angenommen) Antwort gesehen, eine enge while-Schleife Lese Brocken von einem Strom und teilt sie den anderen Strom zu schreiben.

Das Argument, das ich machen würde gegen unnötige Code-Duplizierung, für Apache IOUtils verwenden. Wenn Sie bereits an anderer Stelle verwenden, oder wenn eine andere Bibliothek oder Rahmen Sie verwenden bereits abhängig von ihm, es ist nur eine einzige Zeile, die bekannt ist und gut getestet.

Im folgenden Code, ich bin Streaming ein Objekt von Amazon S3 an den Client in einem Servlet.

import java.io.InputStream;
import java.io.OutputStream;
import org.apache.commons.io.IOUtils;

InputStream in = null;
OutputStream out = null;

try {
    in = object.getObjectContent();
    out = response.getOutputStream();
    IOUtils.copy(in, out);
} finally {
    IOUtils.closeQuietly(in);
    IOUtils.closeQuietly(out);
}

6 Zeilen eines gut definierten Muster mit dem richtigen Strom Schließung scheinen ziemlich solide.

Ich stimme stark mit beiden toby und John Vasileff - S3 ist ideal für off Laden großer Medienobjekte, wenn Sie die damit verbundenen Probleme tolerieren können. (Eine Instanz eigene App macht das für 10-1000MB FLVs und MP4s.) Z. B .: keine Teilanforderungen (Bytebereich-Header), though. Man muss damit umgehen, dass ‚manuell‘, gelegentlich Ausfallzeiten, etc ..

Wenn das nicht möglich ist, sieht Johns Code gut. Ich habe festgestellt, dass ein Byte-Puffer von 2k FILEBUFFERSIZE ist die effizienteste in Mikrobank Mark. Eine weitere Option könnte ein gemeinsames Filechannel sein. (FileChannels Thread-sicher ist.)

Das heißt, würde ich auch, dass bei Erraten hinzufügen, was eine außerhalb des Speicherfehler verursacht eine klassische Optimierung Fehler. Sie würden Ihre Erfolgschancen verbessern, indem sie mit harten Metriken arbeiten.

  1. Platz -XX: + HeapDumpOnOutOfMemoryError in Sie JVM-Startparameter, für alle Fälle
  2. Verwendung jmap auf dem laufenden JVM ( jmap -histo ) unter Last
  3. nehmen
  4. Analyize die Metriken (jmap -histo außer Betrieb gesetzt oder haben jhat auf Ihrem Heapdump aussehen). Es kann sehr gut sein, dass Ihr aus der Erinnerung von irgendwo unerwartet kommt.

Es gibt natürlich auch andere Tools gibt, aber jmap & jhat kommt mit Java 5+ 'out of the box'

  

Ich habe als die Datei auf einem lokalen Temp-Laufwerk zu schreiben und dann einen anderen Thread Laichen die Streaming zu handhaben, so dass der Tomcat Servlet Thread kann wiederverwendet werden. Dies scheint, wie es wäre io schwer sein.

Ach, ich glaube nicht, dass Sie nicht tun können. Und selbst wenn Sie könnten, klingt es zweifelhaft. Der tomcat Thread, der die Verbindung die Verwaltung muss in der Steuerung. Wenn Sie Thread Hunger erleben dann die Anzahl der verfügbaren Threads in ./conf/server.xml erhöhen. Auch hier sind Metriken die Möglichkeit, dies zu erkennen - dont denke nur.

Frage: Sind Sie auch auf EC2? Was sind Ihre Tomcats JVM-Parameter starten?

toby richtig ist, sollten Sie direkt auf S3 gerichtet sein, wenn Sie können. Wenn Sie sich nicht, die Frage ist ein wenig vage, eine genaue Antwort zu geben: Wie groß ist Ihr Java Heap? Wie viele Ströme sind gleichzeitig offen, wenn Sie über genügend Arbeitsspeicher ausgeführt?
Wie groß ist Ihre Lese-Schreib / Bufer (8K ist gut)?
Du liest gerade 8K aus dem Strom, dann 8k an den Ausgang zu schreiben, nicht wahr? Sie versuchen, nicht das ganze Bild von S3, Puffern im Speicher zu lesen, dann auf einmal die ganze Sache zu senden?

Wenn Sie 8K Puffer verwenden, können Sie 1000 gleichzeitige Streams haben in ~ 8Megs Heap-Raum gehen, so machst du auf jeden Fall etwas falsch ....

BTW

, ich habe nicht 8K holen aus der Luft, ist es die Standardgröße für die Socket-Puffer, mehr Daten senden, sagen 1Meg, und Sie werden auf dem TCP / IP-Stack blockiert eine große Menge an Speicher zu halten.

Sie haben zwei Dinge zu überprüfen:

  • Schließen Sie den Strom? Sehr wichtig
  • Sie geben Stream Verbindungen Vielleicht „kostenlos“. Der Strom ist nicht groß, aber viele viele Streams gleichzeitig können alle Ihre Speicher stehlen. Erstellen Sie einen Pool, so dass Sie nicht eine bestimmte Anzahl von Streams laufen zur gleichen Zeit haben

Zusätzlich zu dem, was John vorgeschlagen, sollten Sie immer wieder den Ausgangsstrom spülen. Abhängig von Ihrem Web-Container ist es möglich, dass es Teile-Caches oder sogar alle Ihre Ausgaben und spült es at-once (zB die Content-Length-Header zu berechnen). Das wäre ziemlich viel Speicher verbrennen.

Wenn Sie Ihre Dateien, so dass die statischen Dateien sind getrennt und in ihren eigenen Eimern strukturieren können, heute die schnellste Leistung kann wahrscheinlich mit Hilfe der Amazon S3 CDN erreicht werden, Cloudfront .

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top