У меня есть файл системного журнала с 4 ГБ размером каждую минуту, и ниже 2 строки 4,5 миллионов строк в каждую минуту,
и я хочу генерировать новый файл только с немногими столбцами eventtime|srcip|dstip
, таким образом, результат будет как следовать
1548531299|X.X.X.X|X.X.X.X
обратите внимание на то, что положение полей случайно.
Я попробовал некоторые фильтры, но все еще потребление больше чем 40 минут для обработки одного файла на мощной машине VM с 4 Ядрами и поршне на 16 ГБ.
Так существует ли метод, чтобы обработать такой большой файл и отфильтровать необходимый столбец в быстром методе?
{Jan 26 22:35:00 172.20.23.148 date=2019-01-26 time=22:34:59 devname="ERB-03" devid="5KDTB18800169" logid="0000000011" type="traffic" subtype="forward" level="warning" vd="Users" eventtime=1548531299 srcip=X.X.X.X srcport=3XXXX srcintf="GGI-cer.405" srcintfrole="undefined" dstip=X.X.X.X dstport=XX dstintf="hh-BB.100" dstintfrole="undefined" sessionid=xxxxxxx proto=6 action="ip" policyid=5 policytype="policy" service="HTTP" appcat="unscanned" crscore=5 craction=xxxxxx crlevel="low"
Jan 26 22:35:00 172.20.23.148 date=2019-01-26 time=22:34:59 devname="XXX-XX-FGT-03" devid="XX-XXXXXXXX" logid="0000000013" type="traffic" subtype="forward" level="notice" vd="Users" eventtime=1548531299 srcip=X.X.X.X srcport=XXXXX srcintf="XXX-Core.123" srcintfrole="undefined" dstip=X.X.X.X dstport=XX dstintf="sXX-CC.100" dstintfrole="undefined" sessionid=1234567 cvdpkt=0 appcat="unscanned" crscore=5 craction=123456 crlevel="low"}
Сохраните следующий сценарий как filter.pl
и сделайте это исполняемым файлом (chmod +x
):
#!/usr/bin/env perl
use strict;
use warnings;
while( <> ) {
if ( /^(?=.*eventtime=(\S+))(?=.*srcip=(\S+))(?=.*dstip=(\S+)).*$/ ) {
print "$1|$2|$3\n";
}
}
Затем выполненный
pduck@ubuntu:~> time ./filter.pl < input.txt > output.txt
real 0m44,984s
user 0m43,965s
sys 0m0,973s
regex использует lookaround шаблон, в этом случае положительное предвидение, для соответствия трем значениям eventtime
, srcip
, и dstip
в любом порядке.
Я копировал Ваши две входных строки, пока я не получил файл с 4 ГБ и приблизительно 9 миллионов строк. Я выполнил код SSD.
Если Вы хотите действительно быстрое решение, я предлагаю инструмент гибкого провода. Flex генерирует C. Следующее способно к обработке примеров как тот, представленный, принимая свободные поля порядка. Поэтому создайте файл, названный f.fl
со следующим содержанием:
%option main
%%
char e[100], s[100], d[100];
eventtime=[^ \n]* { strcpy(e,yytext+10); }
srcip=[^ \n]* { strcpy(s,yytext+6); }
dstip=[^ \n]* { strcpy(d,yytext+6); }
\n { if (e[0] && s[0] && d[0] )printf("%s|%s|%s\n",e,s,d);
e[0]=s[0]=d[0]=0 ;}
. {}
%%
Протестировать попытку:
$ flex -f -o f.c f.fl
$ cc -O2 -o f f.c
$ ./f < input > output
Вот time
сравнение:
$ time ./f < 13.5-milion-lines-3.9G-in-file > out-file
real 0m35.689s
user 0m34.705s
sys 0m0.908s
Я копировал Ваши две 'входных' строки к размеру файла 3867148288 байтов (3,7 гибибайта), и я мог обработать его с grep
за 8 минут и 24 секунды (читающий из и пишущий в жесткий диск. Это должно быстрее использовать SSD или ramdrive).
Для уменьшения используемого времени я использовал только стандартные функции grep
, и не выполнял последующую обработку его, таким образом, выходной формат не то, что Вы указываете, но могли бы быть полезными так или иначе. Можно протестировать эту команду
time grep -oE -e 'eventtime=[0-9]* ' \
-e 'srcip=[[:alnum:]]\.[[:alnum:]]\.[[:alnum:]]\.[[:alnum:]]' \
-e 'dstip=[[:alnum:]]\.[[:alnum:]]\.[[:alnum:]]\.[[:alnum:]]' \
infile > outfile
Вывод от Ваших двух строк:
$ cat outfile
eventtime=1548531298
srcip=X.X.X.Y
dstip=X.X.X.X
eventtime=1548531299
srcip=X.X.X.Z
dstip=X.X.X.Y
Выходной файл содержит 25 165 824 строки, соответствующие 8388608 (8,3 миллионов) строки во входном файле.
$ wc -l outfile
25165824 outfile
$ <<< '25165824/3' bc
8388608
Мой тест указывает на это grep
может обработать приблизительно 1 миллион строк в минуту.
Если Ваш компьютер не намного быстрее, чем мой. это не достаточно быстро, и я думаю, что необходимо рассмотреть что-то, что несколько раз быстрее, вероятно, фильтрует прежде, чем записать файл журнала, но было бы лучше полностью избежать вывода того, что не необходимо (и постарайтесь не фильтровать).
Входной файл сделан дублированием, и возможно система 'помнит', что это видело те же строки прежде и делает вещи быстрее, таким образом, я не знаю, как быстро это будет работать с реальным большим файлом со всеми непредсказанными изменениями. Необходимо протестировать его.
Edit1: Я выполнил ту же задачу в Dell M4800 с процессором Intel 4th generation i7 и SSD. Это закончилось через 4 минуты и 36 секунд, почти в удвоенной скорости, 1,82 миллиона строк в минуту.
$ <<< 'scale=2;25165824/3/(4*60+36)*60/10^6' bc
1.82
Все еще слишком медленный.
Edit2: Я упростил grep
шаблоны и выполнили его снова в Dell.
time grep -oE -e 'eventtime=[^\ ]*' \
-e 'srcip=[^\ ]*' \
-e 'dstip=[^\ ]*' \
infile > out
Это закончилось после 4 минут и 11 секунд, маленького улучшения 2,00 миллионов строк в минуту
$ <<< 'scale=2;25165824/3/(4*60+11)*60/10^6' bc
2.00
Редактирование 3: @JJoao, расширение жемчуга убыстряется grep
к 39 секундам, соответствуя 12,90 миллионам строк в минуту в компьютере, где дежурное блюдо grep
чтения 1 миллион строк в минуту (читающий из и пишущий в жесткий диск).
$ time grep -oP '\b(eventtime|srcip|dstip)=\K\S+' infile >out-grep-JJoao
real 0m38,699s
user 0m31,466s
sys 0m2,843s
Это расширение жемчуга является experiental согласно info grep
но работы в моем Lubuntu 18.04.1 LTS.
‘-P’ ‘-perl-regexp’ Интерпретируют шаблон как Совместимое с Perl регулярное выражение (PCRE). Это экспериментально, особенно в сочетании с ‘-z’ (‘ - пустые данные’), опция, и ‘grep-P’ может предупредить о нереализованных функциях. *Отметьте Другие Опции::.
Я также скомпилировал программу C согласно @JJoao flex
метод и это finshed за 53 секунды, соответствуя 9,49 миллионам строк в минуту в компьютере, где дежурное блюдо grep
чтения 1 миллион строк в минуту (читающий из и пишущий в жесткий диск). Оба метода быстры, но grep
с жемчугом расширение является самым быстрым.
$ time ./filt.jjouo < infile > out-flex-JJoao
real 0m53,440s
user 0m48,789s
sys 0m3,104s
Редактирование 3.1: В Dell M4800 с SSD у меня были следующие результаты,
time ./filt.jjouo < infile > out-flex-JJoao
real 0m25,611s
user 0m24,794s
sys 0m0,592s
time grep -oP '\b(eventtime|srcip|dstip)=\K\S+' infile >out-grep-JJoao
real 0m18,375s
user 0m17,654s
sys 0m0,500s
Это соответствует
flex
приложениеgrep
с расширением жемчугаРедактирование 3.2: В Dell M4800 с SSD у меня были следующие результаты, когда я использовал опцию -f
к препроцессору гибкого провода,
flex -f -o filt.c filt.flex
cc -O2 -o filt.jjoao filt.c
Результат был улучшен, и теперь flex
приложение показывает самую высокую скорость
flex -f ...
$ time ./filt.jjoao < infile > out-flex-JJoao
real 0m15,952s
user 0m15,318s
sys 0m0,628s
Это соответствует
flex
приложение.Вот одно возможное решение, на основе этого ответа, предоставленного @PerlDuck только что:
#!/bin/bash
while IFS= read -r LINE
do
if [[ ! -z ${LINE} ]]
then
eval $(echo "$LINE" | sed -e 's/\({\|}\)//g' -e 's/ /\n/g' | sed -ne '/=/p')
echo "$eventtime|$srcip|$dstip"
fi
done < "$1"
Я не знаю, как это будет вести себя на таком большом файле, IMO awk
решение будет намного быстрее. Вот то, как это работает с обеспеченным входным примером файла:
$ ./script.sh in-file
1548531299|X.X.X.X|X.X.X.X
1548531299|X.X.X.X|X.X.X.X
Вот результат производительности time
тест, выполненный на регулярном i7, оборудованном SSD и 16 ГБ RAM:
$ time ./script.sh 160000-lines-in-file > out-file
real 4m49.620s
user 6m15.875s
sys 1m50.254s