Написание файла .tgz с использованием PHP с более чем 100 000 записей, но без записи отдельных файлов

Я пытаюсь написать файл .tgz, содержащий десятки, если не сотни тысяч файловых записей, содержимое каждой из которых получено из строки в базе данных. Каждая запись файла составляет около 2-5 КБ данных.

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

Диск, который мы используем, медленный, поэтому запись десятков тысяч файлов занимает целую вечность. Даже запуская прототип на другой машине с быстрым диском, используя RAM-диск tmpfs и много процессора, я получаю скорость около 100-200 файловых записей в секунду, что кажется медленным — полчаса для 150 000 файлов в структуре каталогов. Как только это будет написано, фактическое преобразование из родной структуры каталогов ОС в tgz не будет проблемой.

Я надеялся использовать PharData для написания. Однако PharData::addFromString, по-видимому, выполняет запись в файл, как только файл добавляется, а не шаблон Open->Add->Writeout.

Может ли кто-нибудь предложить какие-либо стратегии здесь?

После этого конечный файл tgz будет доступен для скачивания и не будет часто обновляться. Но из-за того, что нужно создать ряд этих файлов, приходится ждать 30-60+ минут только для того, чтобы упаковать, и это становится серьезным препятствием.


person fooquency    schedule 30.03.2015    source источник
comment
Можете ли вы дать некоторый контекст о том, какое улучшение производительности вы ищете, и для чего этот файл? Как часто требуется обновленный файл? Например, если это файл, который доступен для загрузки на веб-сайте, нужно ли вам обновлять его чаще, чем каждые полчаса? (Я согласен, что 200 записей в секунду звучит медленно, но я считаю, что сжатие — это процесс, интенсивно использующий процессор).   -  person halfer    schedule 30.03.2015
comment
Если вас не беспокоит больший размер выходного файла, попробуйте уменьшить уровень сжатия. У команды gzip действительно есть опция --fast, попробуйте?   -  person halfer    schedule 30.03.2015
comment
Конечно, было бы интересно сравнить рабочую нагрузку при отключении сжатия, чтобы определить, в чем заключаются проблемы с производительностью. Я подозреваю, что ваш самый большой выигрыш будет заключаться в использовании другой структуры для хранения данных - следовательно, каковы возможности ее изменения?   -  person symcbean    schedule 30.03.2015
comment
Я добавил некоторые пояснения - проблема не в этапе сжатия, а в текущем этапе создания каталога до сжатия, но я надеюсь, что есть лучший способ справиться с этим фундаментально. Я также разъяснил использование файла - см. новый последний абзац.   -  person fooquency    schedule 30.03.2015


Ответы (2)


Вы можете напрямую использовать функции php gzopen/gzwrite/gzclose и форматировать свои собственные заголовки tar, за которыми следуют данные ввода. На странице документации по php gzwrite есть пример.

person Mark Adler    schedule 31.03.2015
comment
К сожалению, у этого, похоже, та же проблема - он записывает весь архив после каждого вызова addString, вместо того, чтобы разрешить выполнение нескольких addString, а затем записать файл. Соответственно, это потребовало бы более 100 000 операций записи файлов в дополнение к более чем 100 000 вычислений сжатия, что даже хуже, чем подход со структурой каталогов. - person fooquency; 31.03.2015

Это старый вопрос, однако я постараюсь на него ответить.
Буферизация Phar поддерживалась по крайней мере в PHP 5.3:

Phar::startBuffering()
Начать буферизацию операций записи Phar, не изменять объект Phar на диске

Phar::stopBuffering()
Остановить буферизацию запросов на запись в архив Phar, и сохранить изменения на диск


Небольшой пример того, как это будет выглядеть:

<?php
$phar = new Phar('bundle.phar');
$phar->startBuffering();
// ... adding files and contents ...
$phar->setStub('<?php __HALT_COMPILER();');
$phar->stopBuffering();
person Oliver Hader    schedule 02.01.2021