#c #filesystems #fortran #parallel-processing #embarrassingly-parallel
#c #файловые системы #fortran #параллельная обработка #недопустимо параллельный
Вопрос:
У нас есть вызывающе параллельная проблема — мы запускаем большое количество экземпляров одной программы с разными наборами данных для каждого; мы делаем это просто путем многократной отправки приложения в пакетную очередь с разными параметрами каждый раз.
Однако при большом количестве заданий не все из них завершаются. Похоже, что это не проблема в очереди — все задания запущены.
Проблема, по-видимому, заключается в том, что при большом количестве запущенных экземпляров приложения множество заданий завершается примерно в одно и то же время и, таким образом, все пытаются записать свои данные в параллельную файловую систему практически в одно и то же время.
Тогда проблема, по-видимому, заключается в том, что либо программа не может выполнить запись в файловую систему и каким-то образом выходит из строя, либо просто сидит там в ожидании записи, а система пакетной очереди завершает задание после того, как оно простояло в ожидании слишком долго. (Из того, что я собрал по проблеме, большинство заданий, которые не завершаются, если не все, не оставляют основных файлов)
Каков наилучший способ запланировать запись на диск, чтобы избежать этой проблемы? Я упоминаю, что наша программа возмутительно параллельна, чтобы подчеркнуть тот факт, что каждый процесс не знает о других — они не могут общаться друг с другом, чтобы каким-то образом запланировать свои записи.
Хотя у меня есть исходный код программы, мы хотели бы решить проблему без необходимости изменять это, если это возможно, поскольку мы не поддерживаем и не разрабатываем его (плюс большинство комментариев на итальянском).
У меня было несколько мыслей по этому поводу:
- Каждое задание сначала записывается на локальный (scratch) диск узла. Затем мы можем запустить другое задание, которое время от времени проверяет, какие задания завершены, и перемещает файлы с локальных дисков в параллельную файловую систему.
- Используйте MPI-оболочку вокруг программы в системе master / slave, где master управляет очередью заданий и отправляет их каждому подчиненному устройству; а подчиненная оболочка запускает приложения и перехватывает исключение (могу ли я сделать это надежно для тайм-аута файловой системы в C или, возможно, Java?) и отправляет сообщение обратно ведущему устройству для повторного запуска задания
Тем временем мне нужно обратиться к своим руководителям за дополнительной информацией о самой ошибке — я никогда не сталкивался с этим лично, но мне не приходилось использовать программу для очень большого количества наборов данных (пока).
На случай, если это полезно: мы запускаем Solaris в нашей системе HPC с системой пакетных очередей SGE (Sun GridEngine). Файловая система — NFS4, а серверы хранения также работают под управлением Solaris. HPC-узлы и серверы хранения обмениваются данными по каналам fibre channel.
Комментарии:
1. Я думаю, что требуется дополнительная информация об ошибке. Если приложение выходит из строя, то это явно нечто большее, чем просто узкое место ввода-вывода.
2. Звучит знакомо. Я регулярно перегружаю наш NFS-сервер слишком большим количеством заданий.
3. Я могу только согласиться — я тот человек, которому сказали устранить проблему! Насколько я понимаю, большинство (если не все) заданий, которые не завершаются, не оставляют основных файлов. Я обновлю завтра дополнительную информацию, когда получу ее. Возможно, мне следовало попросить о хороших стратегиях, позволяющих избежать узкого места.
4. вам нужно каким-то образом ограничить запись в качестве начала профилирования и диагностики того, что вызывает «бутылочное горлышко». В каждой параллельной системе всегда есть некоторый конечный общий ресурс, одним из которых всегда является ввод-вывод.
5. Как насчет использования возможностей системы пакетных очередей? Возможно, запускать задания в шахматном порядке группами? Или, если проблема просто в том, что для какого-то ресурса выполняется слишком много заданий, установите ограничение на количество одновременных заданий. Если вы не хотите случайно пробовать решения, вам нужно выяснить причину сбоев.
Ответ №1:
Большинство параллельных файловых систем, особенно в суперкомпьютерных центрах, предназначены для приложений HPC, а не для устройств типа последовательной фермы. В результате они тщательно оптимизированы для пропускной способности, а не для IOPs (операций ввода-вывода в секунду) — то есть они нацелены на большие (более 1000 процессов) задания, записывающие несколько гигантских файлов, а не на миллиарды маленьких заданий, выводящих октиллионы крошечных файлов. Пользователям слишком просто запускать что-то, что работает нормально (ish) на их рабочем столе, и наивно масштабировать до сотен одновременных заданий, чтобы истощить систему IOPs, зависая на своих заданиях и, как правило, на других в тех же системах.
Главное, что вы можете здесь делать, — это агрегировать, агрегировать, агрегировать. Было бы лучше, если бы вы могли сообщить нам, где вы работаете, чтобы мы могли получить больше информации о системе. Но есть несколько проверенных стратегий:
- Если вы выводите много файлов за задание, измените стратегию вывода таким образом, чтобы каждое задание записывало один файл, содержащий все остальные. Если у вас есть локальный ramdisk, вы можете сделать что-то столь же простое, как записать их на ramdisk, а затем перенести в реальную файловую систему.
- Пишите в двоичном формате, а не в ascii. Большие данные никогда не передаются в формате ascii. Двоичные форматы в ~ 10 раз быстрее для записи, несколько меньше, и вы можете записывать большие куски за раз, а не несколько чисел в цикле, что приводит к:
- Большие операции записи лучше, чем маленькие. Каждая операция ввода-вывода — это то, что должна выполнять файловая система. Делайте несколько больших операций записи, а не зацикливайтесь на крошечных операциях записи.
- Аналогично, не записывайте в форматах, которые требуют от вас поиска для записи в разные части файла в разное время. Поиск выполняется медленно и бесполезно.
- Если вы выполняете много заданий на узле, вы можете использовать тот же трюк с ramdisk, что и выше (или локальный диск), чтобы настроить все выходные данные заданий и отправить их все сразу в параллельную файловую систему.
Приведенные выше предложения улучшат производительность ввода-вывода вашего кода везде, а не только в параллельных файловых системах. Ввод-вывод везде медленный, и чем больше вы можете сделать в памяти и чем меньше фактических операций ввода-вывода вы выполняете, тем быстрее это произойдет. Некоторые системы могут быть более чувствительными, чем другие, поэтому вы можете не заметить этого на своем ноутбуке, но это поможет.
Аналогично, наличие меньшего количества больших файлов вместо большого количества маленьких ускорит все, от списков каталогов до резервных копий в вашей файловой системе; это хорошо для всех.
Комментарии:
1. Пожалуйста, не могли бы вы пояснить, что вы имели в виду, когда сказали — «скажите нам, где я выполняю»? Как вы догадались, система оптимизирована для работы с HPC (некоторые задания, которые мы запускаем здесь, используют 1000 ядер более полугода).
2. Каждое задание считывает 3 файла (~ 5 кб, 100 кб, 15 кб) и выдает пару файлов, которые обычно довольно малы (~ 1 мб и 5 кб). Поиск не выполняется, он просто добавляет информацию к выходным файлам. Само по себе это поведение изменить невозможно. Проблемой может стать двоичный файл — данные вполне могут быть перенесены в систему с другим порядковым номером. Хорошим вариантом может быть блокирование. Как я уже сказал, я не могу реально изменить поведение самого приложения, поэтому это должно быть в сочетании с записью данных ASCII на локальный диск, затем вызовом job, их обработкой и передачей.
3. Да, еще одна проблема заключается в том, что другие задания от других пользователей выполняются в той же системе, и иногда они работают не так хорошо.
4. Вы можете просмотреть наши вычислительные ресурсы здесь, если это то, что вы имели в виду: icc.dur.ac.uk/index.php?content=Computing/Computing — хотя по какой-то причине в нашей последней и самой лучшей системе этого не хватает.
5. Я понимаю, что вы имеете в виду, говоря о невозможности изменить поведение — похоже, они не распространяют исходный код? Бах. Если вы можете использовать целый узел (предположительно, если вы запрашиваете количество ядер узла, вы предпочтительно получите запланированный целый узел), вы можете использовать gnu parallel (например, support.scinet.utoronto.ca/wiki/index.php /… ) выполнить N (или, возможно, 2-3 N) задач в одном задании; затем это одно задание может передавать все входные данные на локальный диск, все выходные данные записывать на локальный диск, а затем обрабатывать этот набор результатов и отправлять их в / data за один раз.
Ответ №2:
Трудно решить, если вы не знаете, что именно вызывает сбой. Если вы считаете, что это ошибка, связанная с производительностью файловой системы, вы можете попробовать распределенную файловую систему: http://hadoop.apache.org/common/docs/r0.20.0/hdfs_user_guide.html
Если вы хотите внедрить систему Master / Slave, возможно, ответом может быть Hadoop.
Но прежде всего я бы попытался выяснить, что вызывает сбой…
Ответ №3:
Операционные системы не всегда ведут себя хорошо, когда у них заканчиваются ресурсы; иногда они просто прерывают процесс, запрашивающий первую единицу ресурса, которую ОС не может предоставить. Многие операционные системы имеют ограничения на ресурс дескриптора файла (Windows, я думаю, имеет ресурс дескриптора в несколько тысяч дескрипторов, с которым вы можете столкнуться в обстоятельствах, подобных вашим), и неспособность найти свободный дескриптор обычно означает, что ОС плохо влияет на запрашивающий процесс.
Одно простое решение, требующее изменения программы, — согласиться с тем, что одновременно может записываться не более N из множества ваших заданий. Вам понадобится общий семафор, который могут видеть все задания; большинство операционных систем предоставят вам средства для одного, часто в виде именованного ресурса (!). Инициализируйте семафор значением N перед запуском любого задания. Пусть каждое задание на запись получает единицу ресурса из семафора, когда задание готовится к записи, и освобождает эту единицу ресурса по завершении. Объем кода для выполнения этого должен составлять несколько строк, вставленных один раз в ваше высокопараллельное приложение. Затем вы настраиваете N до тех пор, пока проблема не исчезнет. N == 1 наверняка решит проблему, и вы, вероятно, можете сделать намного лучше.