запись в режиме реального времени на диск - PullRequest
5 голосов
/ 19 августа 2010

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

Я проверил диск с помощью dd. Я не использую какую-либо файловую систему на нем и пишу прямо на диск (открывая его с помощью прямого флага). Я могу получить около 100 МБ / с с размером блока 32 КБ.

В своем приложении я заметил, что не могу записывать данные на диск почти с такой скоростью. Поэтому я изучил происходящее и обнаружил, что некоторые записи занимают очень много времени. Мой блок кода выглядит (кстати, это на C):

last = get_timestamp();
write();
now = get_timestamp();
if (longest_write < now - last)
  longest_write = now - last;

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

Edit: На самом деле я использую несколько буферов типа, который я объявляю выше, и чередую их между собой на несколько дисков. Одним из решений моей проблемы было бы просто увеличить количество буферов, чтобы амортизировать стоимость длинных записей. Однако я хотел бы сохранить как можно меньший объем памяти, используемой для буферизации, чтобы избежать загрязнения кэша потока, который создает данные, записанные в буфер. Мой вопрос должен быть ограничен разницей в задержке записи небольшого блока на диск и как ее уменьшить.

Ответы [ 4 ]

8 голосов
/ 20 августа 2010

Я предполагаю, что вы используете диск ATA или SATA, подключенный к встроенному контроллеру дисков в стандартном компьютере. Это допустимое предположение или вы используете что-то необычное (аппаратный RAID-контроллер, диски SCSI, внешний диск и т. Д.)?

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

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

Если вы хотите оценить производительность дискового ввода-вывода, я бы порекомендовал использовать инструмент типа IOMeter вместо dd или собственный. IOMeter позволяет легко увидеть, какую разницу он имеет в изменении размера ввода / вывода, выравнивания и т. Д., А также отслеживает ряд полезных статистических данных.

Требование выполнения операции ввода-вывода в течение определенного промежутка времени является рискованным делом. С одной стороны, другие приложения в системе могут конкурировать с вами за доступ к диску или процессорное время, и почти невозможно предсказать их точное влияние на вашу скорость ввода-вывода. Ваш диск может столкнуться с поврежденным блоком, и в этом случае он должен выполнить дополнительную работу для переназначения затронутых секторов перед обработкой ввода / вывода. Это приводит к непредсказуемой задержке. Вы также не можете контролировать, что делают ОС, драйвер и контроллер диска. Ваш запрос ввода / вывода может быть сохранен на одном из этих уровней по любому количеству непредвиденных причин.

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

Ответ на комментарий: Вы не можете «убрать ядро ​​с пути», это самый низкий уровень в системе, и вы должны пройти его в той или иной степени. Возможно, вам удастся создать собственную версию драйвера для вашего контроллера диска (при условии, что он с открытым исходным кодом) и создать «высокоприоритетный» путь ввода-вывода для использования вашим приложением. Вы все еще находитесь в зависимости от встроенного программного обеспечения контроллера диска и встроенного программного обеспечения / оборудования самого привода, которое вы не можете предсказать или что-то сделать.

Жесткие диски традиционно работают лучше всего при выполнении больших последовательных операций ввода-вывода.Драйверы, встроенное ПО устройства и подсистемы ввода-вывода ОС учитывают это и пытаются группировать меньшие запросы ввода-вывода, чтобы они могли генерировать только один большой запрос ввода-вывода к диску.Если вы одновременно очищаете 32 КБ, ваши записи, вероятно, кэшируются на каком-то уровне, объединяются и отправляются на диск сразу.Победив это объединение, вы должны уменьшить количество «пиков» задержки ввода-вывода и увидеть более равномерное время доступа к диску.Однако эти времена доступа будут намного ближе к большим временам, наблюдаемым в ваших «всплесках», чем к умеренным временам, которые вы обычно видите.Пик задержки соответствует запросу ввода-вывода, который не был объединен с любыми другими и, таким образом, должен был поглощать все издержки поиска диска.Запрос на объединение сделан по причине;связывая запросы, вы амортизируете накладные расходы на операцию поиска диска по нескольким командам.Отказ от объединения приводит к выполнению большего количества операций поиска, чем обычно, что в целом приводит к более низкой скорости ввода-вывода.Это компромисс: вы уменьшаете среднюю задержку ввода / вывода за счет того, что иногда выполняете ненормальную операцию с высокой задержкой.Однако это выгодный компромисс, поскольку увеличение средней задержки, связанное с отключением объединения, почти всегда является большим недостатком, чем преимущество при более согласованном времени доступа.

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

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

Учитывая объем памяти, который есть у большинства машин, переход от буфера 32 КБ к системе, которая вращается на 432 КБ буфера - довольно незначительный скачок в использовании памяти.В системе с 1 ГБ памяти увеличение размера буфера составляет всего 0,0092% системной памяти.Попробуйте перейти к системе чередующихся / вращающихся буферов (для простоты, начните с 2) и измерьте влияние на поток с высокой пропускной способностью.Держу пари, что дополнительные 32 КБ памяти не окажут какого-либо заметного влияния на другой поток.Это не должно «загрязнять кеш» потока производителя.Если вы постоянно используете эти области памяти, они всегда должны быть помечены как «используемые» и никогда не должны выгружаться из физической памяти.Сбрасываемый буфер должен оставаться в физической памяти, чтобы DMA работал, а второй буфер будет в памяти, потому что ваш поток производителя в данный момент записывает в него. верно , что использование дополнительного буфера уменьшит общий объем физической памяти, доступной потоку производителя (хотя и незначительно очень ), но если вы используете приложение, которое требует высокойпропускная способность и низкая задержка, то вы бы спроектировали свою систему так, чтобы у нее оставалось гораздо больше 32 КБ памяти.

