Подтвердить что ты не робот

Случайный доступ к gzip файлам?

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

Теперь, чтобы распараллелить работу, я хочу запустить несколько конвейеров, каждая из которых принимает пару байтовых смещений - начало и конец - и принимает этот фрагмент файла. С простым файлом это может быть достигнуто с помощью head и tail, но я не уверен, как это сделать с сжатым файлом; если я gzip -dc и pipe в head, пары смещения, которые находятся ближе к концу файла, будут бесполезно искать через весь файл, поскольку он медленно распаковывается.

Итак, мой вопрос действительно о алгоритме gzip - теоретически можно ли искать смещение байта в базовом файле или получить произвольный кусок из него без каких-либо последствий декомпрессии всего файла до этой точки? Если нет, то как еще я могу эффективно разбивать файл на "случайный" доступ несколькими процессами, минимизируя служебные данные пропускной способности ввода/вывода?

4b9b3361

Ответ 1

Вы не можете сделать это с помощью gzip, но вы можете сделать это с помощью bzip2, который является блочным, а не основанным на потоках - это то, как Hadoop DFS разделяет и распараллеливает чтение огромных файлов с различными сопоставителями в своем алгоритме MapReduce. Возможно, имеет смысл повторно сжать ваши файлы как bz2, чтобы вы могли воспользоваться этим; это было бы проще, чем какой-то специальный способ упорядочить файлы.

Я нашел патчи, которые реализуют это в Hadoop, здесь: https://issues.apache.org/jira/browse/HADOOP-4012

Вот еще один пост по теме: файл BZip2 читайте в Hadoop

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

Ответ 2

Да, вы можете получить доступ к файлу gzip случайным образом, прочитав всю вещь последовательно один раз и построив индекс. См. examples/zran.c в zlib.

Если вы контролируете создание файла gzip, вы можете оптимизировать файл для этой цели, создав точки входа в произвольный доступ и построив индекс при сжатии.

Вы также можете создать gzip файл с маркерами, используя Z_SYNC_FLUSH, а затем Z_FULL_FLUSH в zlib deflate(), чтобы вставить два маркера и сделать следующий блок независимым от предыдущих данных. Это уменьшит сжатие, но не сильно, если вы не будете делать это слишком часто. Например. один раз каждый мегабайт должен иметь очень мало влияния. Затем вы можете найти девятибайтовый маркер (с гораздо менее вероятным ложным положительным, чем шестибайтовый маркер bzip2): 00 00 ff ff 00 00 00 ff ff.

Ответ 3

gzip действительно ожидает, что сможет передать файл с самого начала. Вы не можете начинать посередине.

Что вы можете сделать, так это разбить файл на блоки, кусочно сжатые с помощью gzip, а затем объединить вместе. Вы можете выбрать любой размер, который вам нравится для каждой части, например 10 МБ или 100 МБ. Затем вы декомпрессируете, начиная с начала фрагмента, который содержит требуемое смещение байта. Из-за малоизвестной функции gzip (которая заключается в том, что при распаковке файла, который является конкатенацией нескольких более мелких gzipped файлов, получается тот же результат, что и распаковка каждого из меньших файлов и объединение результата вместе), кусочно сжатый большой файл также работайте со стандартным gzip -d/gunzip, если вы загрузите все это.

Сложная часть: вам нужно поддерживать индекс, содержащий смещение байта начала каждой сжатой части в большом файле.

Ответ 4

FWIW: Я разработал инструмент командной строки на zlib zran.c, который создает индексы для файлов gzip, которые обеспечивают очень быстрый произвольный доступ к ним: https://github.com/circulosmeos/gztool

Он может даже создать индекс для все еще растущего файла gzip (например, журнала, созданного rsyslog непосредственно в формате gzip), тем самым уменьшая на практике время создания индекса. Смотрите опцию -S (Supervise).