Статьи

Ввод / вывод с файлами, которые не являются файлами

Недавно на работе мне нужно было просмотреть наши архивные файлы и предоставить результаты к концу дня. Вот параметры запроса:

  1. Архивные файлы зашифрованы и хранятся в HDFS (не спрашивайте, почему мы храним их в HDFS).
  2. Файлы различаются по размеру от 3 до 9 ГБ.
  3. Общее количество файлов для поиска было 300+
  4. Расшифровка каждого файла занимает от 1 до 2 минут.

В прошлом были запросы на поиск в одном архивном файле. В этих случаях мы будем копировать файл из HDFS на сервер. Затем запустите сценарий оболочки, чтобы расшифровать файл и выполнить поиск. Программа расшифровки требует 2 аргумента: зашифрованный файл и файл для записи расшифрованных данных. Это означает, что расшифрованный и зашифрованный файл находятся на диске одновременно.

При средней скорости 1,5 минуты для расшифровки одного файла для 300 файлов требовалось 450 минут (7,5 часов). Чтобы добавить к моей дилемме, не было достаточно времени, чтобы написать собственный RecordReader . Единственным решением было бы передавать файлы параллельно. Но есть 2 проблемы с этим подходом:

  1. На сервере недостаточно места для 20 (10 зашифрованных и 10 расшифрованных) файлов одновременно.
  2. Код дешифрования выполняет чтение из стандартного ввода или запись в стандартный вывод.

Что делать? Используйте именованные каналы, конечно!

Ускоренный курс по именованным каналам

Трубы используются для составления узконаправленных программ для решения более широких задач. Например :

Пример простых труб

cat someFile.txt | awk -F "|" '{print $5}' | cut -d ':' f2

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

  1. Вы создаете именованные каналы с помощью команды mkfifo name-of-pipe.
  2. Может использоваться повторно несколькими процессами.
  3. Namped трубы сохраняются, пока не будут удалены с помощью команды rm name-of-pipe.
  4. Существуют в файловой системе и отображаются в виде файлов для других процессов.
  5. Разрешить межпроцессное взаимодействие.

Вот пример создания именованного канала и как он выглядит в файловой системе:

Создать именованную трубу

new-host-2:~ bbejeck$ mkfifo pipe1
new-host-2:~ bbejeck$ ls -l pipe1
prw-r--r--  1 bbejeck  staff  0 Aug 16 21:28 pipe1

Обратите внимание, что именованный канал отображается в lsрезультатах, и первый столбец слева — это p. Если вам больше не нужен именованный канал, просто удалите его, как файл с командой rm pipe1.

Мое решение с именованными трубами

Сначала я создал файл, состоящий из путей к архивам. Затем скрипт перебрал файл и запустил 10 процессов дешифрования / поиска параллельно. После запуска 10 процессов сценарий будет ожидать завершения всех 10 процессов, прежде чем запускать другой пакет.

Цикл по списку файлов

count=0
while read fileName; do
   if [[ $((++count)) -eq 10 ]]; then
          count = 0
          wait
    fi
    #backgrounded process      
    processFile $fileName &
done < inputFileNames.txt

Вот код для processFileфункции.

функция processFile

function processFile {
    encryptedFile=$(basename ${1})
    decryptedFile=${encryptedFile%.enc}

    mkfifo ${encryptedFile}
    mkfifo ${decryptedFile}

    hdfs dfs -cat ${1} > ${encryptedFile} &
    cat ${decryptedFile} | awk '{ if ( $5 == someValue) print $0}' &

    /somepath/decryptFile.sh ${encryptedFile} ${decryptedFile}
    rm ${encryptedFile} ${decryptedFile}
}

Хотя processFileфункция проста, есть несколько шагов, которые мы должны объяснить:

  1. Строка 2: создайте переменную с базовым именем зашифрованного файла из полного пути.
  2. Строка 3: создайте переменную имени зашифрованного файла за вычетом .encрасширения файла.
  3. Строки 5,6: Создание именованных каналов для зашифрованного и расшифрованного файла.
  4. Строка 8: поток зашифрованный файл из HDFS и перенаправить на зашифрованный именованный канал и фоновый процесс.
  5. Строка 9: Запустите catкоманду для расшифрованного файла. Затем передайте результаты awkи найдите нужную информацию. Это тоже фоновое.
  6. Строка 11: вызов сценария дешифрования с необходимыми параметрами файла.
  7. Строка 12: после расшифровки и поиска файла удалите именованные каналы.

Вывод

Использование именованных каналов позволило мне расшифровать и найти более 300 файлов примерно за 1,5 часа. Я также избежал проблемы с пространством, так как мне никогда не приходилось записывать файл на диск. Хотя именованные каналы не нужны каждый день, они являются полезным инструментом в вашем арсенале.

Рекомендации