Domainnamen aus Zone File parsen
Seit ein paar Tagen habe ich Zugriff auf die Versign Zone Files und versuche mich im parsen der Domainnamen direkt auf der Command Line. Ich möchte nur die Domainnamen, unique und sortiert haben um sie im Anschluss weiter auswerten zu können. Die Zone Files werden 1x am Tag aktualisiert und per Script herunter geladen. Im ersten Schritt werden alle unnützen Zeichen/Zeilen entfernt, dann wird die Liste sortiert und unique gemacht. Im zweiten Schritt soll eine Liste mit neu dazu gekommenen und entfernt gewordenen Domains erstellt werden. Das ganze soll automatisch laufen und die Resultate sollen direkt in eine MySQL Datenbank geschrieben werden. Hier nun mein Vorgehen um dies zu erreichen.
Teil 1: Vorbereiten der Daten
Als erstes wird das Zone File ein bisschen entschlackt und von unnützen Daten befreit.
$ cat net.zone | wc -l 31.588.624
$ time cat net.zone | \
awk 'NR > 43' | \
awk 'split($1, x, / /) {print x[1]}' | \
grep -v '\.' | \
sed '$d' | \
sort -u > netdomains
real 2m26.329s
user 2m39.694s
sys 0m4.188s
Das funktioniert soweit auch ganz gut, aber um so größer die Datei, umso länger dauert es. Das .net Zone File hat in diesem Fall "gerade mal" 31.588.624 Zeilen. Das .com Zone File schlägt schon mit mehr als 210 Millionen Zeilen zu Buche und die Ausführung dauert hier 19 Minuten. Nun war recht schnell klar was das ganze so langsam macht und das ist das sort -u. Lässt man es weg, läuft das .net Zone File in 30 Sekunden durch und das .com Zone File in unter 6 Minuten. Also habe ich versucht diesen Teil zu optimieren. Um den Overhead zu minimieren, habe ich zum Testen das Resultat ohne sort -u gespeichert und dann weiter bearbeitet. In netdomains2 sind alle Domains unsortiert und nicht unique enthalten. Die Aufgabe ist nun die Namen unique zu bekommen und die Datei zu sortieren. Zu erste der Ausgangspunkt mit sort -u.
$ time cat netdomains2 | sort -u > test1 real 1m53.885s user 1m52.583s sys 0m1.156s $ cat test1 | wc -l 13.502.688
Dann habe ich uniq getestet. Das läuft super schnell wie man sehen kann.
$ time cat netdomains2 | uniq > test2 real 0m4.209s user 0m3.752s sys 0m0.548s $ cat test2 | wc -l 13.503.144
Fügt man nun noch sort an, hat man fast 1 Minute gespart und das gewünschte Ergebnis.
$ time cat netdomains2 | uniq | sort > test3 real 1m3.065s user 1m2.100s sys 0m1.252s cat test3 | wc -l 13.503.144
Es hat nur einen Hacken. Die Zeilen sind nicht wirklich unique, was man an der Anzahl an Zeilen im Result sehen kann. Ich habe leider nicht finden können warum das so ist. Die doppelten Zeilen sehen für mich gleich aus und hätten erkannt werden müssen...
Die Beste Lösung die ich finden konnte ist erst das etwas unsaubere aber schnelle uniq, gefolgt von einem sort -u.
$ time cat netdomains2 | uniq | sort -u > test4 real 1m16.216s user 1m15.137s sys 0m1.284s $ cat test4 | wc -l 13.502.688
Dies läuft immer noch schneller als ein reines sort -u und liefert die gewünschte Anzahl an Zeilen. Hier nochmal alles zusammen und immerhin 41 Sekunden schneller. Beim .com Zone File spart das zusätzliche uniq 5 Minuten 50 Sekunden ein.
$ time cat net.zone | \
awk 'NR > 43' | \
awk 'split($1, x, / /) {print x[1]}' | \
grep -v '\.' | \
uniq | sed '$d' | \
sort -u > netdomains
real 1m45.617s
user 2m4.732s
sys 0m3.944s
*Update*: Uniq und sort zusammen zu verwenden ist leider doch nicht die beste Lösung. Irgend wie werden Zeilen "verschluckt"... Sort -u macht auch was es will und sortiert die Listen nichts immer gleich. Das wiederum gefällt dem diff aber nicht und macht es unbenutzbar. Die Lösung war dann ganz einfach. Vor dem sort Aufruf setzt man die Locale neu, was die Ausführungszeit verringert und das Gewünschte Ergebnis liefert (denke ich jedenfalls, die letzten 4 Tage funktioniert alles wie es soll).
$ export LC_ALL=C $ time cat netdomains2 | sort -u > test5 real 0m32.880s user 0m30.830s sys 0m1.012s
und nochmal alles zusammen:
$ export LC_ALL=C
$ time cat net.zone | \
awk 'NR > 43' | \
awk 'split($1, x, / /) {print x[1]}' | \
grep -v '\.' | \
sed '$d' | \
sort -u > netdomains
real 1m44.563s
user 1m39.434s
sys 0m9.677s
Teil 2: Neue und gelöschte Domains finden
In netdomains hat man nun alle Domainnamen unique und sortiert und man kann sie mit der Datei vom gestriegen Tage vergleichen. Zur Verdeutlichung heißen die Dateien jetzt gestern und heute.
$ time diff gestern heute | grep '^[<>]' > change real 0m5.597s user 0m5.068s sys 0m0.528s $ cat change | wc -l 42.045
Das Resultat ist schon sehr gut (< fehlt in heute, ist also gelöscht worden, > fehlt in gestern, ist also neu). Jetzt muss man es nur noch in neu und entfernt teilen.
$ cat change | grep '^<' | awk 'split($2, x, / /) {print x[1]}' > entfernt
$ cat entfernt | wc -l
19.241
$ cat change | grep '^>' | awk 'split($2, x, / /) {print x[1]}' > neu
$ cat neu | wc -l
22.804
Teil 3: Resultate in MySQL importieren
Abschließend möchte ich die Daten noch in eine MySQL Datenbank schreiben. Dafür bietet sich LOAD DATA INFILE an, da es sehr schnell ist. Als Beispiel benutze ich die unique und sortierte Liste mit immerhin 13 Millionen Einträgen.
# die Tabelle net in tmp hat nur 1 Feld und keine Keys $ time mysql -e "LOAD DATA LOCAL INFILE './heute' INTO TABLE net" tmp real 0m4.551s user 0m0.032s sys 0m0.076s
Hat man einen Key auf der Tabelle, dann kann sich ein REPAIR TABLE lohnen, da dieser danach sehr viel kleiner wird.
Fazit
Wenn man die Befehle nun alle in ein Script Packt, erreicht man das gewünschte Ergebnis.
2 Kommentare
Christian
schrieb am 05.07.2011 um 22:42 Uhr
Hast du zufällig ein Script fertig, welches den Downloadprozess und evtl. auch schon das parsen automatisch durchführt?
Ich scheitere irgendwie gerade daran die Dateien automatisch herunterzuladen, weil er immer die Verbindung abbricht. Hab es schon mit wget und curlftpfs + rsync versucht und drehe langsam echt durch weil es nicht funktioniert
kostaki
schrieb am 06.07.2011 um 07:54 Uhr
Ja die Probleme habe ich auch… Immer bei info und org, alles andere funktioniert normal.
Ich benutze ncftpget, setze hier einen Timeout von 45 Sekunden und rufe es einfach mehrmals auf mit einem sleep dazwischen. Ist die Datei nicht vollständig, lädt er weiter. Ist die Datei komplett, überspringt er den Download. Läuft seit gut 6 Tagen problemlos.