Ошибка Apache / Tomcat - доставляются неправильные страницы - PullRequest
9 голосов
/ 29 октября 2008

Эта ошибка сводила меня с ума. У нас есть сервер под управлением Apache и Tomcat, обслуживающий несколько разных сайтов. Обычно сервер работает нормально, но иногда возникает ошибка, когда людям предоставляется неправильная страница - страница, которую кто-то другой запросил!

Улика:

  • Доставляются те страницы, которые недавно запрошен другим пользователем, и в противном случае они доставляются правильно. Известно, что два одновременных запроса меняются местами. Насколько я могу судить, ни одна из неправильно доставленных страниц не старше нескольких минут.
  • Влияет только на файлы, которые обслуживает Tomcat. Статические файлы, такие как изображения, не затрагиваются.
  • Это не происходит постоянно. Когда это случается, это случается для всех.
  • Кажется, это происходит во времена пикового спроса. Тем не менее, спрос еще не очень высок - он, безусловно, находится в пределах того, с чем может справиться Apache.
  • Перезапуск Tomcat исправил это, но только на несколько минут. Перезапуск Apache исправил это, но только на несколько минут.
  • Сервер работает под управлением Apache 2 и Tomcat 6, используя виртуальную машину Java 6 в Gentoo. Соединение с AJP13, и директивы JkMount в пределах блоков <VirtualHost> являются правильными.
  • Нет ничего полезного ни в одном из файлов журнала.

Дополнительная информация:

В Apache не включена ни одна форма кэширования. Все записи, связанные с кэшированием в httpd.conf и связанных импорте, говорят, например:

<IfDefine CACHE>
  LoadModule cache_module modules/mod_cache.so
</IfDefine>

Хотя параметры для Apache не включают этот флаг:

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

Tomcat также не имеет включенных опций кэширования, которые я могу найти.

предложение инструментария было хорошим, но в данном случае неуместным. Что заставляет меня верить, что ошибка не может быть в моем собственном коде, так это то, что передаются не просто несколько значений, а весь запрос, включая URL-адрес, параметры, сеансовые куки-файлы и все такое. Люди возвращаются к страницам с надписью «Вы вошли как Джон», когда они явно нет.


Обновление:

Исходя из предложений нескольких людей, я собираюсь добавить следующие заголовки HTTP на страницы, обслуживаемые Tomcat, чтобы отключить все формы кэширования:

Cache-Control: no-store
Vary: *

Надеюсь, эти заголовки будут уважаться не только Apache, но и любыми другими кешами или прокси, которые могут быть на пути. К сожалению, у меня нет возможности преднамеренно воспроизвести эту ошибку, поэтому мне просто придется подождать и посмотреть, не появится ли она снова.

Я заметил, что включены следующие заголовки - могут ли они быть связаны каким-либо образом?

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

Обновление:

Очевидно, это случилось снова, когда я спал, но теперь это прекратилось, и я не сплю, чтобы увидеть это. Опять же, нет ничего полезного в журналах, которые я вижу, поэтому у меня нет никаких подсказок о том, что на самом деле происходило или как это предотвратить.

Есть ли какая-либо дополнительная информация, которую я могу поместить в журналы Apache или Tomcat, чтобы упростить диагностику?


Обновление:

С тех пор, как это повторилось пару раз, мы изменили способ подключения Apache к Tomcat, чтобы увидеть, влияет ли он на вещи. Мы использовали mod_jk с такой директивой:

JkMount /portal ajp13

Мы перешли на использование mod_proxy_ajp, вот так:

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

Посмотрим, будет ли это иметь значение. Эта ошибка всегда была неожиданно непредсказуемой, поэтому мы никогда не сможем однозначно сказать, сработала она или нет.


Обновление:

Мы только что получили короткую ошибку на сайте, который был оставлен с использованием mod_jk, в то время как дочерний сайт на том же сервере с использованием mod_proxy_ajp не показывал ошибку. Это ничего не доказывает, но предоставляет доказательства того, что подмена на mod_proxy_ajp, возможно, помогла.


Обновление:

Мы только что получили ошибку вчера вечером на сайте, используя mod_proxy_ajp, настолько ясно, что это не решило - mod_jk не было источником проблемы. Я собираюсь попробовать анонимное предложение отключить постоянные соединения:

KeepAlive Off

Если и это не поможет, я буду достаточно отчаянным, чтобы начать исследование GlassFish.


Обновление:

Проклятье! Проблема только что вернулась. Я не видел это некоторое время, поэтому я начинал думать, что мы наконец разобрали это. Я ненавижу гейзенбагов.

Ответы [ 11 ]

5 голосов
/ 29 октября 2008

Может ли это быть потокобезопасность ваших сервлетов?

Ваши сервлеты хранят какую-либо информацию в членах экземпляра.

Например, что-то простое, как показано ниже, может вызвать проблемы, связанные с потоками:

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
         }
     }
}

Поскольку доступ к сервлету осуществляется несколькими потоками, нет никакой гарантии, что член экземпляра действия не будет захвачен чужим запросом и в конечном итоге отправит неверную страницу обратно.

