Façons de mettre en mémoire tampon la réponse REST

Il existe un sharepoint terminaison REST, qui sert de gros morceaux de données (des dizaines de giga-octets) à mon application.
L’application traite les données à son rythme et, à mesure que les volumes de données entrants augmentent, je commence à atteindre le délai d’attente du sharepoint terminaison REST.
Cela signifie que la vitesse de traitement est inférieure à celle du réseau sur tout le réseau.
Malheureusement, il n’existe aucun moyen d’accroître suffisamment la vitesse de traitement car il n’ya pas assez de ressources: les volumes de données entrants peuvent augmenter indéfiniment.

Je réfléchis à un moyen de stocker les données entrantes localement avant le traitement, afin de libérer la connexion de sharepoint terminaison REST avant l’expiration du délai.

Ce qui m’arrive jusqu’à présent, c’est de télécharger les données entrantes dans un fichier temporaire et de lire (traiter) ledit fichier simultanément avec OutputStream / InputStream.
Sorte de mise en mémoire tampon, en utilisant un fichier.

Cela pose ses propres problèmes:

  • Et si la vitesse de traitement devenait plus rapide que la vitesse de téléchargement pendant un certain temps et que je recevais EOF?
  • l’parsingur de fichier fonctionne avec ObjectInputStream et se comporte bizarrement dans les cas de fichier vide / EOF
  • etc

Existe-t-il des moyens conventionnels de faire une telle chose?
Y a-t-il des solutions alternatives?
S’il vous plaît fournir des conseils.

Upd:

J’aimerais souligner que le serveur http est hors de mon contrôle.
Considérez-le comme un fournisseur de données fournisseur. Ils ont de nombreux consommateurs et refusent de modifier quoi que ce soit pour un seul.
On dirait que nous sums les seuls à utiliser toutes leurs données, car la vitesse de traitement de nos applications client est bien supérieure à celle de leurs exemples de mésortingques de performance. Néanmoins, nous ne pouvons pas faire correspondre les performances de nos applications avec le réseau tout au long de la production.

Le serveur ne prend pas en charge les demandes de plage http ni la pagination.
Il n’y a aucun moyen de diviser les données dans les blocs à charger, car aucun atsortingbut de filtrage ne garantit que chaque bloc sera suffisamment petit.

En bref: nous pouvons télécharger toutes les données dans un délai donné avant l’expiration du délai, mais nous ne pouvons pas les traiter.
Avoir un adaptateur entre inputstream et outpustream, à utiliser comme queue bloquante, vous aidera beaucoup.

