Erreur Apache / Tomcat – fausses pages livrées

Cette erreur m’a rendu fou. Nous avons un serveur exécutant Apache et Tomcat, desservant plusieurs sites différents. Normalement, le serveur fonctionne correctement, mais parfois une erreur se produit lorsque les gens reçoivent la mauvaise page – la page que quelqu’un d’autre a demandée!

Des indices:

  • Les pages en cours de livraison sont celles demandées récemment par un autre utilisateur et livrées correctement. On sait que deux demandes simultanées doivent être échangées. Autant que je sache, aucune des pages livrées de manière incorrecte n’a plus de quelques minutes.
  • Cela n’affecte que les fichiers servis par Tomcat. Les fichiers statiques comme les images ne sont pas affectés.
  • Cela n’arrive pas tout le temps. Quand cela arrive, ça arrive pour tout le monde.
  • Cela semble se produire en période de forte demande. Cependant, la demande n’est pas encore très élevée – elle est certainement dans les limites de ce qu’Apache peut faire.
  • Le redémarrage de Tomcat a résolu le problème, mais seulement pendant quelques minutes. Le redémarrage d’Apache a résolu le problème, mais seulement pendant quelques minutes.
  • Le serveur exécute Apache 2 et Tomcat 6, en utilisant une machine virtuelle Java 6 sur Gentoo. La connexion est avec AJP13, et les directives JkMount dans les blocs sont correctes.
  • Il n’y a rien d’utilisation dans aucun des fichiers journaux.

Informations complémentaires:

Apache ne dispose d’aucune forme de mise en cache activée. Toutes les entrées liées à la mise en cache dans httpd.conf et les importations associées indiquent, par exemple:

  LoadModule cache_module modules/mod_cache.so  

Bien que les options pour Apache n’incluent pas cet indicateur:

 APACHE2_OPTS="-D DEFAULT_VHOST -D INFO -D LANGUAGE -D SSL -D SSL_DEFAULT_VHOST -D PHP5 -D JK" 

Tomcat n’a pas non plus d’options de mise en cache activées, que je peux trouver.

la suggestion de la boîte à outils était bonne, mais pas appropriée dans ce cas. Ce qui m’amène à croire que l’erreur ne peut pas être dans mon propre code, c’est que ce ne sont pas simplement quelques valeurs qui sont transférées – c’est la demande entière, y compris l’URL, les parameters, les cookies de session, le tout. Les gens obtiennent des pages disant “Vous êtes connecté en tant que John”, alors que ce n’est pas le cas.


Mettre à jour:

Sur la base des suggestions de plusieurs personnes, je vais append les en-têtes HTTP suivants aux pages servies par Tomcat pour désactiver toutes les formes de mise en cache:

 Cache-Control: no-store Vary: * 

Espérons que ces en-têtes seront respectés non seulement par Apache, mais aussi par tous les autres caches ou proxys qui pourraient faire obstacle. Malheureusement, je n’ai aucun moyen de reproduire délibérément cette erreur, alors je vais juste devoir attendre pour voir si cela se reproduit.

Je remarque que les en-têtes suivants sont inclus – pourraient-ils être liés de quelque façon?

 Connection: Keep-Alive Keep-Alive: timeout=5, max=66 

Mettre à jour:

Apparemment, cela s’est produit encore pendant que je dormais, mais a cessé de se produire maintenant je suis réveillé pour le voir. Là encore, je ne vois rien d’utile dans les journaux, donc je n’ai aucune idée de ce qui se passait ou de la manière de l’empêcher.

Existe-t-il des informations supplémentaires que je peux mettre dans les journaux d’Apache ou de Tomcat pour faciliter le diagnostic?


Mettre à jour:

Comme cela s’est à nouveau produit quelques fois, nous avons changé la façon dont Apache se connecte à Tomcat pour voir si cela affecte les choses. Nous mod_jk avec une directive comme celle-ci:

 JkMount /portal ajp13 

Nous sums maintenant passés à l’utilisation de mod_proxy_ajp , comme ceci:

 ProxyPass /portal ajp://localhost:8009/portal 

Nous verrons si cela fait une différence. Cette erreur étant toujours imprévisible, nous ne pourrons jamais dire si elle fonctionne ou non.


Mettre à jour:

Nous venons de recevoir l’erreur brièvement sur un site laissé avec mod_jk , alors qu’un site mod_proxy_ajp du même serveur utilisant mod_proxy_ajp n’a pas montré l’erreur. Cela ne prouve rien, mais cela prouve que swithing à mod_proxy_ajp peut avoir aidé.


Mettre à jour:

Nous venons de recevoir l’erreur de nouveau la nuit dernière sur un site utilisant mod_proxy_ajp , donc clairement cela ne l’a pas résolu – mod_jk n’était pas la source du problème. Je vais essayer la suggestion anonyme de désactiver les connexions persistantes:

 KeepAlive Off 

Si cela échoue aussi, je vais être assez désespéré pour commencer à enquêter sur GlassFish.


Mettre à jour:

Bon sang! Le problème est juste revenu. Je ne l’avais pas vu depuis longtemps, alors je commençais à penser que nous avions fini par le régler. Je déteste heisenbugs.

    Serait-ce la sécurité des fils de vos servlets?

    Est-ce que vos servlets stockent des informations dans les membres d’instance?

    Par exemple, quelque chose d’aussi simple que le suivant peut provoquer des problèmes liés aux threads:

     public class MyServlet ... { private Ssortingng action; public void doGet(...) { action = request.getParameter("action"); processAction(response); } public void processAction(...) { if (action.equals("foo")) { // send foo page } else if (action.equals("bar")) { // send bar page } } } 

    Comme le serlvet est accessible par plusieurs threads, il n’y a aucune garantie que le membre de l’instance d’action ne soit pas entravé par une autre requête et finisse par renvoyer la mauvaise page.

    La solution simple à ce problème consiste à utiliser des variables locales insead des membres d’instance:

     public class MyServlet ... { public void doGet(...) { Ssortingng action = request.getParameter("action"); processAction(action, response); } public void processAction(...) { if (action.equals("foo")) { // send foo page } else if (action.equals("bar")) { // send bar page } } } 

    Remarque: cela s’étend également aux pages JavaServer, si vous les envoyiez à vos vues?

    Vérifiez si vos en-têtes autorisent la mise en cache sans l’en-tête HTTP Vary correct (si vous utilisez des cookies de session, par exemple, et autorisez la mise en cache, vous devez entrer une en-tête HTTP ou un cache / proxy). d’une page destinée à un utilisateur à un autre utilisateur).

    Le problème n’est peut-être pas lié à la mise en cache sur votre serveur Web, mais à une autre couche de mise en cache (sur un proxy inverse en face de votre serveur Web ou sur un proxy auprès des utilisateurs). Si les clients utilisent un NAT, ils peuvent également se trouver derrière un proxy transparent (et, pour rendre les choses encore plus difficiles à déboguer, le proxy transparent peut être configuré pour ne pas être visible dans les en-têtes).

    8 mises à jour de la question plus tard, un autre problème à utiliser pour tester / reproduire, même si cela peut être difficile (ou coûteux) pour les sites publics.

    Vous pouvez activer https sur les sites. Cela effacerait au moins tous les caches de mandataires en cours de route. Il serait mauvais de voir qu’il y a des déséquilibres de charge ou des caches de compagnie oubliés qui interfèrent avec votre trafic.

    Pour les sites publics, cela impliquerait des certificates de confiance sur les clés, de sorte que de l’argent sera impliqué. Pour tester les clés auto-signées peut suffire. Vérifiez également qu’il n’ya pas de proxy transparent impliqué qui déchiffre et recrée le trafic. (ils sont facilement détectables, car ils ne peuvent pas utiliser le même certificate / clé que le serveur d’origine)

    Bien que vous ayez mentionné que mod_cache n’était pas activé dans votre configuration, pour les autres utilisateurs ayant rencontré le même problème avec mod_cache activé (même sur des contenus statiques), la solution est de vérifier que la directive suivante est activée sur l’en-tête HTTP Set-Cookie:

     CacheIgnoreHeaders Set-Cookie 

    La raison d’être de mod_cache mettra en cache l’en-tête Set-Cookie qui pourrait être servi à d’autres utilisateurs. Cela entraînerait une fuite de l’ID de session de l’utilisateur qui a rempli le cache pour la dernière fois.

    J’ai eu ce problème et ça m’a vraiment rendu fou. Je ne sais pas pourquoi, mais je l’ai résolu en désactivant le Keep Alive sur le http.conf

    de

    KeepAlive On

    à

    KeepAlive Off

    Mon application n’utilise pas la fonctionnalité keepalive, donc cela a très bien fonctionné pour moi.

    Essaye ça:

     response.setHeader("Cache-Control", "no-cache"); //HTTP 1.1 response.setHeader("Pragma", "no-cache"); //HTTP 1.0 response.setDateHeader("Expires", 0); //prevents caching at the proxy server 

    Jetez un oeil sur ce site, il décrit un problème avec mod_jk. Je suis tombé sur votre message en regardant un problème très similaire. Fondamentalement, le correctif consiste à mettre à niveau vers une version plus récente de mod_jk. Je n’ai pas encore eu la chance de mettre en œuvre le changement sur notre serveur, mais je vais essayer cela demain et voir si cela peut aider.

    http://securitytracker.com/alerts/2009/Apr/1022001.html

    Je ne suis pas un expert, mais pourrait-il s’agir d’un problème étrange de traduction d’adresses réseau ?

    Nous avons basculé Apache du proxy avec AJP vers le proxy avec HTTP. Jusqu’à présent, il semble avoir résolu le problème ou, du moins, considérablement réduit le problème – le problème n’a pas été signalé depuis des mois et l’utilisation de l’application a augmenté depuis.

    Le changement est dans httpd.conf d’Apache. Ayant commencé avec mod_jk :

     JkMount /portal ajp13 

    Nous sums passés à mod_proxy_ajp :

     ProxyPass /portal ajp://localhost:8009/portal 

    Puis finalement à droite mod_proxy :

     ProxyPass /portal http://localhost:8080/portal 

    Vous devez vous assurer que Tomcat est configuré pour servir HTTP sur le port 8080. Et rappelez-vous que si vous servez / , vous devez inclure / deux côtés du proxy ou il commence à pleurer:

     ProxyPass / http://localhost:8080/ 

    Ce n’est peut-être pas un problème de mise en cache du tout. Essayez d’augmenter le paramètre MaxClients dans apache2.conf. Si elle est trop faible (150 par défaut?), Apache commence à mettre en queue les requêtes. Quand il décide de servir une requête en queue via mod_proxy, il sort une mauvaise page (ou peut-être est-il juste stressé de faire toutes les files d’attente).

    Etes-vous sûr que la page demandée par quelqu’un d’autre ou une page sans paramètre?, Vous pourriez obtenir des erreurs étranges si votre connectionTimeout est trop court sur server.xml sur le serveur tomcat derrière apache, augmentez le nombre:

    configuration par défaut:

       

    modifié: