Замедление создания процесса под Java? - PullRequest
4 голосов
/ 31 декабря 2010

У меня есть одна большая куча (до 240 ГБ, хотя в диапазоне 20-40 ГБ для большей части этого этапа выполнения) JVM [1] работает под Linux [2] на сервере с 24 ядрами. У нас есть десятки тысяч объектов, которые должны быть обработаны внешним исполняемым файлом, а затем загрузить данные, созданные этими исполняемыми файлами, обратно в JVM. Каждый исполняемый файл производит около половины мегабайта данных (на диске), которые при чтении сразу после завершения процесса, конечно, больше.

Нашей первой реализацией было иметь каждый исполняемый дескриптор только одного объекта. Это привело к появлению в два раза больше исполняемых файлов, чем у нас было объектов (так как мы называли сценарий оболочки, который называл исполняемый файл). Наша загрузка ЦП будет начинаться с высокой, но не обязательно 100%, и постепенно ухудшаться. Когда мы начали измерять, чтобы увидеть, что происходит, мы заметили, что время создания процесса [3] постоянно замедляется. Начиная с доли секунды, в конечном итоге это займет около минуты или более. Фактическая обработка, выполняемая исполняемым файлом, обычно занимает менее 10 секунд.

Затем мы изменили исполняемый файл, чтобы получить список объектов для обработки в попытке уменьшить количество созданных процессов. При размере пакета в несколько сотен (~ 1% от нашего текущего размера выборки) время создания процесса начинается примерно с 2 секунд и увеличивается примерно до 5-6 секунд.

По сути, почему создание этих процессов занимает так много времени, а выполнение продолжается?

[1] Oracle JDK 1.6.0_22
[2] Red Hat Enterprise Linux Advanced Platform 5.3, ядро ​​Linux 2.6.18-194.26.1.el5 # 1 SMP
[3] Создание объекта ProcessBuilder, перенаправление потока ошибок и запуск его.

Ответы [ 4 ]

3 голосов
/ 01 января 2011

Я предполагаю, что вы МОЖЕТЕ столкнуться с проблемами с fork / exec, если Java использует системные вызовы fork / exec для порождения подпроцессов.

Обычно fork / exec довольно эффективен, потому что fork ()делает очень мало - все страницы копируются при записи.Это перестает быть так верно с очень большими процессами (то есть с гигабайтами отображаемых страниц), потому что сами таблицы страниц создаются относительно долго - и, конечно, уничтожаются, как вы сразу же вызываете exec.

Asвы используете огромное количество кучи, это может повлиять на вас.Чем больше страниц вы отобразили, тем хуже может стать, что может быть причиной постепенного замедления.

Подумайте либо:

  • Использование posix_spawn, если это НЕ реализованоfork / exec в libc
  • Использование одного подпроцесса, который отвечает за создание / получение других;порождайте это один раз и используйте IPC (каналы и т. д.), чтобы сказать ему, что делать.

NB: Это все предположение;вам, вероятно, следует провести несколько экспериментов, чтобы понять, так ли это.

1 голос
/ 01 января 2011

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

Создание 240-гигабайтного изображения не является бесплатным, оно потребляет большое количество виртуальных ресурсов, хотя бы на секунду.ОС не знает, как долго новый процесс будет в курсе, поэтому она должна подготовиться так, как будто весь процесс будет долгоживущим, поэтому она устанавливает виртуальный клон всех 240 ГБ, прежде чем уничтожить его с помощью вызова exec.

Если бы вместо этого у вас был долгоживущий процесс, к которому вы могли бы завершить объекты через некоторый механизм очереди (а их много для Java, C и т. Д.), Это избавило бы вас от некоторого давления процесса разветвления.

Я не знаю, как вы переносите данные из JVM во внешнюю программу.Но если ваша внешняя программа может работать с stdin / stdout, то (если вы используете unix), вы можете использовать inetd.Здесь вы делаете простую запись в файле конфигурации inetd для вашего процесса и назначаете ему порт.Затем вы открываете сокет, засыпаете в него данные и затем читаете обратно из сокета.Inetd обрабатывает детали сети для вас, и ваша программа работает просто с помощью stdin и stdout.Имейте в виду, что у вас есть открытый сокет в сети, который может быть безопасным при вашем развертывании.Но настроить даже устаревший код для запуска через сетевой сервис довольно просто.

Вы можете использовать простую оболочку, подобную этой:

#!/bin/sh
infile=/tmp/$$.in
outfile=/tmp/$$.out

cat > $infile
/usr/local/bin/process -input $infile -output $outfile
cat $outfile
rm $infile $outfile

Это не самый высокопроизводительный сервер на планетерассчитан на миллионы транзакций, но это намного быстрее, чем разветвление 240 ГБ снова и снова.

1 голос
/ 31 декабря 2010

Скорее всего у вас заканчивается ресурс.Ваши диски загружаются, когда вы создаете эти процессы.Вы гарантируете, что у вас меньше процессов, чем у вас ядер?(Чтобы свести к минимуму переключение контекста) Среднее значение нагрузки ниже 24?

Если потребление ЦП снижается, вы, вероятно, столкнетесь с конфликтами ввода-вывода (диска / сети), т. Е. Процессы не могут получать / записывать данные достаточно быстро, чтобы сохранитьони заняты.Если у вас 24 ядра, сколько у вас дисков?

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

0 голосов
/ 31 декабря 2010

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

Таким образом, «решением» может быть создание «потребительских» процессов, инициализировать только некоторые из них;как Питер предложил один на процессор или более.Затем используйте некоторую форму IPC для «передачи» этих объектов процессам потребителя.

Ваши процессы «потребителя» должны управлять созданием подпроцесса;исполняемый файл обработки, к которому, как я полагаю, у вас нет доступа, и таким образом вы не загромождаете ОС слишком большим количеством исполняемых файлов, и «задание» будет «в конце концов» завершено.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...