URL: https://www.opennet.ru/cgi-bin/openforum/vsluhboard.cgi
Форум: vsluhforumID1
Нить номер: 78760
[ Назад ]

Исходное сообщение
"awk 'out of memory in array'"

Отправлено AD , 15-Фев-08 20:34 
Имеется большой файл по трафику с таким содержимым:
ip1  ip2 packets  bytes
ip2  ip3 packets2  bytes2
и т.д
Нужно как-то просуммировать пакеты и байты по совпадающим парам ип.
На awk сделал так:
awk '{k=$0;
    sub(/[ \t]+[0-9]+[ \t]+[0-9]+$/,"",k);
if ( NF==4 ){ s1[k]+=$3;   s2[k]+=$4;}}
    END {for(k in s1){print k,s1[k],s2[k]}}' traffic.dump_wait_agg >> traffic.dump

В итоге все работает как надо, но на больших файлах awk начинает ругаться - out of memory in array. Файлики могут быть по 1 Гб, оперативки 4 Гб.
Подскажите как сделать иначе или может не на awk даже, чтоб на больших объемах не падало.


Содержание

Сообщения в этом обсуждении
"awk 'out of memory in array'"
Отправлено pavel_simple , 15-Фев-08 21:05 
awk какой?
может стоит попробовать gawk или mawk?

"awk 'out of memory in array'"
Отправлено AD , 16-Фев-08 06:02 
>awk какой?
>может стоит попробовать gawk или mawk?

awk родной с freebsd пробовал, gawk также не смог, mawk дольше всех молотил, 1,7 гига в памяти было, потом полча сник. Наверно надо как-то по другому делать агрегацию строк.


"awk 'out of memory in array'"
Отправлено Hetzer , 16-Фев-08 13:34 
>>awk какой?
>>может стоит попробовать gawk или mawk?
>
>awk родной с freebsd пробовал, gawk также не смог, mawk дольше всех
>молотил, 1,7 гига в памяти было, потом полча сник. Наверно надо
>как-то по другому делать агрегацию строк.

просто интересно, если это сделать на perl и как он справится?


"awk 'out of memory in array'"
Отправлено AD , 17-Фев-08 18:34 
>>>awk какой?
>>>может стоит попробовать gawk или mawk?
>>
>>awk родной с freebsd пробовал, gawk также не смог, mawk дольше всех
>>молотил, 1,7 гига в памяти было, потом полча сник. Наверно надо
>>как-то по другому делать агрегацию строк.
>
>просто интересно, если это сделать на perl и как он справится?

Буду пробовать, наверно perl также поведет себя.


"awk 'out of memory in array'"
Отправлено angra , 17-Фев-08 22:07 
>Буду пробовать, наверно perl также поведет себя.

Это смотря как напишите и насколько много разных пар. Вам понадобится количество памяти равное: (количество разных пар) * (размер в байтах одного элемента хеша). Последнее врядли получится больше 20 байт и в любом случае общее количество сожранной памяти будет меньше исходного размера файла.
Приходилось при помощи перла удалять дублирующиеся строки в 30+ гиговых файлах и проблем не возникло, в процессе работы сжирало около сотни метров памяти.



"awk 'out of memory in array'"
Отправлено AD , 18-Фев-08 06:42 
>>Буду пробовать, наверно perl также поведет себя.
>
>Это смотря как напишите и насколько много разных пар. Вам понадобится количество
>памяти равное: (количество разных пар) * (размер в байтах одного элемента
>хеша). Последнее врядли получится больше 20 байт и в любом случае
>общее количество сожранной памяти будет меньше исходного размера файла.
>Приходилось при помощи перла удалять дублирующиеся строки в 30+ гиговых файлах и
>проблем не возникло, в процессе работы сжирало около сотни метров памяти.
>

В perl не силен, это как получится :)


"awk 'out of memory in array'"
Отправлено angra , 18-Фев-08 16:58 
Так бы сразу сказали, я бы еще в прошлом сообщении привел пример
Исходим из того что все значения в строке разделены пробелом. Тогда имеем
#!/usr/bin/perl
use strict;
my %sums; #хеш для суммирования, ключами будут пары ip, значениями ссыслка на массив из двух элементов [сумма пакетов, сумма байт]
while (<>) { #читаем со стандартного ввода или из файлов переданных в виде аргументов
        my @vals = split;#разбиваем строку на элементы
        my $k="$vals[0] $vals[1]"; #формируем ключ для хеша конкатенацией пары ip
        $sums{$k}->[0] += $vals[2]; #суммируем пакеты
        $sums{$k}->[1] += $vals[3]; #суммируем байты
}
print "Results:\n";
print "$_: $sums{$_}->[0] $sums{$_}->[1]\n" foreach (keys %sums) #выводим все пары, при желании можно добавить sort перед keys

