de Marcello Lins

Cum am construit un crawler web fără server pentru a obține la scară largă datele imobiliare din Vancouver

Cum am construit un crawler web fara server pentru a

Recent, m-am mutat din Rio de Janeiro, Brazilia, în Vancouver, Canada. Primul lucru care te lovește chiar în față, în afară de peisajul frumos, sunt prețurile de închiriere. Vancouver este în prezent clasat printre primele 5 cele mai scumpe orașe să trăiască în lume. Prețul de închiriere al unei proprietăți indică cum scump este deținerea și ipotecarea efectivă a aceleiași proprietăți.

Am decis să încep un proiect secundar care să poată obține un număr decent de listări de locuințe și să rezolve datele. Am vrut să vin cu propriile mele concluzii despre piața reală actuală din Vancouver. Există o grămadă de date bine formatate care trăiesc pe aceste site-uri web de listare de pe web, deci de ce să nu mergeți mai departe și să le luați? Așa s-a născut acest proiect.

Acest articol vă va arăta prin arhitectură, costuri, argumente pro și contra și multe altele despre primul crawler pe care l-am construit fără a folosi deloc servere. Trăiește 100% pe cloud, folosind doar AWS (Amazon Web Services).

Așteptați, ați spus „Fără server”?

Destul de sigur, tot ce rulezi pe cloud, este salvat de servere la sfârșitul zilei. Ceea ce am vrut să spun prin Server-less este că nu va trebui să întrețineți de fapt niciun server sau mașină virtuală.

Trucul este să vă construiți arhitectura în jurul unor servicii native în cloud, cum ar fi AWS Lambda, DynamoDB, RDS MySQL și Cloudwatch. Apoi, faceți-i să lucreze împreună într-un mod inteligent.

Putem incepe?

Arhitectura proiectului

1611314710 754 Cum am construit un crawler web fara server pentru a

În cazul în care nu sunteți familiarizați cu aceste servicii, le voi rezuma pentru dvs.:

  • AWS Lambda:
    Funcții de scurtă durată care rulează pe cloud
    Ori de câte ori acestea sunt invocate sau declanșate, acestea se vor întoarce, vor rula codul pe care l-ați scris în el și se vor opri de îndată ce rulează. Veți plăti doar pentru câteva secunde în care fiecare funcție face ceva.
  • DynamoDB:
    Baza de date NoSQL complet gestionată pe cloud
    Puteți să-l alimentați cu înregistrări JSON și acestea vor fi stocate pe un server pe care nu va trebui să îl întrețineți. Puteți scala capacitatea de citire și scriere în câteva secunde. De la începutul anului 2017, au început să sprijine un TTL Mecanismul (Time To Live). Acest lucru permite ca obiectele dvs. să fie șterse automat după atingerea TTL-ului său.
  • RDS MySQL:
    Baza de date MySQL RDS (Relational Database Service) complet gestionată
    Scăriți în sus sau în jos, faceți copii de rezervă după cum doriți. Recent am anunțat un nou Porniți și opriți caracteristică. Vă permite să vă păstrați instanța oprită timp de până la 7 zile la rând. Plătiți doar pentru volumul instanței, în loc să plătiți și pentru orele instanței sale.
  • CloudWatch:
    Monitorizează și înregistrează resursele pe cloud
    Obțineți acest lucru gratuit, deoarece fiecare mesaj „.log” rulat de la Python pe Lambda îl înregistrează direct într-un flux CloudWatch.

Obiective de proiect

Când am început acest proiect, am avut în vedere câteva obiective. Apoi am început să improvizez pe măsură ce mergeam. Proiectul ideal pentru mine ar trebui să:

  • Fiți complet gestionat de AWS pe cloud și nu aveți nevoie de server
  • Fii elastic pentru a ridica în sus și în jos în funcție de sarcină
  • Capabil să proceseze zeci de mii de înregistrări pentru început
  • Fii ieftin

Defalcarea costurilor

Vă puteți baza pe Lambda și CloudWatch pentru acest proiect. Sunt gratuite, cu excepția cazului în care rulați acest lucru în mod constant și non-stop. Atunci va veni factura.

Pentru straturile de stocare din DynamoDB și RDS MySQL veți plăti sub 3 dolari pe lună. Puteți opri baza de date RDS timp de până la 7 zile la rând. Și vă puteți scala tabelele DynamoDB la 1 unitate de citire + 1 scriere atunci când nu le utilizați.

Aceasta duce la costurile totale la o estimare de 2,40 USD pe lună. Verifica documentația mea pentru o defalcare mai detaliată.

Calatoria

De la început până la sfârșit întregul proiect mi-a luat aproximativ 19 ore de muncă. Kilometrajul dvs. poate varia în funcție de cunoștințele dvs. anterioare despre AWS și Python. Cunosc ambele, dar nu serviciile Dynamo și Lambda.

Configurarea funcțiilor Lambda necesită timp pentru a vă obișnui. Este cu siguranță sub-egal cu alte servicii AWS atunci când vine vorba de utilizare și valori.

Odată ce te-ai obișnuit cu întregul dans Lambda dezvoltând: edit Python files locally – & gt; create a .zip packvârstă -> upload pentru a înlocui funcțiile Lambdaon -> Save și Test, devine mai bun.

Integrarea cu CloudWatch este cu siguranță un plus. Este gratuit și vine la îndemână atunci când încercați să înțelegeți de ce lambda dvs. a eșuat după solicitarea HTTP respectivă sau în timpul acelei bucle ați uitat să indentați.

Folosind variabile de mediu, ajustarea resurselor funcției și a expirărilor și activarea și dezactivarea declanșatoarelor pentru testare funcționează fără probleme și se integrează foarte bine. Nu necesită redistribuirea funcțiilor. De asemenea, am observat că spin-up-ul funcțiilor Lambda funcționează rapid, având întârzieri aproape neobservabile. Presupun că folosesc un fel de smart-cache ECS sub capotă, dar nu aș ști.

Configurarea tabelelor DynamoDB nu ar putea fi mai ușoară. Vorbim despre o configurare promptă, în care trebuie doar să completați 2 casete, numele tabelului și cheia de partiție pentru tabelul dvs. Configurarea TTL pentru fiecare tabel funcționează bine. Dar nu puteți face și anula des. Vă va împiedica să îl activați și să îl dezactivați, deoarece vă șterge înregistrările fără să vă taxeze pentru aceste operațiuni. Inserarea manuală a înregistrărilor dynamoDB pe fiecare tabel în scopul testării funcționează perfect. Fiecare inserție sau lot declanșează funcțiile lambda cu puțin sau deloc. Ajustarea capacității fiecărui tabel în sus și în jos cu unități de citire și scriere este o briză. Vă permite să le reglați cu doar câteva secunde de întârziere pentru a aplica noua configurație.

Configurarea RDS MySQL este cu siguranță mai ușoară decât Lambda, dar are mai mulți pași decât DynamoDB. De asemenea, veți obține mai multe opțiuni. Puteți alege tipul de instanță, dimensiunile și tipurile volumului, redundanța, ferestrele de întreținere și perioadele de păstrare a copiilor de rezervă. Odată ce ați configurat-o, veți avea instanța MySQL strălucitoare în aproximativ 10 minute, gata de rock.

După încheierea fazei de configurare și testare, am avut un moment de contemplare, pe măsură ce listările își îndreptau calea către MySQL. Aș putea să mă așez, să mă relaxez și să beau o bere în timp ce capturarea se întâmpla. Sau 3 beri. Trage un pui de somn? Chestia asta e lentă!

Margini abrazive

Performanța nu a fost niciodată scopul meu. Ne-am gândit la tehnologiile disponibile și a construi ceva interesant. Dar nu mă așteptam să fie atât de lent. În cele din urmă, a reușit să capteze aproximativ 11.000 de înregistrări la fiecare 6 ore, ceea ce se traduce prin aproximativ o listare la fiecare ~ 2 secunde. Am scris crawlerele distribuite cu tarife ușor de treizeci de ori mai rapide decât aceasta. Poate că nu au fost la fel de incitante.

Fiecare solicitare HTTP pentru o pagină durează între 0,7 și 1,1 secunde pentru a reveni în medie. Factorul în timpul necesar pentru a învârti fiecare container lambda, plus conectarea la MySQL prin fir și introducerea fiecărei înregistrări, aveți 2 secunde. Fiecare lambda primește un lot sau un flux de 5 înregistrări DynamoDB. Durata medie de viață a fiecărei funcții lambda a fost de aproximativ 7 secunde pentru lambda de analiză.

Câteva optimizări care ar putea fi făcute ar fi efectuarea cererilor HTTP pentru fiecare lot în paralel și efectuarea inserțiilor de lot în MySQL.

Vorbind de paralelism, cea mai rece găleată de apă pentru mine a fost faptul că Lambda nu va escalada foarte bine orizontal.. În capul meu, fiecare flux introdus în Dynamo ar declanșa imediat o funcție lambda pentru al procesa. Acest lucru a însemnat că Lambda va fi mereu la curent cu ritmul inserțiilor pe Dynamo. Deci, aș avea zeci de funcții Lambda care rulează la un moment dat, toate în paralel și frumoase. am gresit.

Ceea ce se întâmplă de fapt este că Lambda are o limită de execuții concurente asta este legat de câte cioburi are masa DynamoDB. Deoarece masa mea avea un singur fragment, exista o singură funcție Lambda care rulează în orice moment. Ceea ce s-a întâmplat este că, deși inserțiile de pe unul din tabelul dynamoDB au durat câteva minute, al doilea strat de Lambda a fost declanșat încet, unul după altul. A existat o coadă internă care îmi stoca fluxurile dinamo și le alimenta către Lambda serializând execuția mea în loc să o paralelizez.

Fiecare modificare a conținutului unei mese DynamoDB va declanșa funcțiile Lambda setate să se declanșeze. Problema este că este posibil ca aceste modificări să nu fie doar Inserts, ci și actualizări, iar unele ștergeri se declanșează atunci când colectorul TTL intră și începe să șteargă înregistrările set-to-expire. Din fericire, fiecare flux DynamoDB conține pentru fiecare înregistrare din flux, un atribut pe care îl puteți utiliza pentru a spune dacă acel obiect a fost inserat, actualizat sau șters. Primeam totul pentru că nu există nicio modalitate de a seta Lambda altfel, ci doar de procesare a inserțiilor.

Argumente pro şi contra

Pro:

  • Ieftin
  • Complet gestionat / fără server
  • Tehnologie Bleeding-Edge
  • Infrastructură flexibilă
  • Dacă găsiți o eroare, vă puteți schimba lambda imediat pentru a remedia fiecare lot următor

Contra:

  • Încet
  • Odată ce începe, nu îl puteți întrerupe și reporni de unde a plecat
  • Posibil de modificat doar până acum (modificări codificate)
  • Testarea pieselor specifice necesită dezactivarea și activarea constantă a declanșatoarelor Lambda

Verdictul final

În ciuda apelului inițial, nu aș recomanda această arhitectură pentru ceva care necesită performanță și flexibilitate pentru a schimba arhitectura cu ușurință și a modifica mai mult decât codul care rulează. Dar, această configurație este ieftină și pentru ceva mic, funcționează bine. Este posibil să nu fie cel mai ușor de configurat, dar odată ce ați trecut de acea parte, întreținerea este aproximativ zero.

M-am distrat scriind acest lucru și lipind toate aceste piese împreună pentru a construi acest mic Frankenstein. Aș face-o din nou. Am bifat în continuare casetele tuturor obiectivelor mele inițiale pentru acest proiect, dar da, performanța ar putea fi mai bună.

În cele din urmă, am reușit să descarc date de peste 40.000 de înregistrări executând acest proces de câteva ori. Cu asta în mână, intenționez să scriu codul pentru a rezolva aceste date, dar, deocamdată, acesta este încă un WIP.

Îți pot mulțumi doar dacă ai reușit până acum. Am pregătit un ghid despre cum să configurați-vă propriul cont AWS. Deoarece codul este sursa deschisa oricum, du-te hack!

Codul este deschis pe GitHub dacă doriți să o verificați. Articolul original a fost postat pe blogul meu. Treci pe acolo dacă vrei să vezi la ce mai lucrez.

Simțiți-vă liber să mă contactați prin orice contact de la mine pagina personală, în cazul în care aveți întrebări sau pur și simplu doriți să conversați.

Ne vedem pe urmatorul 🙂