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