JVM падает с нагрузкой на RHEL 5.2

У меня есть (в настоящее время последний) jdk 1.6.0.18 сбой при запуске веб-приложения на (в настоящее время последний) tomcat 6.0.24 неожиданно после от 4 до 24 часов 4 часа до 8 дней стресс-теста (30 нитей, попадающих в приложение на 6 млн. просмотров страниц/день). Это относится к RHEL 5.2 (Tikanga).

Отчет о сбое находится в http://pastebin.com/f639a6cf1, а согласованные части аварии:

  • забрасывается SIGSEGV
  • на libjvm.so
  • пространство eden всегда заполнено (100%)

JVM работает со следующими параметрами:

CATALINA_OPTS="-server -Xms512m -Xmx1024m -Djava.awt.headless=true"

Я также проверил память на аппаратные проблемы, используя http://memtest.org/ в течение 48 часов (14 проходов всей памяти) без каких-либо ошибок.

Я включил -verbose:gc -XX:+PrintGCDetails -XX:+PrintGCTimeStamps для проверки любых трендов GC или исчерпания пространства, но там нет ничего подозрительного. GC и полный GC происходят с предсказуемыми интервалами, почти всегда освобождая тот же объем памяти.

Мое приложение напрямую не использует какой-либо собственный код.

Любые идеи о том, куда я должен смотреть дальше?

Изменить - подробнее:

1) В этом JDK нет клиента vm:

[[email protected] ~]$ java -version -server
java version "1.6.0_18"
Java(TM) SE Runtime Environment (build 1.6.0_18-b07)
Java HotSpot(TM) 64-Bit Server VM (build 16.0-b13, mixed mode)

[[email protected] ~]$ java -version -client
java version "1.6.0_18"
Java(TM) SE Runtime Environment (build 1.6.0_18-b07)
Java HotSpot(TM) 64-Bit Server VM (build 16.0-b13, mixed mode)

2) Изменение O/S невозможно.

3) Я не хочу изменять переменные стресс-теста JMeter, так как это может скрыть проблему. Поскольку у меня есть прецедент (текущий сценарий стресс-теста), который разбивает JVM, я хотел бы исправить ошибку и не изменять тест.

4) Я сделал статический анализ в своем приложении, но ничего серьезного не появилось.

5) Память не растет с течением времени. Использование памяти уравновешивается очень быстро (после запуска) при очень устойчивом тренде, который не выглядит подозрительным.

6)/var/log/messages не содержит никакой полезной информации до или во время сбоя

Дополнительная информация: забыл упомянуть о том, что был apache (2.2.14), выходящий из tomcat с использованием mod_jk 1.2.28. Прямо сейчас я запускаю тест без apache, только если авария JVM связана с собственным кодом mod_jk, который подключается к JVM (разъем tomcat).

После этого (если JVM снова сработает), я попытаюсь удалить некоторые компоненты из моего приложения (кеширование, lucene, кварц), а позже попытается использовать причал. Поскольку авария в настоящее время происходит в любое время от 4 часов до 8 дней, это может занять много времени, чтобы узнать, что происходит.

Ответ 1

У вас есть выход для компилятора? т.е. PrintCompilation (и если вы чувствуете себя особенно смело, LogCompilation).

Я отлаживал такой случай в части, наблюдая за тем, что делает компилятор, и, в конце концов (это заняло много времени до момента лампочки), осознав, что мой сбой был вызван компиляцией определенного метода в драйвер oracle jdbc.

В основном, что я делаю,

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

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

некоторые ссылки

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

  • последовательный (молодой) коллекционер (IIRC его можно комбинировать с параллельным старым)
  • ParNew + CMS
  • G1

если он не повторяется с другими GC algos, тогда вы это знаете до этого (и у вас нет никаких исправлений, но для изменения GC algo и/или перехода через старые JVM до тех пор, пока вы не найдете версию этого алгоритма удар).

Ответ 2

Несколько идей:

  • Используйте другую версию JDK, Tomcat и/или ОС
  • Слегка изменить параметры теста, например. 25 потоков при просмотре 7,2 страниц в день
  • Использование памяти монитора или профиля.
  • Отладка или настройка сборщика мусора
  • Запуск статического и динамического анализа

Ответ 3

Вы пробовали разные аппаратные средства? Похоже, вы используете 64-битную архитектуру. По моему собственному опыту 32-бит быстрее и стабильнее. Возможно, там есть и аппаратная проблема. Сроки "между 4-24 часами" довольно распространены как проблема программного обеспечения. Хотя вы говорите, что в системном журнале нет ошибок, поэтому я мог бы уйти. По-прежнему считайте, что стоит попробовать.

Ответ 4

С годами растет ваша память? Если это так, я предлагаю изменить пределы памяти ниже, чтобы узнать, не работает ли система чаще, когда память исчерпана.

Можете ли вы быстрее воспроизвести проблему, если:

  • Вы уменьшаете доступную память к JVM?
  • Вы уменьшаете доступные системные ресурсы (т.е. сбрасываете системную память, поэтому JVM не хватает)
  • Вы меняете свои варианты использования на более простую модель?

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

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

Удачи, Jacob

Ответ 6

Если бы я был вами, я бы сделал следующее:

  • попробуйте несколько более старых версий Tomcat/JVM. Кажется, вы управляете новейшим и самым большим. Я бы спустил две версии или около того, возможно, попробовать JRockit JVM.
  • сделайте дамп потока (kill -3 java_pid), пока приложение работает, чтобы увидеть полные стеки. Ваш текущий дамп показывает, что много потоков заблокировано - но неясно, где они блокируются (I/O? Некоторая внутренняя блокировка голодания? Что-нибудь еще?). Я даже мог бы запланировать kill -3, который будет запускаться каждую минуту, чтобы сравнить любой случайный дамп потока с тем, который был непосредственно перед сбоем.
  • Я видел случаи, когда Linux JDK просто умирает, тогда как Windows JDK умеет изящно ловить исключение (тогда был StackOverflowException), поэтому, если вы можете изменить код, добавьте "catch Throwable" где-нибудь в верхнем классе. На всякий случай.
  • Воспроизведение с настройками настройки GC. Включите/выключите параллельный GC, настройте NewSize/MaxNewSize. И да, это не научная, а отчаянная потребность в рабочем решении. Подробнее здесь: http://java.sun.com/javase/technologies/hotspot/gc/gc_tuning_6.html

Сообщите нам, как это было разобрано!

Ответ 7

Можно ли перейти на 32-разрядную JVM? Я считаю, что это самое зрелое предложение от Солнца.