Erreur Apache / Tomcat-mauvaises pages livrées
cette erreur m'a rendu fou. Nous avons un serveur qui exécute Apache et Tomcat, desservant plusieurs sites différents. Normalement le serveur fonctionne bien, mais parfois une erreur se produit où les gens sont servis la mauvaise page - la page que quelqu'un d'autre demandé!
indices:
- les pages livrées sont celles qu'un autre utilisateur A demandées récemment, et sont sinon livré correctement. Il est connu pour deux demandes simultanées à échanger. Pour autant que je sache, aucune des pages mal livrées ne date de plus de quelques minutes.
- n'affecte que les fichiers qui sont servis par Tomcat. Les fichiers statiques comme les images ne sont pas affectés.
- Ça n'arrive pas tout le temps. Quand ça arrive, ça arrive à tout le monde.
- cela semble se produire en période de pointe. Cependant, la demande n'est pas encore très élevée - elle se situe certainement dans les limites de ce qu'Apache peut supporter.
- redémarrant Tomcat fixé, mais seulement pour quelques minutes. Le redémarrage D'Apache l'a réparé, mais seulement quelques minutes.
- le serveur exécute Apache 2 et Tomcat 6, en utilisant une VM Java 6 sur Gentoo. La connexion est avec AJP13, et les directives
JkMount
dans les blocs<VirtualHost>
sont correctes. - il n'y a rien d'utilisation dans les fichiers journaux.
informations complémentaires:
Apache n'a aucune forme de cache activé. Toutes les entrées liées à la mise en cache dans httpd.conf et des importations liées dire, par exemple:
<IfDefine CACHE>
LoadModule cache_module modules/mod_cache.so
</IfDefine>
alors que les options pour Apache n'incluent pas ce drapeau:
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 allumé, que je peux trouver.
la suggestion de toolkit était bonne, mais pas appropriée dans ce cas. Ce qui me porte à croire que l'erreur ne peut pas se trouver dans mon propre code, c'est que ce ne sont pas simplement quelques valeurs qui sont transférées - c'est toute la requête, y compris L'URL, les paramètres, les cookies de session, le tout. Les gens reçoivent des pages en arrière disant "Vous êtes connectés en tant que John", alors qu'ils ne sont clairement pas.
mise à jour:
basé sur les suggestions de plusieurs personnes, je vais ajouter les en-têtes HTTP suivants aux pages servies par Tomcat pour désactiver toutes les formes de cache:
Cache-Control: no-store
Vary: *
espérons que ces en-têtes seront respectés non seulement par Apache, mais aussi par d'autres caches ou procurations qui pourraient être sur le chemin. Malheureusement, je n'ai aucun moyen d'avoir délibérément reproduire cette erreur, donc je vais juste avoir attendre et voir si il tourne à nouveau.
je remarque que les en-têtes suivants sont inclus - pourraient-ils être liés d'une façon quelconque?
Connection: Keep-Alive
Keep-Alive: timeout=5, max=66
mise à jour:
apparemment cela s'est produit à nouveau pendant que je dormais, mais a cessé d'arriver maintenant je suis réveillé pour le voir. Encore une fois, il n'y a rien d'utile dans les registres que je peux voir, donc je n'ai aucun indice de ce qui était réellement qui se passe ou comment faire pour l'empêcher.
y a-t-il des informations supplémentaires que je puisse mettre dans les journaux D'Apache ou de Tomcat pour faciliter le diagnostic?
mise à jour:
depuis que cela s'est reproduit quelques fois, nous avons changé la façon dont Apache se connecte à Tomcat pour voir si cela affecte les choses. Nous utilisions mod_jk
avec une directive comme celle-ci:
JkMount /portal ajp13
nous sommes passés maintenant à l'utilisation de mod_proxy_ajp
, comme ceci:
ProxyPass /portal ajp://localhost:8009/portal
on verra si ça change quelque chose. Cette erreur a toujours été d'une imprévisibilité agaçante, de sorte que nous ne pouvons jamais dire avec certitude si elle a fonctionné ou non.
mise à jour:
nous venons d'obtenir l'erreur brièvement sur un site qui a été laissé en utilisant mod_jk
, alors qu'un site soeur sur le même serveur en utilisant mod_proxy_ajp
n'a pas montré l'erreur. Cela ne prouve rien, mais il fournit la preuve que swithing à mod_proxy_ajp
peut avoir aidé.
mise à jour:
nous venons de recevoir l'erreur à nouveau la nuit dernière sur un site en utilisant mod_proxy_ajp
, donc clairement qui n'a pas résolu - mod_jk
n'était pas la source du problème. Je vais essayer la suggestion anonyme de désactiver persistant connexions:
KeepAlive Off
si ça échoue aussi, je serai assez désespéré pour commencer à enquêter sur les poissons de mer.
mise à jour:
Bon sang! Le problème vient de revenir. Je ne l'avais pas vu depuis un moment, donc je commençais à penser qu'on avait enfin réglé ça. Je déteste les heisenbugs.
11 réponses
pourrait-il S'agir de la sécurité de vos servlets?
vos servlets stocker toutes les informations dans les membres de l'instance.
par exemple, quelque chose d'aussi simple que ce qui suit peut causer des problèmes liés au fil:
public class MyServlet ... {
private String 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
}
}
}
parce que le serlvet est accessible par plusieurs threads, il n'y a aucune garantie que le membre de l'instance d'action ne sera pas bloqué par une requête de quelqu'un d'autre, et finira par renvoyer la mauvaise page.
la solution simple à ce problème est d'utiliser des variables locales en tête des membres de l'instance:
public class MyServlet ... {
public void doGet(...) {
String 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
}
}
}
Note: Ceci s'étend aussi aux Pages JavaServer, si vous les expédiiez pour 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 avez besoin d'une entrée dans l'en-tête HTTP Vary
pour l'en-tête cookie, ou un cache/proxy pourrait servir la version mise en cache d'une page destinée à un utilisateur à un autre utilisateur).
le problème pourrait ne pas être avec la mise en cache sur votre serveur web, mais sur une autre couche de mise en cache (soit sur un proxy inverse en face de votre web serveur, ou sur un proxy près de l'utilisateur). Si les clients se comportent comme un NAT, ils pourraient aussi être derrière un proxy transparent (et, pour rendre les choses encore plus difficiles à déboguer, le proxy transparent pourrait être configuré pour ne pas être visible dans les en-têtes).
8 mises à jour de la question plus tard, un autre numéro à utiliser pour tester/reproduire, bien qu'il puisse être difficile (ou coûteux) pour les sites publics.
vous pouvez activer https sur les sites. Cela éliminerait au moins toutes les autres caches proxies en cours de route. Ce serait dommage de voir qu'il y a des équilibres oubliés ou des caches de compagnie sur le chemin qui interfèrent avec votre trafic.
pour les sites publics cela impliquerait des certificats de confiance sur le touches, donc de l'argent. Pour tester les clés auto-signées pourrait suffire. Aussi, Vérifiez qu'il n'y a pas de mandataire transparent impliqué qui décrypte et réencrypte le trafic. (ils sont facilement détectables, car ils ne peuvent pas utiliser le même certificat/clé que le serveur d'origine)
bien que vous ayez mentionné que mod_cache n'était pas activé dans votre setup, pour les autres qui ont rencontré le même problème avec mod_cache activé (même sur les contenus statiques), la solution est de s'assurer que la directive suivante est activée sur L'en-tête HTTP Set-Cookie:
CacheIgnoreHeaders Set-Cookie
la raison étant que mod_cache cache l'en-tête Set-Cookie qui peut être servie à d'autres utilisateurs. L'ID de session de l'utilisateur qui a rempli le cache pour la dernière fois serait alors divulgué à un autre utilisateur.
j'ai eu ce problème et ça m'a vraiment rendu dingue. 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 ça a très bien fonctionné pour moi.
essayez ceci:
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
Regardez ce site, il décrit un problème avec mod_jk. Je suis venu à travers votre affectation tout en regardant une question très similaire. Fondamentalement, la solution consiste à mettre à jour vers une nouvelle version de mod_jk. Je n'ai pas encore eu la chance d'implémenter le changement dans notre serveur, mais je vais essayer ça demain et voir si ça aide.
Je ne suis pas un expert, mais est-ce que ça pourrait être un problème bizarre traduction de L'adresse réseau ?
nous avons fait passer Apache du proxying avec AJP au proxying avec HTTP. Jusqu'à présent, il semble avoir résolu le problème, ou au moins considérablement réduit - le problème n'a pas été signalé dans le mois, et l'application de l'utilisation a augmenté depuis lors.
Le changement est dans Apache httpd.conf. Ayant commencé par mod_jk
:
JkMount /portal ajp13
nous sommes passés à mod_proxy_ajp
:
ProxyPass /portal ajp://localhost:8009/portal
puis enfin à 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 /
des deux côtés du mandataire ou il commence à pleurer:
ProxyPass / http://localhost:8080/
C'est peut-être pas un problème de mise en cache à tous. Essayez d'augmenter le paramètre MaxClients dans apache2.conf. Si elle est trop faible (150 par défaut?), Apache commence à mettre les requêtes en file d'attente. Quand il décide de servir la requête mise en file d'attente via mod_proxy il sort une mauvaise page (ou peut-être il est juste stressé en faisant toute la file d'attente).
Êtes-vous sûr que c'est la page que quelqu'un d'autre demande ou une page sans paramètres?, vous pourriez avoir des erreurs bizarres si votre connectionTimeout est trop court sur le serveur.xml sur le serveur tomcat derrière apache, augmentez - le à un plus grand nombre:
configuration par défaut:
<Connector port="8080" protocol="HTTP/1.1"
connectionTimeout="20000"
redirectPort="8443" />
modifié:
<Connector port="8080" protocol="HTTP/1.1"
connectionTimeout="2000000"
redirectPort="8443" />