Улучшить скорость записи для высокоскоростного копирования файлов?

Я пытался найти самый быстрый способ закодировать процедуру копирования файлов, чтобы скопировать большой файл на оборудование RAID 5.

Средний размер файла составляет около 2 ГБ.

Есть 2 виндовса (на обоих работает win2k3). Первое поле - это источник, где находится большой файл. И второй ящик имеет хранилище RAID 5.

http://blogs.technet.com/askperf/archive/2007/05/08/slow-large-file-copy-issues.aspx

Приведенная выше ссылка ясно объясняет, почему копирование Windows, robocopy и другие распространенные утилиты копирования снижают производительность записи. Поэтому я написал программу C/C++, которая использует API CreateFile, ReadFile и WriteFile с флагами NO_BUFFERING и WRITE_THROUGH. Программа имитирует ESEUTIL.exe, в том смысле, что использует 2 потока, один для чтения и один для записи. Поток чтения читает 256 КБ из исходного кода и заполняет буфер. После заполнения 16 таких блоков по 256 КБ поток записи записывает содержимое буфера в целевой файл. Как видите, поток записи записывает 8 МБ данных за один раз. Программа выделяет 32 таких блока по 8 МБ... следовательно, запись и чтение могут происходить параллельно. Подробную информацию о ESEUtil.exe можно найти по ссылке выше. Примечание. Я забочусь о проблемах с выравниванием данных при использовании NO_BUFFERING.

Я использовал утилиты бенчмаркинга, такие как ATTO, и обнаружил, что наше оборудование RAID 5 имеет скорость записи 44 МБ в секунду при записи блока данных размером 8 МБ. Что составляет около 2,57 ГБ в минуту.

Но моя программа способна достичь только 1,4 ГБ в минуту.

Может ли кто-нибудь помочь мне определить, в чем проблема? Доступны ли более быстрые API, чем CreateFile, ReadFile, WriteFile?


person ring0    schedule 08.01.2010    source источник
comment
Вы можете опубликовать код, чтобы превратить это в вопрос по программированию; в противном случае он, скорее всего, будет перемещен на serverfault.com.   -  person RickNZ    schedule 08.01.2010
comment
Подождите, 44 МБ в секунду? Разве это не та постоянная пропускная способность, которую вы должны получить для одного диска в наши дни?   -  person Pascal Cuoq    schedule 08.01.2010
comment
@Pascal: RAID 5 не оптимизирован для скорости записи. Я удивлен, что вы даже получаете 44 МБ/с. Я ожидал ниже.   -  person jalf    schedule 09.01.2010
comment
Пожалуйста, сделайте дополнительный тест: отделите записывающую часть кода, напишите искусственные данные (случайные числа, нули и т.п.) и замерьте скорость записи. Просто чтобы исключить любые другие узкие места (сеть, чтение и т.д.). И, пожалуйста, отпишитесь о результатах!   -  person Frunsi    schedule 09.01.2010


Ответы (7)


Вы должны использовать асинхронный ввод-вывод, чтобы получить максимальную производительность. Это открытие файла с помощью FILE_FLAG_OVERLAPPED и использование аргумента LPOVERLAPPED WriteFile. Вы можете или не можете улучшить производительность с FILE_FLAG_NO_BUFFERING. Вам придется проверить, чтобы увидеть.

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

Вы также должны проверить, какой оптимальный размер для каждого блока ввода-вывода. По моему опыту, существует огромная разница в производительности между копированием файла 4 КБ за раз и копированием его 1 МБ за раз.

В моем прошлом тестировании этого (несколько лет назад) я обнаружил, что в размерах блоков менее 64 КБ преобладают накладные расходы, а общая пропускная способность продолжала улучшаться с большими размерами блоков примерно до 512 КБ. Я не удивлюсь, если с сегодняшними дисками вам нужно использовать блоки размером более 1 МБ, чтобы получить максимальную пропускную способность.

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

Вы также должны знать, что копирование файлов с помощью CreateFile/WriteFile не приведет к копированию метаданных, таких как временные метки или альтернативные потоки данных в NTFS. С этими вещами вам придется разбираться самостоятельно.

На самом деле замена CopyFile вашим собственным кодом — это довольно много работы.

Приложение:

Вероятно, мне следует упомянуть об этом, когда я пробовал это с программным Raid 0 в WindowsNT 3.0 (около 10 лет назад). Скорость была ОЧЕНЬ чувствительна к выравниванию в памяти буферов. Оказалось, что в то время драйверы SCSI должны были использовать специальный алгоритм выполнения DMA из списка разброса/сбора, когда DMA составлял более 16 физических областей памяти (64Кб). Чтобы получить гарантированную оптимальную производительность, требуются физически непрерывные выделения, которые могут запрашивать только драйверы. По сути, это был обходной путь для ошибки в контроллере DMA популярного в то время чипсета, и вряд ли он все еще будет проблемой.

НО - я бы все же настоятельно рекомендовал вам протестировать ВСЮ мощность двух размеров блоков от 32 КБ до 32 МБ, чтобы увидеть, какой из них быстрее. И вы можете подумать о тестировании, чтобы увидеть, постоянно ли одни буферы работают быстрее, чем другие - это не является чем-то неслыханным.

person John Knoeller    schedule 12.01.2010
comment
Я еще не пробовал асинхронный ввод-вывод. Я должен попробовать. Кстати, после некоторого теста чтения/записи я выяснил, что 256 КБ чтения и 8 МБ записи дают максимальную пропускную способность. Я написал программу чтения, чтобы проверить скорость чтения, и использовал ATTO и другую написанную программу для проверки скорости записи. - person ring0; 19.01.2010

Некоторое время назад я написал в блоге сообщение об асинхронном файловом вводе-выводе и о том, как часто он оказывается синхронным, если вы не делаете все правильно (http://www.lenholgate.com/blog/2008)./02/когда-асинхронный-файл-пишет-не-асинхронно.html).

Ключевым моментом является то, что даже когда вы используете FILE_FLAG_OVERLAPPED и FILE_FLAG_NO_BUFFERING, вам все равно нужно предварительно расширять файл, чтобы вашим асинхронным записям не нужно было расширять файл по мере их выполнения; по соображениям безопасности расширение файла всегда синхронно. Для предварительного продления необходимо сделать следующее:

  • Включите привилегию SE_MANAGE_VOLUME_NAME.
  • Откройте файл.
  • Найдите желаемую длину файла с помощью SetFilePointerEx().
  • Установите конец файла с помощью SetEndOfFile().
  • Установите конец допустимых данных в файле SetFileValidData().
  • Закройте файл.

Потом...

  • Откройте файл для записи.
  • Выдать записи
person Len Holgate    schedule 12.01.2010
comment
На самом деле я предварительно расширяю файл. Поскольку я использую NO_BUFFERING, я забочусь о проблемах выравнивания данных. Например, чтобы скопировать файл размером 1027 КБ. 1) Я создаю целевой файл размером 1024 КБ. Использование SetFilePointerEx и SetEndOfFile. 1024 КБ из-за соображений выравнивания. 2) Запустите копирование. 3) После того, как скопировано 1024 КБ, я закрываю дескриптор целевого файла, повторно открываю его без использования флага NO_BUFFERING, ищу соответствующее смещение с помощью SetFilePointerEx, а затем запускаю WriteFile, который автоматически увеличивает размер файла до 1027 КБ. Я еще не читал ваш блог. Я сделаю это и вернусь к вам. - person ring0; 19.01.2010

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

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

http://technet.microsoft.com/en-us/sysinternals/bb897428.aspx

Насколько быстро сеть соединяет две машины?

Вы пробовали просто записывать фиктивные данные, не читая их сначала, как это делает ATTO?

Есть ли у вас одновременно более одного запроса на чтение или запись?

Каков размер полосы вашего массива RAID-5? Запись всей полосы за один раз — это самый быстрый способ записи в RAID-5.

person RickNZ    schedule 08.01.2010

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

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

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

person Thomas Matthews    schedule 08.01.2010

Если скорость записи так важна, почему бы не рассмотреть RAID 0 для вашей аппаратной конфигурации?

  • Клиент хочет RAID 5.
  • Предпочтительнее RAID 0 из-за лучшей отказоустойчивости.
  • Клиент доволен тем, что может предложить RAID 5. Вопрос здесь в том, что бенчмаркинг оборудования с использованием ATTO показывает скорость записи 2,57 ГБ в минуту (запись фрагмента 8 МБ), почему инструмент копирования не может достичь этого? Что-то вроде 2 ГБ в минуту — это то, на что мы смотрим. Пока нам удалось достичь только ~1,5 ГБ в минуту.
person ring0    schedule 09.01.2010

Правильный способ сделать это — использовать небуферизованный полностью асинхронный ввод-вывод. Вы захотите выполнить несколько операций ввода-вывода, чтобы сохранить очередь. Это позволяет файловой системе, драйверу и подсистеме Raid-5 более оптимально управлять вводом-выводом.

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

ПРИМЕЧАНИЕ! Оптимальное количество незавершенных операций ввода-вывода и способ чередования операций чтения и записи будут сильно зависеть от самой подсистемы хранения. Ваша программа должна быть тщательно параметризована, чтобы вы могли ее настроить.

Примечание. Я считаю, что Robocopy улучшили. Вы пробовали? я

person Foredecker    schedule 12.01.2010
comment
Одна цель состоит в том, чтобы свести к минимуму движение головки диска. Если вы открываете несколько файлов или выполняете непоследовательные запросы ввода-вывода, поиск головки диска может привести к падению пропускной способности ввода-вывода на порядок или более. - person RickNZ; 12.01.2010
comment
На самом деле это совсем не так. Открытие нескольких файлов сначала устраняет этот ввод-вывод. это также позволяет файловой системе более эффективно загружать объекты каталога. Обычно ОС работает лучше, когда у нее есть очередь запросов ввода-вывода для работы. - person Foredecker; 13.01.2010

Я сделал несколько тестов и получил некоторые результаты. Тесты проводились на сетевой карте 100 Мбит/с и 1 Гбит/с. Исходная машина — сервер Win2K3 (SATA), а целевая машина — сервер Win2k3 (RAID 5).

