У меня есть каталог с почти 100 файлами журналов, каждый весом 10 ~ 15 ГБ. Требуется прочитать построчно каждый файл (порядок не имеет значения), очистить строку json и выгрузить ее в хранилище эластичного поиска бэкэнда для индексации.
вот мой работник, который делает эту работу
# file = worker.php
echo " -- New PHP Worker Started -- "; // to get how many times gnu-parallel initiated the worker
$dataSet = [];
while (false !== ($line = fgets(STDIN))) {
// convert line text to json
$l = json_decode($line);
$dataSet[] = $l;
if(sizeof($dataSet) >= 1000) {
//index json to elasticsearch
$elasticsearch->bulkIndex($dataSet);
$dataSet = [];
}
}
С помощью ответов Вот а также Вот Я почти там, и он работает (вроде), но мне просто нужно убедиться, что под капотом он действительно делает то, что, как я предполагаю, он делает.
С одним файлом я могу справиться, как показано ниже
parallel --pipepart -a 10GB_input_file.txt --round-robin php worker.php
Это прекрасно работает. добавление —round-robin гарантирует, что рабочий процесс php запускается только один раз, а затем просто продолжает получать данные в виде конвейера (очередь бедного человека).
Таким образом, для машины 4CPU она запускает 4 php работников и очень быстро обрабатывает все данные.
Чтобы сделать то же самое для всех файлов, вот мой взгляд на это
find /data/directory -maxdepth 1 -type f | parallel cat | parallel --pipe -N10000 --round-robin php worker.php
Что-то вроде работает, но у меня есть ощущение, что это неправильный способ вложения параллели для всех файлов.
А во-вторых, поскольку он не может использовать —pipepart, я думаю, что это медленнее.
В-третьих, как только работа завершена, я вижу, что на 4-процессорной машине только 4 рабочих были запущены, и работа была выполнена. Это правильное поведение? Разве это не должно запускать 4 рабочих для каждого файла? Просто хочу убедиться, что я не пропустил никаких данных.
Есть идеи, как это можно сделать лучше?
Если они примерно одинакового размера, почему бы просто не дать один файл каждому:
find /data/directory -maxdepth 1 -type f |
parallel php worker.php '<' {}
Другой способ заключается в использовании --pipepart
на каждом из них:
do_one() {
parallel --pipepart -a "$1" --block -1 php worker.php
}
export -f do_one
find /data/directory -maxdepth 1 -type f | parallel -j1 do_one
Если это не займет много времени, чтобы начать php worker.php
тогда последний может быть предпочтительнее, потому что он будет распределяться более равномерно, если файлы очень разных размеров, поэтому, если последний файл огромен, вам не придется ждать, пока один процесс завершит его обработку.
Других решений пока нет …