HVORDAN VI DOWNLOADEDE INTERNETTET Man skal crawle før man kan gå
DAGSORDEN Hvem jeg er Behovet for en crawler Arkitektur Nutch og Hadoop MongoDB Udfordringer Tak for i dag
JACOB AVLUND Partner i Siblingsoft - som bl.a. gør sig i app-udvikling Har dog brugt en god del af det sidste halve år på konsulentopgaver - hvilket vi skal snakke om lige om lidt Har tidligere været ansat godt 5 år i L&B Derudover underviser jeg i en række fag på IT-universitetet - i indeværende semester er det Android-udvikling
BEHOVET FOR EN CRAWLER Eniro lever af at levere kvalificerede søgeresultater. Jo mere præcise og detaljerede søgeresultater, jo bedre. Crawlede sider er én måde at forbedre de data der ligger til grund for søgeresultaterne.
ENIRO CONTENT CRAWLER Henter data fra udvalgte web sites (primært webshops). Leverer disse data til diverse consumers: Product Identifier: leder efter mønstre der kan identificere produkter (deraf navnet). Content Information: leder efter mønstre der kan identificere stamdata. Crawler-delen selv kigger ikke kritisk på indholdet af siderne - men crawler bare alt det den kan.
ARKITEKTUR Eniro Content Crawler Consumers! Crawler Nutch + Hadoop Web interface + REST services Spring MVC!!! Product Identification (PI)!! Content Mongo Page repo MongoDB Crawl reports etc. ActiveMQ!!! Information (CI)
NUTCH Java-baseret webcrawler og Apache-projekt. Kører (som regel) på Hadoop (mere om dette senere). Crawler bredt i stedet for dybt: Fordel: bedre politeness og fordeling af ressourcer. Ulempe: hvornår ved vi at et site er crawlet færdig? Plugin-baseret - alt kan i princippet skiftes ud. Sider kan gives en score, som indikerer hvor højt de skal prioriteres når der laves fetch lists, og et fetch interval, som indikerer hvor ofte de skal gencrawles. Indeholder flere databaser, bl.a.: CrawlDB - liste over links der skal hentes. Segment DB - indhold af hentede sider.
NUTCH Vi kører Nutch i runder af ca. 2-4 timers varighed. En runde består af flg. trin: Injection - indlæs nye URLs. Generation - generer fetch lists til crawling. Fetching - hent siderne fra nettet og placer dem i Segment DB. Updating - opdater CrawlDB med links fra de hentede sider. Alle trin køres via Hadoops MapReduce (mere om dette senere). Efter hver runde flyttes de hentede data fra Segment DB til vores page repository (også mere om dette senere).
HADOOP Java-baseret Apache-framework designet til at håndtere opgaver med store datamængder. Opkaldt efter en gul tøjelefant. Oprindeligt en del af Nutch, men nu et selvstændigt projekt. To primære komponenter: Hadoop HDFS Hadoop MapReduce
HDFS Hadoop Distributed File System. Baseret på Google File System. Distribueret filsystem: Deler data op i store blokke (som regel 64+ MB). Fokus på stor fortløbende læsehastighed på bekostning af latency. Indbygget redundans. Gearet til fejlsituationer. Styres af en NameNode, som holder styr på placeringen af data på diverse DataNodes.
HDFS Klient NameNode Data Metadata DataNode DataNode DataNode
MAPREDUCE Algoritme designet til at understøtte parallellitet i databehandling. Løseligt inspireret af funktionerne map og reduce i funktionel programmering. Google var de første til at beskrive denne arkitektur i 2004.
MAPREDUCE Skridt 1: Map En task modtager input i form af key/value-par. Mapperen bearbejder input og returnerer nye key/value-par. Skridt 2: Reduce Hadoop samler alle data med samme key og sender dette til den samme reducer. Reduceren udfører den endelige bearbejdning og returnerer output. Skridt 1 1/2: Combine Nogle gange giver det mening at lave en local reduction på samme node som mapperen inden man sender data videre til en reducer på en anden node.
MAPREDUCE Hadoop leverer en JobTracker til at kontrollere processen. Denne videredelegerer opgaverne (tasks) til TaskTrackers, som afvikler dem med mappers eller reducers. Tasks vil fortrinsvis blive afviklet på DataNodes hvor de relevante data i forvejen ligger.
MAPREDUCE Input Node Node Map task Map task Map task Node Reduce task Reduce task Output
FEJL UNDERVEJS? Hvis en task fejler, så vil TaskTrackeren registrere dette og sende besked til JobTrackeren, som vil prøve at afvikle den igen - helst via en anden TaskTracker. Hvis en task fejler 5 gange, så vil den ikke blive afviklet igen. Hele jobbet vil som udgangspunkt så fejle - med mindre man eksplicit fortæller Hadoop at det er OK. Hvis en TaskTracker fejler, vil den blive fjernet fra JobTrackerens liste over brugbare TaskTrackers. Hvis mere end 4 tasks fejler på samme TaskTracker, bliver den blacklistet af JobTrackeren.
EKSEMPEL: MAPPER public class WCMapper implements Mapper<LongWritable, Text, Text, IntWritable> {! private Text word = new Text(); public void map(longwritable key, Text value, OutputCollector<Text, IntWritable> output, Reporter reporter) throws IOException { String line = (casesensitive)? value.tostring() : value.tostring().tolowercase(); StringTokenizer tokenizer = new StringTokenizer(line); while (tokenizer.hasmoretokens()) { word.set(tokenizer.nexttoken()); output.collect(word, one); } } }
EKSEMPEL: REDUCER public class WCReducer implements Reducer<Text, IntWritable, Text, IntWritable> { } public void reduce(text key, Iterator<IntWritable> values, } OutputCollector<Text, IntWritable> output, Reporter reporter) throws IOException { int sum = 0; while (values.hasnext()) { } sum += values.next().get(); output.collect(key, new IntWritable(sum));
EKSEMPEL: LIMEN public class WordCount extends Configured implements Tool { public int run(string[] args) throws Exception { JobConf conf = new JobConf(getConf(), WordCount.class); conf.setoutputkeyclass(text.class); conf.setoutputvalueclass(intwritable.class);!! } } conf.setmapperclass(wcmapper.class); conf.setcombinerclass(wcreducer.class); conf.setreducerclass(wcreducer.class); conf.setinputformat(textinputformat.class); conf.setoutputformat(textoutputformat.class); JobClient.runJob(conf); return 0; public static void main(string[] args) throws Exception { int res = ToolRunner.run(new Configuration(), new WordCount(), args); System.exit(res); }
MONGODB Dokument-baseret database ( NoSQL ). Den nok mest populære af slagsen. Gemmer data som BSON ( binær JSON ). Tilgås med JavaScript. Designet til clustering ( sharding ). Vi bruger MongoDB til vores page repository - sider hentet fra Nutchs Segment DB flyttes herover for bedre at kunne arbejde med dem.
MONGODB Vores MongoDB er sharded ( = clustered). Giver ikke redundans, men fordeler data. (Ønsker man redundans, skal man kigge på såkaldte replica sets i stedet.) Styres af mongos-processen, som deler data op i chunks og fordeler dem på de forskellige shards når de når en vis grænse. Clusterets shard key bestemmer hvordan data fordeles på de forskellige shards.
UDFORDRINGER Primære udfordringer: Performance Plads Gennemsigtighed Besværlige websites
PERFORMANCE Hadoop skal sættes korrekt op ifm. antallet af processorkerner til rådighed - da antallet af samtidige tasks på noderne er afhængigt af dette. Når man bruger MongoDB i et sharded environment, er det ekstremt vigtigt at finde en shard key der fordeler data fornuftigt mellem de forskellige shards - det tog os nogle forsøg. Alt der kan køre asynkront, bør køre asynkront! Hadoop har muligheder for at komprimere data der sender mellem noderne - forskellige algoritmer giver forskellige forhold mellem hastighed og komprimeringsgrad. Vi kører med Googles Snappy, som primært fokuserer på hastighed.
PERFORMANCE Specielle hardwarekrav: Hadoop har brug for mange kerner for at kunne processere mange tasks sideløbende på de enkelte noder. MongoDB har ikke dette behov, da kun én tråd kan skrive til databasen ad gangen. Til gengæld kræver databasen store mængder RAM til sit working set. Specielt MongoDB har stor fordel af SSD. Hadoops store blokke medvirker til at konventionelle harddiske egner sig godt til denne arkitektur.
PLADS Selv om plads er billigere end det har været, er adskillige terabytes ikke ligefrem gratis i et datacenter - og specielt ikke, hvis det også skal være hurtige drev Vi sletter data fra Nutchs Segment DB så snart de er sendt til MongoDB. Vi har med fuldt overlæg valgt ikke at bruge MongoDBs replica sets (redundans). Forskellige strategier til løbende oprydning i MongoDB overvejes p.t.: Time-To-Live Capped collections Opdeling af collections i flere databaser
GENNEMSIGTIGHED Nutch gemmer data i HDFS, og det skal hentes over til det normale filsystem før man kan studere det. Derudover er redskaberne til at hente data fra den store CrawlDB ikke overvældende gode. Generelt er det tricky at se og logge hvad der foregår i Nutch - også selv om man har kildekoden! Det er ikke altid klart hvad der crawles - og hvornår. Når der ryddes op i CrawlDB og page repo er vigtigt at disse er i sync.
BESVÆRLIGE WEBSITES Redirects til andre domæner: Løsning: test for dette og inject de nye domæner også. Session-parametre o.lign. giver mange ens sider med forskellige URLs: Løsning: brug regex-filtre til at slette de uheldige parametre ( normalisere URLs). Billeder, PDF-filer og andet ligegyldigt skrammel: Løsning: tjek response headers og ignorer visse kendte MIME-typer. Sider med æøå og andre unicode-chars: Løsning: lav en patch til Nutch. :) Uløste problemer p.t.: sites der redirecter via JavaScript, sites der kræver cookies etc.
TAK FOR JERES TID Spørgsmål?