L'utilisation d'Internet Explorer pour appeler PHP / CURL pour une API de données de longue durée provoque le gel du serveur Apache 2 et nécessite un redémarrage

10

J'exécute un programme PHP qui fonctionne bien tant qu'il n'est pas invoqué par un navigateur Microsoft Internet Explorer, après quoi il génère les processus ci-dessous, verrouille Apache 2 et nécessite un redémarrage du serveur Web (sur Ubuntu 12.04 LTS).

bob@drools:/etc/php5/apache2# ps auxwww | grep apache2
root      8737  0.1  2.5 369164 25800 ?        Ssl  12:41   0:00 /usr/sbin/apache2 -k start
www-data  8743  0.0  3.2 393748 33268 ?        Sl   12:41   0:00 /usr/sbin/apache2 -k start
www-data  8755  0.1  3.3 393856 33904 ?        Sl   12:41   0:00 /usr/sbin/apache2 -k start
www-data  8779  0.1  3.2 393724 33252 ?        Sl   12:45   0:00 /usr/sbin/apache2 -k start
www-data  8782  0.1  3.2 393716 33236 ?        Sl   12:45   0:00 /usr/sbin/apache2 -k start
www-data  8785  0.1  3.2 393684 33204 ?        Sl   12:45   0:00 /usr/sbin/apache2 -k start
www-data  8812  1.1  3.2 393684 33264 ?        Sl   12:47   0:00 /usr/sbin/apache2 -k start
www-data  8815  1.3  3.2 393684 33264 ?        Sl   12:47   0:00 /usr/sbin/apache2 -k start
www-data  8818  1.3  3.2 393684 33264 ?        Sl   12:47   0:00 /usr/sbin/apache2 -k start
www-data  8821  1.5  3.2 393684 33264 ?        Sl   12:47   0:00 /usr/sbin/apache2 -k start
www-data  8824  1.4  3.2 393684 33264 ?        Sl   12:47   0:00 /usr/sbin/apache2 -k start
www-data  8827  1.4  3.2 393684 33264 ?        Sl   12:47   0:00 /usr/sbin/apache2 -k start
www-data  8830  1.4  3.2 393684 33264 ?        Sl   12:47   0:00 /usr/sbin/apache2 -k start
www-data  8835  2.5  3.2 393684 33256 ?        Sl   12:47   0:00 /usr/sbin/apache2 -k start
www-data  8838  2.8  3.2 393684 33264 ?        Sl   12:47   0:00 /usr/sbin/apache2 -k start
www-data  8841  2.5  3.2 393684 33264 ?        Sl   12:47   0:00 /usr/sbin/apache2 -k start
www-data  8844  2.5  3.2 393684 33264 ?        Sl   12:47   0:00 /usr/sbin/apache2 -k start
www-data  8847  3.2  3.2 393684 33264 ?        Sl   12:47   0:00 /usr/sbin/apache2 -k start
www-data  8850  3.0  3.2 393684 33264 ?        Sl   12:47   0:00 /usr/sbin/apache2 -k start
www-data  8853  3.2  3.2 393684 33264 ?        Sl   12:47   0:00 /usr/sbin/apache2 -k start
www-data  8856  3.2  3.2 393684 33264 ?        Sl   12:47   0:00 /usr/sbin/apache2 -k start
www-data  8861  3.3  3.2 393684 33264 ?        Sl   12:47   0:00 /usr/sbin/apache2 -k start
www-data  8864  3.6  3.2 393684 33264 ?        Sl   12:47   0:00 /usr/sbin/apache2 -k start
www-data  8867  3.5  3.2 393684 33264 ?        Sl   12:47   0:00 /usr/sbin/apache2 -k start
www-data  8870  3.6  3.2 393684 33264 ?        Sl   12:47   0:00 /usr/sbin/apache2 -k start
www-data  8873  3.6  3.2 393684 33264 ?        Sl   12:47   0:00 /usr/sbin/apache2 -k start
www-data  8876  3.5  3.2 393684 33264 ?        Sl   12:47   0:00 /usr/sbin/apache2 -k start
www-data  8879  3.3  3.2 393684 33264 ?        Sl   12:47   0:00 /usr/sbin/apache2 -k start
www-data  8881  3.5  3.2 393684 33264 ?        Sl   12:47   0:00 /usr/sbin/apache2 -k start
www-data  8883  3.6  3.2 393684 33264 ?        Sl   12:47   0:00 /usr/sbin/apache2 -k start
www-data  8886  3.5  3.2 393684 33264 ?        Sl   12:47   0:00 /usr/sbin/apache2 -k start
www-data  8891  3.5  3.2 393684 33264 ?        Sl   12:47   0:00 /usr/sbin/apache2 -k start
www-data  8894  3.5  3.2 393684 33264 ?        Sl   12:47   0:00 /usr/sbin/apache2 -k start
www-data  8896  3.5  3.2 393684 33264 ?        Sl   12:47   0:00 /usr/sbin/apache2 -k start
www-data  8900  3.5  3.2 393684 33264 ?        Sl   12:47   0:00 /usr/sbin/apache2 -k start
www-data  8901  3.5  3.2 393684 33264 ?        Sl   12:47   0:00 /usr/sbin/apache2 -k start
www-data  8904  3.5  3.2 393684 33264 ?        Sl   12:47   0:00 /usr/sbin/apache2 -k start
www-data  8909  3.8  3.2 393684 33264 ?        Sl   12:47   0:00 /usr/sbin/apache2 -k start
www-data  8912  3.8  3.2 393684 33264 ?        Sl   12:47   0:00 /usr/sbin/apache2 -k start
www-data  8915  3.8  3.2 393684 33264 ?        Sl   12:47   0:00 /usr/sbin/apache2 -k start
www-data  8918  3.6  3.2 393684 33260 ?        Sl   12:47   0:00 /usr/sbin/apache2 -k start
root      8922  0.0  0.1   9396  2000 pts/0    S+   12:47   0:00 grep --color=auto apache2