Простым решением этой проблемы является использование локальных переменных, а не членов экземпляра:

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
         }
     }
}

Примечание: это распространяется и на страницы JavaServer Pages, если вы отправляете им для своих просмотров?

3 голосов
/ 30 октября 2008

Проверьте, разрешают ли ваши заголовки кэширование без правильного заголовка HTTP Vary (например, если вы используете cookie-файлы сеанса и разрешаете кэширование, вам нужна запись в заголовке HTTP Vary для заголовка cookie или кэш-память). / proxy может обслуживать кэшированную версию страницы, предназначенную для одного пользователя другому).

Возможно, проблема не в кэшировании на вашем веб-сервере, а на другом уровне кэширования (либо на обратном прокси-сервере перед вашим веб-сервером, либо на прокси-сервере рядом с пользователями). Если клиенты работают с NAT, они могут также находиться за прозрачным прокси-сервером (и, чтобы усложнить отладку, прозрачный прокси-сервер может быть настроен так, чтобы он не отображался в заголовках).

2 голосов
/ 24 января 2011

Несмотря на то, что вы упомянули, что mod_cache не был включен в вашей установке, для тех, кто мог столкнуться с той же проблемой при включенном mod_cache (даже для статического содержимого), решение состоит в том, чтобы убедиться, что следующая директива включена в Set-Cookie Заголовок HTTP:

CacheIgnoreHeaders Set-Cookie

Причина в том, что mod_cache кеширует заголовок Set-Cookie, который может быть передан другим пользователям. В результате будет получен идентификатор сеанса от пользователя, который последний раз заполнил кэш, другому.

2 голосов
/ 19 апреля 2009

8 обновлений вопроса позже - еще одна проблема для тестирования / воспроизведения, хотя это может быть сложно (или дорого) для публичных сайтов.

Вы можете включить https на сайтах. Это по крайней мере уничтожило бы любые другие кеши прокси на этом пути. Было бы плохо видеть, что есть некоторые забытые балансировщики нагрузки или кэши компании, которые мешают вашему трафику.

Для общедоступных сайтов это будет означать доверенные сертификаты на ключи, поэтому будут задействованы некоторые деньги. Для тестирования может быть достаточно самозаверяющих ключей. Кроме того, убедитесь, что не задействован прозрачный прокси, который расшифровывает и повторно шифрует трафик. (их легко обнаружить, поскольку они не могут использовать тот же сертификат / ключ, что и на исходном сервере)

1 голос
/ 17 июня 2009

Загляните на этот сайт, он описывает проблему с mod_jk. Я наткнулся на ваши сообщения, глядя на очень похожую проблему. По сути, исправление заключается в обновлении до более новой версии mod_jk. У меня еще не было возможности применить изменения на нашем сервере, но я собираюсь попробовать это завтра и посмотреть, поможет ли это.

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

1 голос
/ 19 апреля 2009

Попробуйте это:

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
1 голос
/ 26 января 2009

У меня была эта проблема, и это действительно сводило меня с ума. Я не знаю почему, но я решил отключить Keep Alive на http.conf

от

KeepAlive On

до

KeepAlive Off

Мое приложение не использует функцию keepalive, поэтому оно работало очень хорошо для меня.

0 голосов
/ 07 июля 2012

Вы уверены, что это страница, запрошенная кем-то другим, или страница без параметров ?, Вы можете получить странные ошибки, если ваш connectionTimeout слишком короткий в server.xml на сервере tomcat за apache, увеличьте его до большего числа:

конфигурация по умолчанию:

  <Connector port="8080" protocol="HTTP/1.1"
               connectionTimeout="20000"
               redirectPort="8443" />

изменен:

  <Connector port="8080" protocol="HTTP/1.1"
               connectionTimeout="2000000"
               redirectPort="8443" />
0 голосов
/ 26 марта 2010

Это может быть не проблема кеширования вообще. Попробуйте увеличить параметр MaxClients в apache2.conf. Если оно слишком мало (150 по умолчанию?), Apache начинает ставить запросы в очередь. Когда он решает обработать запрос в очереди через mod_proxy, он вытаскивает не ту страницу (или, может быть, он просто подчеркивает всю очередь).

0 голосов
/ 16 ноября 2009

Мы переключили Apache с прокси с помощью AJP на прокси с HTTP. Пока что он, похоже, решил проблему или, по крайней мере, значительно ее уменьшил - о проблеме не сообщалось месяцами, и с тех пор использование приложения возросло.

Изменение в файле Apache httpd.conf. Начав с mod_jk:

JkMount /portal ajp13

Мы перешли на mod_proxy_ajp:

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

Тогда, наконец, прямо mod_proxy:

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

Вам нужно убедиться, что Tomcat настроен на обслуживание HTTP через порт 8080. И помните, что если вы обслуживаете /, вам нужно включить / с обеих сторон прокси-сервера, иначе он начнет плакать. :

ProxyPass / http://localhost:8080/
...