Я провел 3 теста:

1) Network Reader -> Эта программа просто читает файлы по сети. Цель программы - найти максимальную скорость чтения n/w. Я выполняю НЕБУФЕРНОЕ чтение, используя CreateFile и ReadFile.

2) Disk Writer -> Эта программа измеряет скорость RAID 5 путем записи данных. Небуферизованные записи выполняются с помощью CreateFile и WriteFile.

3) Blitz Copy -> Эта программа является механизмом копирования файлов. Он копирует файлы по сети. Логика этой программы обсуждалась в начальном вопросе. Я использую синхронный ввод-вывод с чтением и записью NO_BUFFERING. Используемые API: CreateFile, ReadFile и WriteFile.


Ниже приведены результаты:

СЕТЕВОЙ ЧИТАТЕЛЬ:-

сетевой адаптер 100 Мбит/с

Потребовалось 148 344 мс, чтобы прочитать 768 МБ с размером фрагмента 8 КБ.

Потребовалось 89359 мс, чтобы прочитать 768 МБ с размером блока 64 КБ

Потребовалось 82 625 мс, чтобы прочитать 768 МБ с размером фрагмента 128 КБ

Потребовалось 79594 мс, чтобы прочитать 768 МБ с размером блока 256 КБ

Потребовалось 78687 мс, чтобы прочитать 768 МБ с размером блока 512 КБ

Потребовалось 79078 мс для чтения 768 МБ с размером фрагмента 1024 КБ

Потребовалось 78594 мс, чтобы прочитать 768 МБ с размером блока 2048 КБ

Потребовалось 78 406 мс для чтения 768 МБ с размером фрагмента 4096 КБ

Потребовалось 78281 мс для чтения 768 МБ с размером фрагмента 8192 КБ

сетевой адаптер 1 Гбит/с

Потребовалось 206 203 мс для чтения 5 120 МБ (5 ГБ) с размером фрагмента 8 КБ

Потребовалось 77860 мс, чтобы прочитать 5120 МБ с размером фрагмента 64 КБ

Потребовалось 74531 мс, чтобы прочитать 5120 МБ с размером блока 128 КБ

Потребовалось 68 656 мс для чтения 5 120 МБ с размером фрагмента 256 КБ

Потребовалось 64922 мс, чтобы прочитать 5120 МБ с размером фрагмента 512 КБ

Потребовалось 66312 мс, чтобы прочитать 5120 МБ с размером фрагмента 1024 КБ

Потребовалось 68 688 мс для чтения 5 120 МБ с размером фрагмента 2048 КБ

Потребовалось 64922 мс для чтения 5120 МБ с размером фрагмента 4096 КБ

Потребовалось 66047 мс, чтобы прочитать 5120 МБ с размером фрагмента 8192 КБ

ЗАПИСЬ НА ДИСК:-

Запись выполняется на RAID 5 с NO_BUFFERING и WRITE_THROUGH

Запись 2048 МБ (2 ГБ) данных с размером фрагмента 4 МБ заняла 68 328 мс.

Запись 2048 МБ данных с размером фрагмента 8 МБ заняла 55 985 мс.

Запись 2048 МБ данных с размером фрагмента 16 МБ заняла 49 569 мс.

Запись 2048 МБ данных с размером фрагмента 32 МБ заняла 47 281 мс.

Запись выполняется на RAID 5 только с NO_BUFFERING

Запись 2048 МБ (2 ГБ) данных с размером фрагмента 4 МБ заняла 57 484 мс.

Запись 2048 МБ данных с размером фрагмента 8 МБ заняла 52 594 мс.

Запись 2048 МБ данных с размером фрагмента 16 МБ заняла 49 125 мс.

Запись 2048 МБ данных с размером фрагмента 32 МБ заняла 46 360 мс.

Производительность записи снижается линейно по мере уменьшения размера фрагмента. А флаг WRITE_THROUGH приводит к снижению производительности

БЛИЦ-КОПИЯ:-

Сетевой адаптер 1 Гбит/с, копирование файлов объемом 60 ГБ с использованием NO_BUFFERING

Время, затраченное на полное копирование: 2236735 мс. То есть 37,2 мин. Скорость ~97 ГБ/пер.

сетевой адаптер 100 Мбит/с, копирование 60 ГБ файлов без буферизации

Время, затраченное на полное копирование: 7337219 мс. То есть 122 мин. Скорость ~30 ГБ/пер.

Я пытался использовать программу 10-FileCopy Джеффри Ритчера, которая использует Async-IO с NO_BUFFERING. Но результаты были плохими. Я предполагаю, что причина может быть в том, что размер фрагмента составляет 256 КБ ... 256 КБ записи на RAID 5 ужасно медленные.

Сравнение с robocopy:

100 Мбит/с NIC: Blitz Copy и robocopy выполняются со скоростью ~30 ГБ в час.

Сетевая карта со скоростью 1 Гбит/с: Blitz Copy работает со скоростью ~97 ГБ в час, а robocopy — с частотой ~50 ГБ в час.

person ring0    schedule 02.02.2010