Question

Je suis la construction d'un serveur java besoins à l'échelle.L'un des servlets sera de servir les images stockées dans Amazon S3.

Récemment, sous la charge, j'ai couru hors de la mémoire dans ma VM et c'était après que j'ai ajouté le code pour servir les images donc je suis assez sûr que le streaming plus servlet réponses est à l'origine de mes ennuis.

Ma question est :est-il les meilleures pratiques en matière de code java servlet pour diffuser une grande (>200) réponse à un navigateur lors de la lecture à partir d'une base de données ou de stockage sur le cloud?

J'ai envisagé d'écrire le fichier vers un lecteur temp et puis fraie un autre thread pour gérer la diffusion en continu de sorte que la servlet tomcat fil peut être ré-utilisé.Cela semble comme il serait io lourd.

Toute pensée serait appréciée.Merci.

Était-ce utile?

La solution

Lorsque cela est possible, vous ne devez pas stocker l'intégralité du contenu d'un fichier pour être servi dans la mémoire.Au lieu de cela, l'acquisition d'un InputStream pour les données, et de copier les données de la Servlet OutputStream en morceaux.Par exemple:

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

Je suis d'accord avec toby, vous devriez au lieu de "point à l'url S3."

Comme pour le OOM exception, êtes-vous sûr qu'il a à faire avec de servir les données de l'image?Disons que votre JVM a 256 mo de "extra" de la mémoire à utiliser pour traiter les données d'image.Avec Google aide", 256 mo de mémoire 200KO" = 1310.Pour 2 GO "extra" de la mémoire (de nos jours un très raisonnable) de plus de 10 000 clients simultanées pourraient être pris en charge.De même, 1300 clients simultanés est un assez grand nombre.Est-ce le type de charge que vous avez vécu?Si non, vous devrez peut-être chercher ailleurs la cause de l'OOM exception.

Edit - En Ce Qui Concerne:

Dans ce cas d'utilisation, les images peuvent contenir des données sensibles...

Quand j'ai lu le S3 de la documentation il y a quelques semaines, j'ai remarqué que vous pouvez générer des temps d'expiration de touches qui peut être attaché à S3 Url.Donc, vous n'auriez pas à ouvrir les fichiers sur S3 pour le public.Ma compréhension de la technique, c'est:

  1. Initiale page HTML a des liens de téléchargement à votre webapp
  2. L'utilisateur clique sur un lien de téléchargement
  3. Votre webapp génère une URL S3 qui comprend une clé expire dans, disons 5 minutes.
  4. Envoyer une redirection HTTP vers le client avec l'URL à partir de l'étape 3.
  5. L'utilisateur télécharge le fichier à partir de S3.Cela fonctionne même si le téléchargement ne prend plus de 5 minutes - une fois le téléchargement démarre, il peut continuer jusqu'à la fin.

Autres conseils

Pourquoi ne pas vous venez de pointer vers l'url S3?En prenant un artefact de S3, puis de les diffuser par le biais de votre propre serveur et de me défait le but de l'utilisation de la S3, qui est de déchargement de la bande passante et le traitement de servir les images pour Amazon.

J'ai vu beaucoup de code comme jean-vasilef est (actuellement acceptées), un serré tandis que la boucle de lecture des morceaux à partir d'un flux et de les écrire pour les autres flux.

L'argument que je voudrais faire est par contre inutile duplication de code, en faveur de l'utilisation d'Apache IOUtils.Si vous utilisez déjà un autre endroit, ou si une autre bibliothèque ou d'un cadre que vous utilisez déjà, selon elle, c'est une seule ligne qui est connu et bien testé.

Dans le code suivant, je suis en streaming un objet à partir d'Amazon S3 pour le client dans un 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 lignes d'un plan bien défini avec un bon flux de clôture semble assez solide.