Il sert à verrouiller le serveur entier jusqu'à ce que je change certains des paramètres du module " mpm_ " en quelque chose de plus raisonnable dans /etc/spache2/apache2.conf .

Compte tenu des problèmes avec Internet Explorer, j'ai même ajouté cette ligne:

**" SetEnvIf User-Agent ".*MSIE.*"   nokeepalive "**

dans le fichier des hôtes virtuels situé ici: / etc / apache2 / sites-available.

Il existe un certain nombre d'articles écrits sur la question, mais je n'ai pas réussi à les mettre en œuvre:

Apache Server 2 se bloque après réception des demandes d'IE 10/11 :

Plus de R&D: Internet Explorer 10 (Windows 8) plante Apache

Le programme PHP utilise cURL pour prendre une liste de 25 éléments et effectuer un appel API (GET) pour chacun à un serveur externe qui renvoie les données JSON pour un traitement ultérieur. C'est un programme de données classique de longue durée.

Ce qui fait cuire mes nouilles, c'est qu'elles fonctionnent bien dans tous les autres navigateurs, à l'exception d'Internet Explorer - ce qui provoque un mauvais comportement du serveur Web.

J'ai interrogé la R&D répertoriée, puis certains ont implémenté les correctifs suggérés, mais j'ai toujours le même comportement de serveur prévisible, récréatif et problématique.

J'ai besoin de comprendre comment protéger le serveur contre tout mauvais comportement lorsqu'il rencontre et le navigateur Internet Explorer en faisant ces demandes particulières. J'aimerais comprendre pourquoi cela se produit en premier lieu.

Tout conseil, perspective, direction ou solution serait grandement apprécié ...

Voici un instantané de mon code cURL:

<?php

// *** CURL Init, SetOps, and Execution Statements ****
$ch = curl_init();


// *** Execute the  API call for each part number and store in the Associative Array ****
$index=0;
foreach ($partNumbersArray as $partNum) {

    $MyValue = $partNum;

    $MyUrl = $MyNiinjaBaseURL."/".$APICmd1."/".$MyDataSet."/".$MyValue."?key=".$MyKey."&$"."filter=substringof('".$MyValue."',PartNumbers)";


    // *** cURL SetOpts, and Execution Statements ****
    curl_setopt($ch, CURLOPT_URL, $MyUrl);
    curl_setopt($ch, CURLOPT_HEADER, 0);
    curl_setopt($ch, CURLOPT_FRESH_CONNECT, true);
    // curl_setopt($ch, CURLOPT_TIMEOUT, 15);       // <= THIS *never* worked with any reliability ....
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);

    $server_output = curl_exec ($ch);   // <= THIS executes the cURL call and stores the resulting JSON object in the variable '$server_output'

    $niinjaResultsJsonArray[$MyValue] = $server_output;        // Add the JSON object to the Array and index to PartNumber
    $index++;                                                // Increment the index

} // End Execution of NIINJA API Calls

