Intereting Posts
Откройте специальное приложение в рабочей области * new * с i3wm Пожалуйста, объясните параметр -f в pgrep CentOS 7. SSH В доступе отказано. Почему нет пароля? Почему $ является символом по умолчанию для оболочки пользователя и # символом по умолчанию для корневой оболочки? Преобразование соединения EDUROAM WPA2-Enterprise в NetworkManager к системному соединению Выбрав дистрибутив для старого ПК, какую проблему совместимости нужно искать? Эмуляция поведения блокировки прокрутки для запуска USB-переключателя KVM xfce: Как выровнять значки на правой стороне рабочего стола? Как вы используете 'find' для обновления права собственности на все каталоги, файлы и символические ссылки в папке? Экран записи в X Нажмите кнопку html через скрипт оболочки? Сравните два указателя, исключая расширения файлов правильное разбиение AVI-файла Есть ли способ отслеживать совместно используемые объекты (.so), загруженные при запуске определенного приложения? Вывести некоторые разделы текстового файла

Временно кэшируйте и записывайте буфер в каталог (чтобы ускорить процесс сборки на общем ресурсе NFS)

обзор

Этот вопрос структурирован следующим образом:
Сначала я расскажу о том, почему меня интересует эта тема и как она решит проблему, с которой я имею дело. Затем я задаю фактический автономный вопрос о кешировании файловой системы, поэтому, если вас не интересует мотивация (некоторые настройки сборки проекта на C ++), просто пропустите первый раздел.

Исходная проблема: привязка разделяемых библиотек