Ну и пример выполнения
$ ./a.pl
1.1.1.1 1.1.1.2 10 15
1.1.1.1 1.1.1.3 10 15
1.1.1.1 1.1.1.2 10 15
1.1.1.2 1.1.1.3 20 20
Results:
1.1.1.2 1.1.1.3: 20 20
1.1.1.1 1.1.1.3: 10 15
1.1.1.1 1.1.1.2: 20 30

Возможной проблемой может быть переполнение суммы при превышении предела integer. Тогда можно посмотреть в сторону Math::BigInt или аналогов


"awk 'out of memory in array'"
Отправлено pavel_simple , 18-Фев-08 00:03 
а так?
awk '{if ( NF==4 ){ s1[$1"-"$2]+=$3;s2[$1"-"$2]+=$4;}} END {for(k in s1){print k,s1[k],s2[k]}}'
ИМХО от NF'а лучше заранее избавится grep'ом

"awk 'out of memory in array'"
Отправлено AD , 18-Фев-08 06:37 
>а так?
>awk '{if ( NF==4 ){ s1[$1"-"$2]+=$3;s2[$1"-"$2]+=$4;}} END {for(k in s1){print k,s1[k],s2[k]}}'
>ИМХО от NF'а лучше заранее избавится grep'ом

Так я тоже делал, разницы особой нету. По крайней мере, гиг не переварило.



"awk 'out of memory in array'"
Отправлено pavel_simple , 18-Фев-08 12:36 
>Так я тоже делал, разницы особой нету. По крайней мере, гиг не
>переварило.

"ну тогда незнаю" (C) Народная мудрось


Linux XXXX 2.6.22-3-amd64 #1 SMP Tue Feb 12 09:22:35 UTC 2008 x86_64 GNU/Linux

mawk 1.3.3 Nov 1996, Copyright (C) Michael D. Brennan

compiled limits:
max NF             32767
sprintf buffer      2040

ls -lah aaa.log
-rw-r--r-- 1 pavel pavel 2,2G 2008-02-18 14:23 aaa.log

time cat aaa.log | grep -v "Accounting"|grep -v "Source"| awk '{s1[$1"\t"$2]+=$3;s2[$1"\t"$2]+=$4;} END {for(k in s1){print k,s1[k],s2[k]}}'>aaa.done.log

real    2m11.159s
user    2m3.672s
sys    0m14.169s

даже учитавая то, что файлик aaa.log был создан искусственно (слепил десяток) памяти сожрал всего-то 100M


"awk 'out of memory in array'"
Отправлено Andrey Mitrofanov , 18-Фев-08 11:43 
>Подскажите как сделать иначе или может не на awk даже, чтоб на
>больших объемах не падало.

Например, суммировать "частями", потом частичные суммы суммировать.
Или скормить твой гигабайт sort-у :) и суммировать awk-ом с _одой_ суммой единовременно.
Или ещё какой хитрый "дизигн"-подход применить... Например, избавиться от гигабайтных логов совсем.


"awk 'out of memory in array'"
Отправлено ShyLion , 18-Фев-08 12:57 
>>Подскажите как сделать иначе или может не на awk даже, чтоб на
>>больших объемах не падало.
>
>Например, суммировать "частями", потом частичные суммы суммировать.
>Или скормить твой гигабайт sort-у :) и суммировать awk-ом с _одой_ суммой
>единовременно.
>Или ещё какой хитрый "дизигн"-подход применить... Например, избавиться от гигабайтных логов совсем.
>

Ага, например сливать не аккаунтинг, а NetFlow, и flow-tools'ами анализировать :)


"awk 'out of memory in array'"
Отправлено AD , 18-Фев-08 21:09 
В общем сделал на perl, как  angra советовал (готовый совет не хотелось сразу, хотел сам сделать, в итоге к почти такому и пришел :) ).
900 Мб файлик делал минуты 3-4, оперативки занял 1,6 Гб. На выходе файлик получился 180 Мб.
Спасибо большое всем за наставления ;)
Оставлю пока так, если уж будет совсем тяжко, тогда буду либо делить, либо netflow тот же юзать.

"awk 'out of memory in array'"
Отправлено angra , 18-Фев-08 22:27 
Ничего себе пожирание памяти. Не должно такого происходить. Можете привести код, который использовали?

"awk 'out of memory in array'"
Отправлено AD , 19-Фев-08 08:35 
>Ничего себе пожирание памяти. Не должно такого происходить. Можете привести код, который
>использовали?

Оставил Ваш вариант как основной.
Файл 900 мег, 16 млн строк.