Je suis d'accord fortement avec les deux toby et Jean Vasileff--S3 est idéal pour désactiver le chargement d'un grand support des objets si vous pouvez tolérer les problèmes qui y sont associés.(Une instance de la propre application n'est que pour 10-1000MB les fichiers flv et MP4s.) E. g.:Aucun partielle des demandes (plage d'octets d'en-tête), si.L'un a pour le gérer "manuellement", occasionnelle de temps d'arrêt, etc..

Si ce n'est pas une option, John, le code semble bon.J'ai trouvé que un tampon d'octets de 2k FILEBUFFERSIZE est le plus efficace en microbench marques.Une autre option pourrait être partagée FileChannel.(FileChannels sont thread-safe.)

Cela dit, je voudrais aussi ajouter que faire des suppositions sur ce qui a causé une erreur de mémoire insuffisante est un classique de l'optimisation de l'erreur.Vous permettrait d'améliorer vos chances de succès en travaillant avec dur métriques.

  1. Lieu -XX:+HeapDumpOnOutOfMemoryError en vous JVM paramètres de démarrage, juste au cas où
  2. utiliser jmap sur le fonctionnement de la JVM (jmap -histo <pid>) sous la charge
  3. Analyize les mesures (jmap -histo mettre à, ou ont jhat regardez votre heap dump).Il peut très bien être que votre mémoire est venue de quelque part d'inattendu.

Il y a bien sûr d'autres outils, mais jmap & jhat venir avec Java 5+ 'out of the box'

J'ai envisagé d'écrire le fichier vers un lecteur temp et puis fraie un autre thread pour gérer la diffusion en continu de sorte que la servlet tomcat fil peut être ré-utilisé.Cela semble comme il serait io lourd.

Ah, je ne pense pas que vous ne pouvez pas le faire.Et même si tu le pouvais, il semble douteux.Le tomcat thread qui gère la connexion de contrôle.Si vous rencontrez des threads puis augmenter le nombre de threads disponibles dans ./conf/server.xml.De nouveau, les mesures sont le moyen de détecter ce-ne pas deviner juste.

Question:Êtes-vous également en cours d'exécution sur EC2?Quels sont vos tomcat JVM de démarrage des paramètres?

toby est à droite, vous devez pointer droit à S3, si vous le pouvez.Si vous ne pouvez pas, la question est un peu vague pour donner une réponse exacte:Quelle est la taille de votre tas java?Comment de nombreux cours d'eau sont ouverts simultanément lorsque vous exécutez hors de la mémoire?
Quelle est la taille de votre lecture et en écriture/bufer (8K est bonne)?
Vous êtes la lecture de 8K à partir du flux, puis l'écriture de 8k à la sortie, à droite?Vous n'êtes pas d'essayer de lire l'ensemble de l'image à partir de S3, tampon en mémoire, puis envoyer le tout à la fois?

Si vous utilisez 8K tampons, vous pouvez avoir 1000 flux simultanés aller dans ~8Megs des tas d'espace, de sorte que vous êtes certainement fait quelque chose de mal....

BTW, je n'ai pas chercher 8K hors de l'air mince, c'est la taille par défaut pour la prise tampons, envoyer plus de données, dire 1Meg, et vous serez blocage sur la pile tcp/ip de la tenue d'une grande quantité de mémoire.

Vous devez vérifier deux choses:

  • Êtes-vous fermeture le flux?Très important
  • Peut-être que vous donnez flux connexions "gratuitement".Le flux n'est pas grand, mais de nombreux de nombreux cours d'eau en même temps peut voler toute votre mémoire.Créer un pool de sorte que vous ne pouvez pas avoir un certain nombre de cours d'eau cours d'exécution dans le même temps

En plus de ce que Jean a suggéré, vous devriez rincer abondamment plusieurs fois le flux de sortie.En fonction de votre conteneur web, il est possible qu'il met en cache les parties ou la totalité de votre sortie et les tient à la fois (par exemple, pour calculer la Longueur du Contenu de l'en-tête).Qui pouvait brûler un peu de mémoire.

Si vous pouvez, de la structure de vos fichiers ainsi que les fichiers statiques sont séparés et dans leur propre seau, la performance la plus rapide aujourd'hui peut vraisemblablement être obtenue par l'utilisation du Amazon S3 CA, CloudFront.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top