Каков наилучший способ избежать перегрузки параллельной файловой системы при выполнении смущающе параллельных заданий?

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

Однако с большим количеством рабочих мест, не все из них завершены. Это не является проблемой в очереди - все задания запущены.

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

Тогда возникает проблема, заключающаяся в том, что либо программа не может выполнить запись в файловую систему и каким-либо образом аварийно завершает работу, либо просто сидит в ожидании записи, а система очереди пакетов убивает задание после того, как оно слишком долго ожидает выполнения. (Из того, что я понял по этой проблеме, большинство заданий, которые не могут быть выполнены, если не все, не оставляют основные файлы)

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

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

У меня были некоторые мысли по этому поводу:

  1. Каждое задание сначала записывается на локальный (рабочий) диск узла. Затем мы можем запустить другое задание, которое время от времени проверяет, какие задания завершены, и перемещает файлы с локальных дисков в параллельную файловую систему.
  2. Используйте обертку MPI для программы в системе master/slave, где master управляет очередью заданий и передает их каждому ведомому устройству; и подчиненная оболочка запускает приложения и ловит исключение (могу ли я сделать это надежно в течение тайм-аута файловой системы в C++ или, возможно, Java?) и отправляет сообщение мастеру для повторного запуска задания

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

Если это полезно: мы запускаем Solaris в нашей системе HPC с системой пакетной очереди SGE (Sun GridEngine). Файловая система - NFS4, а серверы хранения также работают под управлением Solaris. Узлы HPC и серверы хранения обмениваются данными по оптоволоконным каналам.

3 ответа

Решение

Большинство параллельных файловых систем, особенно в суперкомпьютерных центрах, нацелены на приложения HPC, а не на устройства типа последовательной фермы. В результате они тщательно оптимизированы для пропускной способности, а не для операций ввода-вывода в секунду (операций ввода-вывода в секунду), то есть они нацелены на большие (более 1000 процессов) задания, пишущие горстку гигантских файлов, а не миллионы маленьких задания, выводящие октиллионы маленьких файлов. Пользователи могут легко запускать что-то, что отлично работает (ish) на своем настольном компьютере и наивно масштабировать до сотен одновременных заданий, чтобы лишить системы IOP нагрузку, повесив свои задания и, как правило, другие в тех же системах.

Главное, что вы можете здесь сделать - это агрегат, агрегат, агрегат. Было бы лучше, если бы вы сообщили нам, где вы работаете, чтобы мы могли получить больше информации о системе. Но некоторые проверенные стратегии:

  1. Если вы выводите много файлов на одно задание, измените свою стратегию вывода так, чтобы каждое задание выписывало один файл, содержащий все остальные. Если у вас есть локальный ramdisk, вы можете сделать что-то такое же простое, как записать их на ramdisk, а затем перенести их в реальную файловую систему.
  2. Пишите в двоичном формате, а не в ascii. Большие данные никогда не отправляются в ASCII. Двоичные форматы пишутся примерно в 10 раз быстрее, несколько меньше, и вы можете записывать большие куски за раз, а не несколько чисел в цикле, что приводит к:
  3. Большие записи лучше, чем маленькие. Каждая операция ввода-вывода - это то, что должна делать файловая система. Делайте несколько больших писем, а не зацикливайтесь на крошечных записях.
  4. Точно так же не пишите в форматах, которые требуют, чтобы вы искали разные части файла в разное время. Ищет медленно и бесполезно.
  5. Если вы выполняете много заданий на узле, вы можете использовать тот же прием виртуального диска, что и выше (или локальный диск), чтобы преобразовать выходные данные всех заданий и сразу отправить их все в параллельную файловую систему.

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

Аналогично, наличие меньшего количества больших файлов, чем большого количества маленьких, ускорит все: от списков каталогов до резервных копий в вашей файловой системе; все хорошо.

Трудно решить, если вы не знаете, что именно является причиной сбоя. Если вы считаете, что это ошибка, связанная с производительностью файловой системы, вы можете попробовать распределенную файловую систему: http://hadoop.apache.org/common/docs/r0.20.0/hdfs_user_guide.html

Если вы хотите внедрить систему Master/Slave, возможно, Hadoop может помочь.

Но прежде всего я бы попытался выяснить, что является причиной аварии...

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

Одно простое решение, требующее изменения программы, - согласиться с тем, что одновременно может писать не более N ваших многочисленных заданий. Вам понадобится общий семафор, который могут видеть все вакансии; большинство ОС предоставляют вам средства для одного, часто в качестве именованного ресурса (!). Инициализируйте семафор до N, прежде чем запускать какую-либо работу. Пусть каждое задание на запись получит ресурсную единицу из семафора, когда задание собирается написать, и освободит эту единицу ресурса, когда оно будет выполнено. Объем кода для достижения этой цели должен состоять из нескольких строк, вставленных один раз в ваше высокопараллельное приложение. Затем вы настраиваете N, пока у вас больше не возникнет проблема. N==1 наверняка решит это, и вы, вероятно, можете сделать намного лучше, чем это.

Другие вопросы по тегам