// ** Close the CURL Object and release resources
curl_close ($ch);

?>

Voici la page d'informations PHP: http://www.versaggi.net/phptest.phtml

ProfVersaggi
la source
1
Je pense que vous devez en quelque sorte enregistrer les demandes HTTP entrantes complètes à la fois d'IE et d'un autre navigateur qui n'a pas de problème afin que nous puissions les comparer et rechercher des différences. Veuillez consulter cette question pour savoir comment vous pouvez le faire. Il doit y avoir quelque chose qu'IE fait avec la requête HTTP (un en-tête supplémentaire ou manquant, etc.?) Qui conduit Apache à la traiter différemment. Soit ça, soit c'est à un niveau inférieur (paquets IP), ce que je n'espère certainement pas.
Stijn de Witt
J'y mets une prime pour, espérons-le, vous aider à attirer l'attention sur votre question.
Stijn de Witt
2
En y réfléchissant un peu plus, vous pourriez probablement signaler cela à Apache comme un bug ... Parce qu'il n'y a vraiment aucun moyen que je puisse expliquer cela comme n'étant pas un bug Apache. Cela pourrait également vous aider à obtenir des gourous Apache très expérimentés pour examiner le problème (et, espérons-le, le résoudre). Si vous souhaitez suivre cette voie, il peut être utile de réduire la page rencontrant le problème dans le plus petit scénario possible qui présente toujours le problème. Cela peut être utile en soi de toute façon.
Stijn de Witt
Définissez un délai d'expiration dans curl à l'aide de setopt
user1050544
3
Le client a-t-il une influence sur les URL auxquelles le script php accède? Les demandes cURL sont-elles toujours en cours lorsque vous trouvez le serveur dans l'état ci-dessus? Serait-il possible qu'IE essaie à nouveau les demandes alors qu'elles répondent trop lentement? Si chaque demande HTTP adressée à votre serveur Web peut l'amener à lancer 25 autres demandes HTTP vers un serveur principal, cela peut dégénérer assez rapidement. Pourriez-vous réutiliser les réponses que vous obtenez avec cURL pour plus d'un client?
kasperd

Réponses:

5

Il y a longtemps, j'ai vu des blocages Apache résultant d'un processus Apache effectuant un appel via HTTP vers une autre URL desservie par un processus Apache sur le même serveur. Je me suis parfois retrouvé avec un tas de processus en attente de tels appels sans processus Apache disponible pour les traiter. Dans mon cas, j'avais une couche de traduction devant certaines pages Web, mais appeler une API sur votre propre site est à peu près la même chose.

Les caractéristiques du navigateur effectuant l'appel d'origine pourraient rendre cela plus probable. Par exemple, maintien en vie, comportement d'expiration et ainsi de suite, mais ce n'est pas fondamentalement le navigateur en faute.

Si c'est quelque chose comme ce que j'ai vu, alors vous voulez regarder le comportement de timeout dans votre utilisation de curl. Le code que vous avez inclus suggère que vous y êtes, mais vous devrez peut-être être plus précis dans votre compréhension du stade exact de la demande. Il pourrait être intéressant de le regarder avec tcpdump (ou ngrep, Wireshark ou autre). Il serait également bon de savoir quel appel système est en cours lorsque le processus d'appel se bloque. Autrement dit, regardez-le avec strace -p [PID].

Vous devriez probablement aussi vous demander si vous pouvez supprimer l'appel HTTP de votre utilisation de l'API. Pouvez-vous conserver les choses dans le même processus Apache en appelant directement le code approprié qui gère la demande d'API?

Il est probablement pertinent de dire aux gens comment vous utilisez PHP (par exemple, mod_php, fpm, etc.). Cela peut faire partie de la compréhension du mécanisme de verrouillage du code.

mc0e
la source
Cela pourrait aider à l'interrogation des internes PHP ... versaggi.net/phptest.phtml
ProfVersaggi
À titre d'expérience, j'ai désactivé les appels API de la boucle CURL et j'ai exécuté un tas de tests. Cela a isolé le problème car pendant ces tests, le démon Apache2 est resté sain.
ProfVersaggi