JVM падает из-за стресса на RHEL 5.2
Я получил (на данный момент самый последний) сбой jdk 1.6.0.18 при запуске веб-приложения на (на данный момент новейшем) tomcat 6.0.24 неожиданно после 4-24 часов от 4 часов до 8 дней стресс-тестирования (30 потоков в приложении 6 миллионов просмотров страниц в день). Это на RHEL 5.2 (Тиканга).
Отчет о сбое находится по адресу http://pastebin.com/f639a6cf1 и его частями являются следующие:
- SIGSEGV бросается
- на libjvm.so
- eden space всегда заполнен (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:
[foo@localhost ~]$ 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)
[foo@localhost ~]$ 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 не содержит никакой полезной информации до или во время сбоя
Больше информации: Забыл упомянуть, что был tomcat apache (2.2.14), использующий mod_jk 1.2.28. Прямо сейчас я запускаю тест без Apache на случай, если сбой JVM связан с собственным кодом mod_jk, который подключается к JVM (соединитель tomcat).
После этого (если JVM снова выйдет из строя) я попытаюсь удалить некоторые компоненты из моего приложения (кеширование, lucene, кварц), а позже попробую использовать jetty. Поскольку авария происходит в любое время от 4 часов до 8 дней, может потребоваться много времени, чтобы выяснить, что происходит.
7 ответов
У вас есть выход компилятора? т.е. PrintCompilation
(и если вы чувствуете себя особенно смелым, LogCompilation).
Я отлаживал такой случай в этой части, наблюдая за тем, что делает компилятор, и, в конце концов (это заняло много времени до момента появления лампочки), понимая, что мой сбой был вызван компиляцией определенного метода в драйвере oracle jdbc,
По сути, я бы сделал это;
- включить PrintCompilation
- так как это не дает меток времени, напишите скрипт, который просматривает этот лог-файл (например, спит каждую секунду и печатает новые строки) и сообщает, когда методы были скомпилированы (или нет)
- повторить тест
- проверьте вывод компилятора, чтобы увидеть, соответствует ли сбой компиляции какого-либо метода
- повторите еще несколько раз, чтобы увидеть, если есть шаблон
Если есть различимый шаблон, используйте.hotspot_compiler (или.hotspotrc), чтобы он прекратил компилировать вызывающий (-ые) метод (-ы), повторите тест и посмотрите, не сработает ли он. Очевидно, в вашем случае этот процесс теоретически может занять месяцы, я боюсь.
некоторые ссылки
- для работы с выходными данными компиляции журнала -> http://wikis.sun.com/display/HotSpotInternals/LogCompilation+tool
- для получения информации о.hotspot_compiler -> http://futuretask.blogspot.com/2005/01/java-tip-7-use-hotspotcompiler-file-to.html или http://blogs.oracle.com/javawithjiva/entry/hotspotrc_and_hotspot_compiler
- действительно простой, быстрый и грязный скрипт для просмотра выходных данных компилятора -> http://pastebin.com/Haqjdue9
- обратите внимание, что это было написано для соляриса, который всегда имеет странные опции для утилит по сравнению с эквивалентами GNU, так что, без сомнения, более простые способы сделать это на других платформах или с использованием других языков
Другая вещь, которую я бы сделал, - это систематическое изменение используемого вами алгоритма gc и проверка времени сбоя по отношению к активности gc (например, соотносится ли он с молодым или старым gc, как насчет TLAB?). Ваш дамп указывает, что вы используете параллельный мусор, поэтому попробуйте
- серийный (молодой) коллектор (IIRC может сочетаться с параллельным старым)
- ParNew + CMS
- G1
если он не повторяется с другими GC-алгоритмами, то вы знаете, что дело в этом (и у вас нет никакого решения, кроме как изменить GC-алгоритм и / или вернуться к старым JVM, пока вы не найдете версию этого алгоритма, которая не дует).
Несколько идей:
- Используйте другую версию JDK, Tomcat и / или OS
- Немного измените параметры теста, например, 25 потоков при 7,2 млн просмотров страниц в день
- Использование памяти монитора или профиля
- Отладка или настройка сборщика мусора
- Запустить статический и динамический анализ
Вы пробовали другое оборудование? Похоже, вы используете 64-битную архитектуру. По моему опыту 32-бит быстрее и стабильнее. Возможно, где-то тоже есть проблемы с оборудованием. Время "между 4-24 часами" довольно распространено, чтобы быть просто проблемой программного обеспечения. Хотя вы говорите, что системный журнал не содержит ошибок, так что я могу быть далеко. Тем не менее думаю, стоит попробовать.
Если бы я был тобой, я бы сделал следующее:
- попробуйте немного более старые версии Tomcat/JVM. Вы, кажется, работаете самым новым и лучшим. Я бы остановился на двух версиях или около того, возможно, попробую JRockit JVM.
- делать дамп потока (kill -3 java_pid), пока приложение работает, чтобы увидеть полные стеки. Ваш текущий дамп показывает, что многие потоки заблокированы, но неясно, где они блокируются (ввод / вывод - некоторое внутреннее блокирование блокировки - что-нибудь еще?). Возможно, я бы даже запланировал запуск kill -3 каждую минуту, чтобы сравнить любой случайный дамп потока с тем, который был до сбоя.
- Я видел случаи, когда Linux JDK просто умирает, тогда как Windows JDK может изящно перехватить исключение (тогда это было StackruException), поэтому, если вы можете изменить код, добавьте "catch Throwable" где-то в верхнем классе. Так, на всякий случай.
- Играйте с настройками GC. Включить / выключить одновременный сборщик мусора, настроить NewSize/MaxNewSize. И да, это не научно - скорее отчаянная потребность в рабочем решении. Более подробная информация здесь: http://java.sun.com/javase/technologies/hotspot/gc/gc_tuning_6.html
Дайте нам знать, как это было решено!
Можно ли вместо этого перейти на 32-разрядную JVM? Я считаю, что это самое зрелое предложение от Sun.
Попробуйте переключить свой контейнер сервлетов с Tomcat на Jetty http://jetty.codehaus.org/jetty/.
Ваша память растет со временем? Если это так, я предлагаю изменить пределы памяти ниже, чтобы увидеть, происходит ли сбой системы чаще, когда память исчерпана.
Можете ли вы воспроизвести проблему быстрее, если:
- Вы уменьшаете объем памяти, доступной для JVM?
- Вы уменьшаете доступные системные ресурсы (т.е. истощаете системную память, чтобы JVM не хватало)
- Вы меняете свои варианты использования на более простую модель?
Одна из основных стратегий, которые я использовал, - определить, какой вариант использования вызывает проблему. Это может быть общая проблема, или это может быть конкретный случай использования. Попробуйте зарегистрировать начало и остановку вариантов использования, чтобы узнать, сможете ли вы определить, какие варианты использования чаще всего вызывают проблему. Если вы разделите ваши варианты использования пополам, посмотрите, какая из них даст сбой быстрее всего. Это может быть более частой причиной сбоя. Естественно, проведение нескольких испытаний каждой конфигурации повысит точность ваших измерений.
Мне также известно, что я либо меняю сервер, чтобы выполнять небольшую работу, либо зацикливаюсь на работе, которую выполняет сервер. Одна заставляет код вашего приложения работать намного сложнее, другая заставляет веб-сервер и сервер приложений работать намного сложнее.
Удачи тебе, Джейкоб