Vous utilisez quelque chose comme le new ObjectInputStream(new FileInputStream(..._) et la solution pour EOF pourrait envelopper le FileInputStream premier dans un WriterAwareStream qui bloquerait si vous WriterAwareStream sur EOF tant que l’écrivain écrit.

Quoi qu’il en soit, au cas où la latence importerait peu, je ne prendrais pas la peine de commencer le traitement avant la fin du téléchargement. Souvent, vous ne pouvez pas faire grand chose avec une liste d’objects incomplète.

Peut-être qu’une queue basée sur des fichiers mappés en mémoire, telle que Chronicle-Queue, peut vous aider. C’est plus rapide que de traiter directement des fichiers et peut même être plus simple à utiliser.


Vous pouvez également implémenter HugeBufferingInputStream interne en utilisant une queue, qui lit à partir de son stream d’entrée, et, au cas où elle contient beaucoup de données, il les crache sur le disque. Cela peut être une belle abstraction, cachant complètement la mise en mémoire tampon.

Il existe également FileBackedOutputStream dans Guava, qui passe automatiquement de la mémoire à la taille d’un fichier, mais j’ai peur qu’il soit optimisé pour les petites tailles (avec des dizaines de gigaoctets attendus, rien ne sert d’essayer d’utiliser la mémoire).

Y a-t-il des solutions alternatives?

Si votre client (le client http) ne parvient pas à suivre le stream de données, vous pouvez envisager une conception dans laquelle le client gère son propre travail en cours, extrayant les données du serveur à la demande.

La RFC 7233 décrit les demandes de plage

les périphériques avec un stockage local limité pourraient bénéficier de la possibilité de ne demander qu’un sous-ensemble d’une représentation plus grande, telle qu’une seule page d’un très grand document ou les dimensions d’une image incorporée

Les demandes de plage HTTP sur le site Web Documents MDN peuvent constituer une introduction plus accessible.

C’est le genre de choses pour lesquelles les serveurs de files d’attente sont faits. RabbitMQ, Kafka, Kinesis, aucun de ceux-là. Peut-être que KStream fonctionnerait. Avec tout ce que vous obtenez du serveur HTTP (compte tenu de votre contrainte, il ne peut pas être divisé en unités de travail), vous pouvez le partitionner en blocs d’octets d’une taille raisonnable, peut-être 1024 Ko. Votre application envoie / publie ces enregistrements / messages dans la rubrique / la queue. Ils partagent tous un identifiant de série commun afin que vous sachiez quels morceaux correspondent, et chacun doit emporter un ordinal afin de pouvoir les remonter dans le bon ordre; avec une seule partition Kafka, vous pouvez probablement compter sur des compensations . Vous pouvez publier un enregistrement final pour cette série avec un drapeau “terminé” qui agira comme un EOF pour tout ce qui le consum. Bien sûr, vous enverriez une réponse HTTP dès que toutes les données sont en queue, même si elles ne sont pas nécessairement traitées pour le moment.

Je ne sais pas si cela vous aiderait dans votre cas car vous n’avez pas mentionné la structure et le format dans lesquels les données vous parviennent. Cependant, je supposerai un xml hiérarchisé, superbement normalisé et profondément nested (c.-à-d. quasiment le pire cas de streaming, non? … pega bix ?)

Je propose une solution partielle qui pourrait vous permettre de contourner la limitation de votre impossibilité de contrôler la façon dont votre client interagit avec le serveur de données http –

  1. déployez votre propre serveur Web, quelle que soit la technologie contemporaine que vous souhaitez (que vous contrôlez) – votre serveur local sera assis devant votre copie des données mise en cache localement

  2. Téléchargez périodiquement la sortie du service Web à l’aide d’une bibliothèque d’interrogation HTTP intégrée, un utilitaire commnd-line tel que aria2c curl wget et. al , un etl (ou ce que vous préférez) directement sur un fichier .xml local sauvegardé par un périphérique – cela se produit aussi souvent que nécessaire

  3. pointez votre client restant sur votre serveur 127.0.0.1/modern_gigabyte_large/get... hébergé sur votre ordinateur, au lieu de l’ancien serveur api.vendor.com/last_tested_on_megabytes/get... server

quelques idées:

  • vous devrez peut-être refactoriser votre modèle de données pour indiquer que les données de service Web XML consommées par vous et vos clients étaient datées de la dernière exécution réussie ^ (c’est-à-dire, mettez à jour cette date à la fin du prochain processus d’acquisition).

  • il serait théoriquement possible pour vous de transformer le XML sous-jacent en cours de route pour obtenir de meilleurs résultats en streaming vers votre client Webservice (si vous ne le faites pas déjà), mais cela demanderait des efforts – je pourrais en discuter davantage si un échantillon de la structure de données a été fourni

  • tout ce travail peut être exécuté en parallèle avec votre application existante, ce qui continue sur votre dernière version des “anciennes données” traitées avec succès jusqu’à la disponibilité de la nouvelle version “nouvelles données”


^ dans le commerce, vous devez maintenant gérer une “fenêtre glissante” de fichiers de données, où chaque “résultat” correspond à une instance spécifique de votre application téléchargeant les données du service Web et les stockant sur disque, puis les intégrant avec succès dans votre modèle:

  1. dernier (deux?) bon (s) résultat (s) compressé (selon mon expérience, des gigaoctets de xml sont très volumineux)

  2. prochain résultat en attente / provisoire pendant la diffusion sur disque / vérification d’intégrité / ingestion de données – (cela devient le “bon” résultat actuel et le dernier “bon” résultat devient le “bon précédent”)

  3. si nous supposons que vous êtes en train d’acquérir dans une firebase database relationnelle, les tables actuelles (et peut-être précédentes) avec les données du service Web chargées dans votre application, ainsi que la table attente suivante

  4. Basculer entre elles devient une opération de métadonnées, mais votre firebase database doit maintenant stocker au moins les données Webservice x2 (ou x3 – selon vos limitations)

  5. … oui, vous n’avez pas besoin de faire cela, mais vous souhaiterez le faire après quelque chose qui ne va pas 🙂

On dirait que nous sums les seuls à utiliser toutes leurs données

  • cela implique qu’il existe un moyen pour vous de partitionner ou de limiter le stream du service Web – comment les autres clients font-ils de la discrimination pour ne pas recevoir la totalité du mois?

Vous pouvez utiliser des techniques de mise en cache en mémoire OU vous pouvez utiliser des stream Java 8. Veuillez consulter le lien suivant pour plus d’informations: https://www.conductor.com/nightlight/using-java-8-streams-toprocess-large-amounts-of-data/

Camel pourrait peut-être vous aider à réguler la charge du réseau entre le producteur REST et le producteur?

Vous pouvez par exemple introduire un sharepoint terminaison Camel agissant en tant que proxy devant le sharepoint terminaison REST réel, appliquer une stratégie de limitation avant de transmettre au sharepoint terminaison réel:

from (” http: // localhost: 8081 / mywebserviceproxy “) .throttle (…) .to (” http://myserver.com:8080/myrealwebservice );

http://camel.apache.org/throttler.html http://camel.apache.org/route-throttling-example.html

Mes 2 centimes

Bernard

Si vous avez assez de mémoire, vous pouvez peut-être utiliser un magasin de données en mémoire comme Redis.

  • Lorsque vous recevez des données de votre terminal Rest, vous pouvez les enregistrer dans la liste Redis (ou dans toute autre structure de données appropriée).

  • Votre consommateur utilisera les données de la liste.