2010-11-27 31 views
3

J'ai besoin d'utiliser cURL en PHP pour faire des milliers de requêtes cURL à une API. Mon plan actuel est de les faire en parallèle avec les fonctions curl_multi_(). Fondamentalement, exécuter simultanément toutes les demandes de cURL en parallèle.Ouverture de milliers de poignées cURL sans problèmes? (PHP)

J'ai entendu dire que vous pouvez rencontrer des problèmes de mémoire en ouvrant trop de poignées, ce qui peut entraîner des erreurs fatales. Comment peut éviter cela et toujours faire mes demandes d'URL aussi vite que possible?

Si j'ai besoin de limiter le nombre de demandes cURL à faire à la fois, à quoi bon # définir la limite? Contexte: Je suis en ce moment sur un hébergement partagé avec Godaddy, ce qui me convient parfaitement avec les requêtes cURL, bien que je ne l'ai pas testé avec des milliers de requêtes parallèles. Dans le futur, je serai sur un Rackspace Cloud Site qui peut gérer une charge modeste.

Cet énorme nombre de requêtes cURL est une chose une fois par an, et ne fait pas partie des opérations quotidiennes du site.

Répondre

5

Cela ressemble à un problème d'architecture. Pourquoi avez-vous besoin de faire des milliers de demandes en même temps? Est-ce que ce genre de parellisme va faire du bien, ou allez-vous accidentellement DOS (Denial-of-Service) un mauvais service web/API suspect?

En supposant que vous ne battez pas un seul serveur distant, vous devez toujours vous soucier du nombre de connexions que votre boîte locale peut gérer. Il y a seulement beaucoup de ports que vous pouvez utiliser sortants, et ils sont mesurés dans les quelques dizaines de milliers. Il n'est pas difficile d'atteindre cette limite si vous êtes en train d'ouvrir des connexions. Quiconque fait un test de chargement avec apachebench le sait.

PHP n'est pas un excellent outil pour ce genre de chose - et je suis un gars qui fait 90% de PHP. Il n'y a pas de threading, et c'est très gourmand en mémoire. Si vous voulez 1000 processus PHP en parallèle, vous aurez besoin de plus d'une machine. Votre processus PHP typique va consommer environ 10 à 20 Mo de mémoire, à moins que vous ne l'ayez réglé (probablement au moment de la compilation.)

Vous dites que cela se produit une fois par an. Et si vous n'aviez que 24 ou 36 processus parallèles, que se passe-t-il si vous n'aviez que 24 ou 36 processus parallèles?

Cela dit, voici comment j'approcherais probablement ceci: PHP fonctionnera probablement bien, et si vous rencontrez des problèmes d'inefficacité de la mémoire, vous pouvez échanger sur une seule partie que vous voulez deux, les files d'attente plus ou moins asynchrones, et une paire de processus qui y travaillent.

  • a "fetch queue" - une file d'attente de travail de requêtes HTTP à réaliser. Ils effectuent la requête et collent les données dans la file d'attente de traitement (voir puce suivante).

  • Une "file d'attente de traitement" est une file d'attente de travail fonctionnant avec toutes les réponses HTTP. A mesure que la file d'attente est traitée, elle peut ajouter de nouveaux éléments à "récupérer la file"

  • Processus (ou quelques dizaines) s'exécutant en parallèle et fonctionnant dans la file d'attente de récupération. Le parallélisme est sympa ici, puisque vous avez tellement de latence due au réseau.

  • Certains processus qui mâchent sur la "file d'attente de traitement" - il n'est pas clair que le parallélisme aidera ici. Tout ce traitement se passe localement, et peut probablement être une simple boucle.

+0

Votre point que je repenser cette méthode sonne vrai. D'une certaine manière, il n'est pas strictement nécessaire pour moi d'utiliser l'API. Je vais accepter votre réponse pour ceux qui en bénéficieraient en plus de moi-même. – babonk

+0

Bon - c'est juste un cas typique de «diviser pour régner» - divisez le travail en différents petits travaux, puis concentrez-vous sur l'exécution efficace de ce tas de tâches. Si vous deviez le faire tous les jours, vous pourriez mettre à l'échelle la solution que je décris jusqu'à un certain nombre de machines, de récupération et de traitement, dans un rapport que vous auriez à déterminer par essais et erreurs. – timdev

0

Pas assez d'informations vraiment. Quelle quantité de bande passante sera utilisée pour chaque connexion? à moins que ce soit un couple d'octets, vous étoufferez la plupart des connexions ouvrant autant de prises à la fois. Même si votre compte est plafonné, votre idée de socket 1000 sera goulot et rendue inutile. Pourquoi ne peux-tu pas ouvrir 100 sockets et boucler comme celui que l'on termine. c'est très rapide

1

Découvrez Rolling Curl. Je l'ai utilisé pour extraire les liens et le contenu de la page Web à partir de plusieurs pages de pages Web. Je n'ai aucune idée de comment cela fonctionnera sur le serveur car je n'ai qu'une expérience sur les machines locales.

1

Toutes les choses suggérées par timdev sont enveloppées dans Zebra cURL https://github.com/stefangabos/Zebra_cURL. vous pouvez passer un tableau d'URL et en mettre en file d'attente (par défaut 10) en parallèle, puis les appeler et passer un objet résultat dans un rappel. Des GitHub docs:

<?php 
     function callback($result) { 
      // remember, the "body" property of $result is run through 
      // "htmlentities()", so you may need to "html_entity_decode" it 
      // show everything 
      print_r('<pre>'); 
      print_r($result->info); 
     } 
     require 'path/to/Zebra_cURL.php'; 
     // instantiate the Zebra_cURL class 
     $curl = new Zebra_cURL(); 
     // cache results 60 seconds 
     $curl->cache('cache', 60); 
     // get RSS feeds of some popular tech websites 
     $curl->get(array(
      'http://rss1.smashingmagazine.com/feed/', 
      'http://allthingsd.com/feed/', 
      'http://feeds.feedburner.com/nettuts', 
      'http://www.webmonkey.com/feed/', 
      'http://feeds.feedburner.com/alistapart/main', 
     ), 'callback'); 
    ?> 

Il est vraiment rapide et doux sur l'utilisation de la mémoire