Назад | Перейти на главную страницу

Конфигурация пула потоков 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 -> Things I forgot to mention: Windows Server 2003 Enterprise w/ JVM 1.4.2 (for JRun)

Максимальный размер кучи составляет около 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 (и какая версия), это также повлияет на ситуацию. Итак, это несколько ответов, которые помогут нам разобраться в этом.

Тем не менее, вашему приложению не хватает памяти. Недостаточно памяти по одной или нескольким из следующих причин:

  1. У вашего приложения утечка памяти. На некоторый объект, который использует ваше приложение, постоянно ссылаются, и поэтому он никогда не подлежит сборке мусора; или, что еще хуже, на какой-то объект, созданный новым при каждом запросе, ссылается другой объект на неограниченный срок, и поэтому он никогда не имеет права на сборку мусора. Правильная обработка сеанса J2EE может быть особенно сложной в этом отношении.
  2. Объем памяти, необходимой для обработки каждого параллельного запроса (на настроенном уровне одновременных запросов), превышает объем памяти, доступный в куче JVM. Например, у вас есть размер кучи 1 ГБ, и каждый запрос может использовать до 10 МБ. Ваш сервер приложений настроен на обработку 150 одновременных запросов. (Я знаю, что это упрощенные числа). В этом случае вам определенно не хватит памяти, если вы испытаете 100 или более одновременных запросов под нагрузкой (если каждый запрос использует максимальный объем памяти, необходимый для выполнения запроса).

Еще о чем следует помнить: в 32-битной Windows 32-битная JVM может выделить только примерно 1,4 ГБ памяти. Я не припоминаю, чтобы 32-битная JVM в 64-битной Windows имела ограничение меньше теоретических 4 ГБ для любого 32-битного процесса.

ОБНОВЛЕНО

Я прочитал сообщение в блоге, на которое есть ссылка через TalkingTree, а также другое сообщение, связанное с этим сообщением. Я не сталкивался с этим конкретным случаем, но у меня было следующее наблюдение: журнал метрик JRUN может не записывать «максимальные значения», которые вы указали в период пикового использования потоков. Я думаю, что он регистрирует показатели с фиксированным повторяющимся интервалом. Это хорошо для демонстрации плавных, средних характеристик производительности вашего приложения, но может не фиксировать состояние JRUN непосредственно перед тем, как возникнет состояние ошибки.

Не зная о внутренней работе управления потоками JRUN, я все же говорю, что это действительно нехватка памяти. Возможно, это не из-за нехватки памяти, потому что вашему приложению нужно было выделить память в куче JVM, и ни одна из них не была доступна, но она не в памяти, потому что JRUN попытался создать другой поток для обработки входящего запроса, а память в куче, необходимая для поддержки другого потока, не была t доступны - другими словами, потоки не бесплатны - они также требуют кучи памяти.

Ваши варианты выглядят следующим образом:

  1. Уменьшите объем памяти, который ваше приложение использует при каждом запросе, или-
  2. Экспериментально уменьшите значение параметров настройки потоков в конфигурации JRUN, чтобы большее количество потоков помещалось в очередь для обработки вместо того, чтобы одновременно запускаться, или
  3. Уменьшите количество одновременных запросов в администраторе ColdFusion (страница Request Tuning, поле «Максимальное количество одновременных запросов Template»)

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

Попробуйте и уменьшить максимальный размер кучи. Каждому потоку требуются собственные ресурсы (наряду с собственными материалами Java). Размер используемой виртуальной AS составляет 2 ГБ; 1,2 ГБ зарезервировано для кучи. Часть оставшихся 800 МБ используется для кода (текстовые сегменты java и все необходимые библиотеки DLL), затем существуют собственные выделения, требуемые JRE и ее зависимостями ... и потоки: для каждого потока по умолчанию зарезервировано 1 МБ AS ( хотя фактически фиксируется только страница), 100 потоков = 100 МБ (только для стеков). Теперь добавьте немного дополнительного пространства между различными частями, немного фрагментации ... OOM ;-)