JRun поток конфигурации
Я и моя команда изо всех сил пытались сохранить кластерное приложение ColdFusion стабильным в течение большей части последних 6 месяцев с небольшим результатом. Мы обращаемся к SF в надежде на то, что кто-нибудь найдет экспертов по JRun или свежие идеи, потому что мы не можем понять это.
Настройка:
Два экземпляра ColdFusion 7.0.2, сгруппированные с JRun 4 (с последним обновлением) на IIS 6 под Windows Server 2003. Два четырехъядерных процессора, 8 ГБ ОЗУ.
Проблема:
Время от времени, обычно один раз в неделю, один из экземпляров полностью прекращает обработку запроса. Там нет никакой активности, и мы должны перезапустить ее.
Что мы знаем:
Каждый раз, когда это происходит, журнал ошибок JRun всегда полон java.lang.OutOfMemoryError: невозможно создать новый собственный поток.
После прочтения документации по JRun из Macromedia/Adobe и множества запутанных постов в блоге мы более или менее сузили ее до неправильных / неоптимизированных настроек пула потоков JRun в экземпляре jrun.xml.
Соответствующая часть нашего jrun.xml:
<service class="jrun.servlet.jrpp.JRunProxyService" name="ProxyService">
<attribute name="activeHandlerThreads">500</attribute>
<attribute name="backlog">500</attribute>
<attribute name="deactivated">false</attribute>
<attribute name="interface">*</attribute>
<attribute name="maxHandlerThreads">1000</attribute>
<attribute name="minHandlerThreads">1</attribute>
<attribute name="port">51003</attribute>
<attribute name="threadWaitTimeout">300</attribute>
<attribute name="timeout">300</attribute>
{snip}
</service>
На прошлой неделе я включил ведение журнала метрик JRun для сбора данных, связанных с потоками. Это сводка данных после записи в журнал в течение недели.
Средние значения:
{jrpp.listenTh} 1
{jrpp.idleTh} 9
{jrpp.delayTh} 0
{jrpp.busyTh} 0
{jrpp.totalTh} 10
{jrpp.delayRq} 0
{jrpp.droppedRq} 0
{jrpp.handledRq} 4
{jrpp.handledMs} 6036
{jrpp.delayMs} 0
{freeMemory} 48667
{totalMemory} 403598
{sessions} 737
{sessionsInMem} 737
Максимальные значения:
{jrpp.listenTh} 10
{jrpp.idleTh} 94
{jrpp.delayTh} 1
{jrpp.busyTh} 39
{jrpp.totalTh} 100
{jrpp.delayRq} 0
{jrpp.droppedRq} 0
{jrpp.handledRq} 87
{jrpp.handledMs} 508845
{jrpp.delayMs} 0
{freeMemory} 169313
{totalMemory} 578432
{sessions} 2297
{sessionsInMem} 2297
Есть идеи о том, что мы можем попробовать сейчас?
Ура!
РЕДАКТИРОВАТЬ #1 -> Вещи, которые я забыл упомянуть: Windows Server 2003 Enterprise с JVM 1.4.2 (для JRun)
Максимальный размер кучи составляет около 1,4 ГБ, да. Раньше у нас были утечки, но мы их исправили, теперь приложение использует около 400 МБ, редко больше. Максимальный размер кучи установлен в 1200 МБ, поэтому мы не достигаем его. Когда у нас были утечки, JVM просто взорвалась, и экземпляр перезапустился сам. Сейчас этого не происходит, просто прекращается обработка входящего запроса.
Мы думали, что это связано с темой, следующей за этим сообщением в блоге: http://www.talkingtree.com/blog/index.cfm/2005/3/11/NewNativeThread
Выдаваемое исключение Java относится к типу OutOfMemory, но на самом деле оно не говорит о том, что у нас закончилось пространство кучи, просто оно не может создавать новые потоки. Тип исключения немного вводит в заблуждение.
В основном блог говорит, что 500 как activeHandlerThreads может быть слишком высоким, но мои метрики, кажется, показывают, что мы не достигли того, что сбивает нас с толку.
2 ответа
Что ж, давайте рассмотрим некоторые большие проблемы с изображением, прежде чем углубляться в детали конфигурации JRun.
Если вы получаете исключения java.lang.OutOfMemoryError в журнале ошибок JRun, значит, у вас недостаточно памяти. Никаких возражений за это, пожалуйста;-). Вы не сказали, используете ли вы 32- или 64-разрядную версию Windows, но вы сказали, что у вас 8 ГБ ОЗУ, так что это повлияет на ответ. Независимо от того, используете ли вы 32- или 64-разрядную JVM (и какую версию), это также повлияет на ситуацию. Так что это несколько ответов, которые помогут нам разобраться в этом.
В любом случае, вашему приложению не хватает памяти. Недостаточно памяти по одной или нескольким из следующих причин:
- У вашего приложения течет память. На некоторые объекты, которые использует ваше приложение, постоянно ссылаются, и поэтому они никогда не могут быть использованы для сборки мусора; или еще хуже - какой-то объект, созданный новым при каждом запросе, постоянно ссылается на другой объект и, следовательно, никогда не может быть использован для сборки мусора. Корректная обработка сеанса J2EE может быть особенно сложной в этом отношении.
- Объем необходимой памяти для обработки каждого одновременного запроса (на настроенном уровне одновременного запроса) превышает объем памяти, доступный в куче JVM. Например, у вас есть размер кучи 1 ГБ, и каждый запрос может использовать до 10 МБ. Ваш сервер приложений настроен на 150 одновременных запросов. (Упрощенные числа, я знаю). В этом случае вам определенно не хватит памяти, если вы столкнулись с 100 или более одновременными запросами под нагрузкой (если каждый запрос использовал максимальный объем памяти, необходимый для выполнения запроса).
Другие вещи, которые следует иметь в виду: в 32-битной Windows 32-битная JVM может выделить только приблизительно 1,4 ГБ памяти. Я не припоминаю, если 32-битная JVM в 64-битной Windows имеет ограничение меньше, чем теоретический максимум 4 ГБ для любого 32-битного процесса.
ОБНОВЛЕНО
Я прочитал пост в блоге, связанный через TalkingTree, и другой пост, связанный с этим постом. Я не сталкивался с этим конкретным случаем, но у меня было следующее наблюдение: регистрация метрик JRUN может не записывать "максимальные значения", которые вы указали в период пикового использования потока. Я думаю, что это регистрирует метрики с фиксированным, повторяющимся интервалом. Это хорошо для того, чтобы показать вам плавные средние характеристики производительности вашего приложения, но оно может не отражать состояние JRUN непосредственно перед началом возникновения ошибки.
Не зная о внутренней работе управления потоками JRUN, я все еще говорю, что на самом деле не хватает памяти. Возможно, это не из-за нехватки памяти, потому что вашему приложению нужно было выделить память в куче JVM, и ни одна из них не была доступна, но в ней недостаточно памяти, потому что JRUN попытался создать другой поток для обработки входящего запроса, а память кучи, необходимая для поддержки другого потока, не была ' t доступны - другими словами, потоки не являются свободными - им также требуется куча памяти.
Ваши варианты выглядят следующим образом:
- Уменьшите объем памяти, используемый вашим приложением в каждом запросе, или
- Экспериментально уменьшите значение параметров настройки потока в конфигурации JRUN, чтобы большее количество потоков было поставлено в очередь на обработку вместо того, чтобы становиться работоспособным одновременно, или
- Уменьшите количество одновременных запросов в администраторе ColdFusion (страница "Настройка запросов", поле "Максимальное количество одновременных запросов шаблона")
Независимо от того, какой вариант вы используете, я думаю, что правильное решение будет экспериментальным. Вам нужно будет внести изменения и посмотреть, как это повлияет на приложение. У вас есть среда нагрузочного тестирования, верно?
Попробуйте уменьшить максимальный размер кучи. Каждый поток требует собственных ресурсов (наряду с собственным материалом Java). Используемая виртуальная AS - 2 ГБ; 1,2 Гб зарезервировано для кучи. Часть оставшихся 800 МБ используется для кода (текстовые сегменты java и все необходимые библиотеки DLL), затем для JRE и его зависимостей требуются собственные выделения... и потоки: для каждого потока по умолчанию зарезервировано 1 МБ AS (хотя на самом деле фиксируется только страница), 100 потоков = 100 МБ (только для стеков). Теперь добавьте немного дополнительного пространства между различными частями, немного фрагментации... OOM;-)