Я и моя команда изо всех сил пытались сохранить стабильность кластерного приложения 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,4 ГБ. Раньше у нас были утечки, но мы их исправили, теперь приложение использует около 400 МБ, редко больше. Максимальный размер кучи установлен на 1200 МБ, поэтому мы его не достигаем. Когда у нас были утечки, JVM просто взорвалась, и экземпляр перезапустился. Сейчас этого не происходит, он просто перестает обрабатывать входящий запрос.
Мы думали, что это связано с веткой после этого сообщения в блоге: http://www.talkingtree.com/blog/index.cfm/2005/3/11/NewNativeThread
Вызываемое исключение Java относится к типу OutOfMemory, но на самом деле это не говорит о том, что у нас закончилось пространство кучи, а просто о том, что оно не может создавать новые потоки. Тип исключения немного вводит в заблуждение.
В основном в блоге говорится, что 500 as activeHandlerThreads может быть слишком большим, но мои показатели, похоже, показывают, что мы не приближаемся к тому, что нас сбивает.
Что ж, давайте посмотрим на некоторые более серьезные проблемы, прежде чем переходить к деталям конфигурации JRun.
Если вы получаете исключения java.lang.OutOfMemoryError в журнале ошибок JRun, что ж, вам не хватает памяти. Не голосуйте за это, пожалуйста ;-). Вы не сказали, используете ли вы 32- или 64-битную Windows, но вы сказали, что у вас 8 ГБ ОЗУ, так что это окажет некоторое влияние на ответ. Независимо от того, используете ли вы 32- или 64-разрядную JVM (и какая версия), это также повлияет на ситуацию. Итак, это несколько ответов, которые помогут нам разобраться в этом.
Тем не менее, вашему приложению не хватает памяти. Недостаточно памяти по одной или нескольким из следующих причин:
Еще о чем следует помнить: в 32-битной Windows 32-битная JVM может выделить только примерно 1,4 ГБ памяти. Я не припоминаю, чтобы 32-битная JVM в 64-битной Windows имела ограничение меньше теоретических 4 ГБ для любого 32-битного процесса.
ОБНОВЛЕНО
Я прочитал сообщение в блоге, на которое есть ссылка через TalkingTree, а также другое сообщение, связанное с этим сообщением. Я не сталкивался с этим конкретным случаем, но у меня было следующее наблюдение: журнал метрик JRUN может не записывать «максимальные значения», которые вы указали в период пикового использования потоков. Я думаю, что он регистрирует показатели с фиксированным повторяющимся интервалом. Это хорошо для демонстрации плавных, средних характеристик производительности вашего приложения, но может не фиксировать состояние JRUN непосредственно перед тем, как возникнет состояние ошибки.
Не зная о внутренней работе управления потоками JRUN, я все же говорю, что это действительно нехватка памяти. Возможно, это не из-за нехватки памяти, потому что вашему приложению нужно было выделить память в куче JVM, и ни одна из них не была доступна, но она не в памяти, потому что JRUN попытался создать другой поток для обработки входящего запроса, а память в куче, необходимая для поддержки другого потока, не была t доступны - другими словами, потоки не бесплатны - они также требуют кучи памяти.
Ваши варианты выглядят следующим образом:
Независимо от того, какой вариант вы выберете, я думаю, что действующее исправление здесь будет экспериментальным по своей природе. Вам нужно будет внести изменения и посмотреть, как они повлияют на приложение. У вас ведь есть среда для нагрузочного тестирования?
Попробуйте и уменьшить максимальный размер кучи. Каждому потоку требуются собственные ресурсы (наряду с собственными материалами Java). Размер используемой виртуальной AS составляет 2 ГБ; 1,2 ГБ зарезервировано для кучи. Часть оставшихся 800 МБ используется для кода (текстовые сегменты java и все необходимые библиотеки DLL), затем существуют собственные выделения, требуемые JRE и ее зависимостями ... и потоки: для каждого потока по умолчанию зарезервировано 1 МБ AS ( хотя фактически фиксируется только страница), 100 потоков = 100 МБ (только для стеков). Теперь добавьте немного дополнительного пространства между различными частями, немного фрагментации ... OOM ;-)