Буферизация поверх VFS

Проблема, которую я пытаюсь решить, - это сохранение большого количества (миллионов) небольших файлов (до 50 КБ), которые отправляются по сети. Сохранение выполняется последовательно: сервер получает файл или каталог (по сети), сохраняет его на диск; следующий приходит, он сохраняется и т. д. Очевидно, что производительность не приемлема, если несколько серверных процессов сосуществуют (скажем, у меня есть 5 процессов, которые все читают из сети и пишут одновременно), потому что планировщик ввода-вывода не ' не удается эффективно объединить записи ввода / вывода.

Предложенное решение состоит в том, чтобы реализовать некоторую буферизацию: каждый процесс сервера должен иметь кэш объемом 50 МБ, в который он должен записать текущий файл, выполнить chdir и т. Д.; когда буфер заполнен, он должен быть синхронизирован с диском, поэтому получается пакет ввода-вывода.

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

2) есть ли у вас предложения, где искать, если бы я это реализовал?

Большое спасибо.

3 ответа

Вам нужно будет сделать лучше, чем

"по-видимому, производительность не приемлема".

конкретно

  • Как ты это измеряешь? У вас есть точная, воспроизводимая фигура
  • Какова ваша цель?

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

Боюсь, без них ты утонул.

Насколько важны эти записи? У меня есть три предложения (которые можно объединить), но одно из них - большая работа, а одно менее безопасное...

Журналирование

Я предполагаю, что вы видите некоторую низкую производительность, частично из-за журналирования, характерного для большинства современных файловых систем Linux. Журналирование вызывает вставку барьеров в очередь ввода-вывода при записи метаданных файла. Вы можете попытаться уменьшить безопасность (и, возможно, увеличить скорость) с mount(8) опции barrier=0 а также data=writeback,

Но если происходит сбой, журнал не сможет предотвратить длительный fsck(8), И есть шанс, что fsck(8) приведет к выбрасыванию ваших данных при устранении проблемы. С одной стороны, это не шаг, чтобы сделать легкомысленный, с другой стороны, в прежние времена, мы побежали ext2 файловые системы в async Режим без журнала в обе стороны на снегу и нам понравилось.

IO Scheduler Лифт

Другая возможность - поменять лифт IO; увидеть Documentation/block/switching-sched.txt в исходном дереве ядра Linux. Короткая версия такова, что deadline, noop, as, а также cfq доступны. cfq по умолчанию ядро ​​и, вероятно, то, что использует ваша система. Ты можешь проверить:

$ cat /sys/block/sda/queue/scheduler
noop deadline [cfq] 

Самые важные части из файла:

As of the Linux 2.6.10 kernel, it is now possible to change the
IO scheduler for a given block device on the fly (thus making it possible,
for instance, to set the CFQ scheduler for the system default, but
set a specific device to use the deadline or noop schedulers - which
can improve that device's throughput).

To set a specific scheduler, simply do this:

echo SCHEDNAME > /sys/block/DEV/queue/scheduler

where SCHEDNAME is the name of a defined IO scheduler, and DEV is the
device name (hda, hdb, sga, or whatever you happen to have).

The list of defined schedulers can be found by simply doing
a "cat /sys/block/DEV/queue/scheduler" - the list of valid names
will be displayed, with the currently selected scheduler in brackets:

# cat /sys/block/hda/queue/scheduler
noop deadline [cfq]
# echo deadline > /sys/block/hda/queue/scheduler
# cat /sys/block/hda/queue/scheduler
noop [deadline] cfq

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

Изменения в приложении

Другая возможность - радикально изменить ваше приложение, чтобы самим связывать файлы и записывать на диск меньше больших файлов. Я знаю, это звучит странно, но (а) команда разработчиков iD упаковала свои карты, текстуры, объекты и т. Д. В гигантский zip файлы, которые они будут читать в программу с помощью нескольких системных вызовов, распаковывать и запускать, потому что они обнаружили, что производительность намного лучше, чем чтение нескольких сотен или нескольких тысяч небольших файлов. Время загрузки между уровнями было значительно короче. (b) Команда рабочего стола Gnome и группа рабочего стола KDE использовали разные подходы к загрузке своих значков и файлов ресурсов: команда KDE упаковывает свои многочисленные небольшие файлы в более крупные пакеты какого-либо типа, а команда Gnome этого не делала. Команда Gnome имела более длительные задержки при запуске и надеялась, что ядро ​​может предпринять некоторые усилия, чтобы улучшить время их запуска. Команда ядра продолжала предлагать меньший, больший, файловый подход.

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

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