Я ищу способ ускорить время сборки нашего проекта. Настройка выглядит следующим образом: каталог (разрешает вызов workarea ) находится в общем ресурсе NFS. Он содержит только исходный код и make-файлы. Затем процесс сборки сначала создает статические библиотеки в workarea/lib а затем создает общие библиотеки в workarea/dll , используя статические библиотеки в workarea/lib . Во время создания разделяемых библиотек они не только записываются, но и снова считываются с использованием, например, nm для проверки времени ссылки, когда отсутствуют символы. Используя много заданий параллельно (например, make -j 20 или make -j 40), время сборки быстро доминирует за счет времени связывания. В этом случае производительность соединения ограничена производительностью файловой системы. Например, связывание с 20 заданиями параллельно примерно занимает 35 секунд в общем ресурсе NFS, но всего лишь 5 секунд в RAM-диске. Обратите внимание, что использование rsync для копирования dll обратно на общий ресурс NFS занимает еще 6 секунд, поэтому работа в RAM-диске и синхронизация с NFS впоследствии намного быстрее, чем прямое работа в общем разделе NFS. Я ищу способ достижения быстрой производительности без явного копирования / связывания файлов между общим файлом NFS и RAM-диском.
Обратите внимание, что наш общий ресурс NFS уже использует кеш, но этот кеш может кэшировать доступ только для чтения.
AFAIK, NFS требует, чтобы любой клиент NFS не смог подтвердить запись до тех пор, пока сервер NFS не подтвердит завершение записи, поэтому клиент не может использовать локальный буфер записи, а пропускная способность записи (даже в шипах) ограничена скоростью сети. Это эффективно ограничивает общую пропускную способность записи примерно до 80 МБ / с в нашей настройке.
Однако производительность чтения намного лучше, поскольку используется кеш чтения. Если я связываю (создаю содержимое dll ) с workarea/lib в NFS, а workarea/dll – символическая ссылка на RAM-накопитель, производительность по-прежнему хорошая – примерно 5 секунд. Обратите внимание, что для завершения процесса сборки требуется, чтобы workarea/* в общем ресурсе NFS: lib должен находиться в общем workarea/* (или любом постоянном монтировании), чтобы разрешить быстрые инкрементные сборки, а dll должна быть в NFS для доступа с помощью вычислительных машин, начинающих работу с использованием этих DLL.
Следовательно, я хотел бы применить решение проблемы ниже к workarea/dll и, возможно, также workarea/lib (последнее для улучшения времени компиляции). Требование быстрого времени установки ниже связано с необходимостью выполнять быстрые инкрементные сборки, при необходимости копируя данные.

Обновить

Вероятно, я должен был немного более подробно рассказать о настройке сборки. Вот еще несколько деталей: Компиляторы компилируются в .o-файлы во временном каталоге (в / tmp). Затем они объединяются в статические библиотеки в lib используя ar . Полный процесс сборки является инкрементным:

  • Компиляционные единицы только перекомпилируются, если сам блок компиляции (файл .C) или включенный заголовок (с использованием файлов зависимостей, сгенерированных компилятором, которые включены в make ).
  • Статические библиотеки обновляются только в том случае, если один из его компиляционных модулей был перекомпилирован.
  • Совместно используемые библиотеки обновляются только в том случае, если одна из ее статических библиотек изменилась. Символы разделяемых библиотек проверяются только в том случае, если символы, предоставленные совместно используемыми библиотеками, зависят от изменения, если обновлена ​​сама разделяемая библиотека.

Тем не менее, полные или почти полные перестройки необходимы довольно часто, поскольку несколько компиляторов ( gcc , clang ), версии компилятора, режимы компиляции ( release , debug ), стандарты C++97 ( C++97 , C++11 ) и дополнительные модификации ( например, libubsan ). Все комбинации эффективно используют разные каталоги lib и dll , поэтому можно переключаться между установками и строить поэтапно на основе последней сборки для этой самой настройки. Кроме того, для инкрементных построений часто нужно перекомпилировать несколько файлов, занимая очень мало времени, но вызывая перезагрузку (возможно, больших) разделяемых библиотек, занимая гораздо больше времени.

Обновление 2

Тем временем я узнал о опции монтирования nocto NFS, которая, по-видимому, могла решить мою проблему в основном для всех реализаций NFS, за исключением Linux, поскольку Linux сбрасывает буферы записи всегда на close() даже с nocto . Мы уже пробовали несколько других вещей: например, мы могли бы использовать другой локальный сервер NFS с включенной поддержкой async которая служит в качестве буфера записи и экспортирует основное монтирование NFS, но, к сожалению, сервер NFS сам по себе не создает буферизации записи. Кажется, что async просто означает, что сервер не заставляет свою базовую файловую систему скрываться в стабильном хранилище, а буфер записи используется неявно в том случае, если базовая файловая система использует буфер записи (как это, по-видимому, имеет место для файла система на физическом диске).
Мы даже подумали о возможности использования виртуальной машины, отличной от Linux, в том же окне, который монтирует основной общий ресурс NFS, используя nocto , обеспечивая буфер записи и обеспечивая это буферизованное монтирование через другой сервер NFS, но не тестировал его и хотел бы чтобы избежать такого решения.
Мы также обнаружили несколько оберток файловой системы на базе FUSE служащих кешами, но ни одна из них не реализовала буферизацию записи.

Кэширование и буферизация каталога

Рассмотрим какой-то каталог, позвоните ему orig , который находится в медленной файловой системе, например, общий ресурс NFS. В течение короткого промежутка времени (например, секунд или минут, но это ни в коем случае не имеет значения), я хотел бы создать полностью кэшированный и буферизованный вид orig используя cache каталога, который находится в быстрой файловой системе, например локальный жесткий диск или даже RAM-накопитель. Кэш должен быть доступен, например, через mount cached_view и не требует прав root. Я предполагаю, что на время существования кеша нет доступа к чтению или записи непосредственно в orig (помимо самого кеша, конечно). Полностью кэшированный и буферизованный я имею в виду следующее:

  1. Запросы на чтение отвечают путем пересылки запроса в файловую систему orig , кэширования этого результата и использования его с этого момента и
  2. Запросы записи записываются в cache и подтверждаются по завершении напрямую, т.е. кеш также является буфером записи. Это должно произойти, когда close() вызывается в записанном файле. Затем в фоновом режиме записи пересылаются (возможно, используя очередь) в orig . Разумеется, чтение запросов к письменным данным осуществляется с использованием данных в cache .

Кроме того, мне нужно:

  1. Кэш обеспечивает функцию для закрытия кеша, который сбрасывает все записи в orig . Продолжительность промывки должна зависеть только от размера записанных файлов, а не от всех файлов. Впоследствии можно было спокойно orig к orig .
  2. Время установки выполняется быстро, например, инициализация кеша может зависеть только от количества файлов в orig , но не от размера файлов в orig , поэтому копирование orig в cache не является вариантом.

Наконец, я также был бы в порядке с решением, которое не использует другую файловую систему в качестве кеша, а просто кэширует в основной памяти (на серверах много ОЗУ). Обратите внимание, что использование встроенных кешей, например NFS, не является опцией, так как AFAIK NFS не позволяет писать буферы записи (cf first section).

В моей настройке я мог бы подражать немного худшему поведению, символизируя содержимое orig в cache , а затем работать с cache (поскольку все операции записи фактически заменяют файлы новыми файлами, в этом случае символические ссылки заменяются обновленными версиями) и После этого измените файлы с измененными файлами. Это точно не соответствует указанным выше требованиям, например, чтение выполняется не один раз, а файлы заменяются символьными ссылками, что, конечно же, имеет значение для некоторых приложений.
Я предполагаю, что это не правильный способ решить эту проблему (даже в моей более простой настройке), и, возможно, кто-то знает о более чистом (и быстрее!) Решении.

Вау, удивленный, никто не ответил «overlayfs».

На самом деле у меня есть два предложения. Первый заключается в использовании overlayfs, который в основном является именно тем, что вы описываете, с одной оговоркой. Overlayfs (стандартный с Linux 3.18 или около того) позволяет вам читать из двух практически объединенных деревьев каталогов при написании только одного из них. Что бы вы сделали, так это быстросохранить (например, tmpfs) и наложить его на том NFS, а затем выполнить компиляцию в наложенном слиянии двух. Когда вы закончите, в NFS была записана нуль в любом файле, а в другой файловой системе – все ваши изменения. Если вы хотите сохранить изменения, вы можете просто переписать их обратно в NFS. Вы даже можете исключить файлы, которые вам не нужны, или просто вытащить несколько файлов из результата.

Вы можете увидеть относительно простой пример overlayfs в небольшом моем проекте: https://github.com/nrdvana/squash-portage/blob/master/squash-portage.sh Этот сценарий также показывает, как использовать UnionFS, если вы 're на более старом ядре, у которого нет overlayfs.

В моем случае команда rsync, используемая Gentoo для обновления своей библиотеки программного обеспечения, занимает безумно долгое время, так как у нее миллионы крошечных записей на диске. Я использую overlayfs для записи всех изменений в tmpfs, а затем я mksquashfs для создания сжатого изображения дерева. Затем я отбрасываю tmpfs и монтирую сжатое изображение на свое место.

Мое второе предложение – сборка «из дерева». Идея заключается в том, что у вас есть исходный код и make-файлы в одном дереве, и вы говорите automake генерировать все свои промежуточные файлы в отдельном дереве, которое отражает первое.

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