Вместо того чтобы решать проблему, пытаясь заставить аппаратное и низкоуровневое программное обеспечение выполнять определенные измерения производительности, более простым решением является адаптация вашего программного обеспечения под аппаратное обеспечение. Если вы измеряете максимальную задержку записи, равную 1 секунде (ради хороших круглых чисел), напишите свою программу так, чтобы буфер, записанный на диск, не нуждался в повторном использовании в течение как минимум 2,5-3 секунд. Таким образом, вы охватите свой наихудший сценарий и обеспечите запас прочности на случай, если произойдет что-то действительно неожиданное. Если вы используете систему, в которой вы поворачиваете через 3-4 выходных буфера, вам не нужно беспокоиться о повторном использовании буфера до его очистки. Вы не сможете управлять аппаратным обеспечением слишком близко, и если вы уже пишете в сырой том (без файловой системы), между вами и оборудованием, с которым вы можете манипулировать или устранять, не так уж много. Если ваша программа негибкая и вы видите недопустимые всплески задержки, вы всегда можете попробовать более быстрый диск. Твердотельные накопители не должны «искать» операции ввода-вывода, поэтому вы должны увидеть довольно равномерную задержку ввода-вывода аппаратного обеспечения.

2 голосов
/ 20 августа 2010

Пока вы используете O_DIRECT | O_SYNC, вы можете использовать ioprio_set(), чтобы установить приоритет планирования ввода-вывода для вашего процесса / потока (хотя на странице руководства написано "процесс", я полагаю, вы можете передать TID, как указаноgettid()).

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

1 голос
/ 20 августа 2010

У меня есть поток, который должен записывать данные из буфера в памяти на диск тысячи раз.

Я проверил диск с помощью dd. Я не использую какую-либо файловую систему на нем и пишу прямо на диск (открывая его с помощью прямого флага). Я могу получить около 100 МБ / с с размером блока 32 КБ.

Размер блока dd соответствует размеру блока файловой системы. Я думаю, ваш файл журнала не.

Плюс, вероятно, ваше приложение записывает не только файл журнала, но и выполняет некоторые другие файловые операции. Или ваше приложение не одиноко, используя диск.

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

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

Некоторые записи занимают больше времени, потому что через некоторое время вы насыщаете очередь записи, и ОС, наконец, решает фактически сбросить данные на диск. Очереди ввода / вывода по умолчанию настроены довольно коротко: чтобы избежать чрезмерной буферизации и потери информации из-за сбоя.

N.B. Если вы хотите увидеть скорость real , попробуйте установить флаг O_DSYNC при открытии файла.

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

100 МБ / с с dd - без какой-либо синхронизации - это очень синтетический тест, поскольку вы никогда не знаете, что данные действительно попали на диск. Попробуйте добавить conv=dsync в командную строку dd.

Также пытаюсь использовать блок большего размера. 32К все еще мало. Размер IIRC 128K был оптимальным, когда я тестировал последовательный и случайный ввод-вывод несколько лет назад.

Я вижу самую длинную скорость записи около 47 мс.

«Реальное время»! = «Быстро». Если я определю максимальное время ответа 50 мс, а ваше приложение будет постоянно отвечать в течение 50 мс (47 <50), тогда ваше приложение будет классифицировано как реальное время. </p>

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

Я не думаю, что вы можете избежать задержек write(). Задержки являются свойством наследования дискового ввода-вывода. Вы не можете избежать их - вы должны ожидать и обращаться с ними.

Я могу думать только о следующей опции: использовать два буфера. Первый будет использоваться write(), второй - для хранения новых входящих данных из потоков. Когда write() закончится, переключите буферы и, если есть что написать, начните писать. Таким образом, всегда есть буфер для потоков, в которые можно поместить информацию. Переполнение может все еще произойти, если потоки генерируют информацию быстрее, чем write () может записать. Динамическое добавление дополнительных буферов (до некоторого предела) может помочь в этом случае.

В противном случае вы можете достичь некоторого вида реального времени для (ротационного) дискового ввода-вывода, только если ваше приложение является единственным пользователем диска. (Применяется старое правило приложений реального времени: их может быть только один.) O_DIRECT помогает как-то убрать влияние самой ОС из уравнения. (Хотя вы по-прежнему будете иметь накладные расходы на файловую систему в виде случайных задержек из-за выделения блоков для расширения файла. В Linux это работает довольно быстро, но все же этого можно избежать, предварительно выделив весь файл заранее, например, записав нули. ) Если сроки действительно важны, подумайте о покупке специального диска для работы. SSD имеют отличную пропускную способность и не страдают от поиска.

0 голосов
/ 19 августа 2010

Вы пишете в новый файл или перезаписываете тот же файл?

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

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

...