Înapoi la blog

Stabilitatea colectării de date la scară mare: probleme care apar abia după scalare

O sarcină poate funcționa bine pe zece ținte și își poate pierde fiabilitatea la mii. Clasificarea erorilor și deduplicarea, limitarea ratei și concurența, reluarea, defectarea ieșirilor de rețea, verificarea consistenței și câteva metrici cheie devin critice la scară mare.

Un script de colectare poate rula fără probleme pe zece ținte și poate începe să piardă din rata de succes când este extins la mii. Adaugi reîncercări, schimbi proxy-uri, reglezi concurența, dar problemele reapar. La o analiză mai atentă, blocajul nu este adesea în logica de parsare, ci în câteva straturi de inginerie care lipsesc. La scară mică, aceste probleme pot să nu apară deloc.

Clasifică mai întâi erorile, pentru ca reîncercările să aibă sens

Eșecurile sunt inevitabile în colectarea datelor. Important este să le clasifici: fluctuațiile de rețea și resetările de conexiune pot fi reîncercate imediat; o limitare temporară a ratei cere backoff înainte de o nouă încercare; dacă o schimbare în structura paginii produce rezultate de parsare goale, nici zece mii de reîncercări nu ajută, deci cazul trebuie înregistrat și semnalat; dacă ținta nu există, marchezi sarcina ca finalizată; dacă un mediu sau o ieșire de rețea nu pornește, schimbi resursa și încerci din nou.

Reîncercarea tuturor cazurilor fără diferențiere este una dintre cele mai ușoare greșeli. Ea ascunde în bucle probleme care necesită intervenție umană și consumă inutil cote și ieșiri. Este necesar și backoff-ul: intervalul dintre reîncercări trebuie să crească, altfel un lot întreg va reveni în aceeași fereastră de timp și va agrava limitarea.

Reîncercările duc direct la deduplicare. O sarcină poate fi executată de mai multe ori, astfel că fiecare sarcină are nevoie de un identificator unic și stabil — de exemplu, valoarea după normalizarea URL-ului — iar scrierile în baza de date trebuie să fie idempotente după acel identificator. Altfel, mai multe reîncercări înseamnă mai multe date murdare.

Limitarea ratei și concurența sunt lucruri diferite

Creșterea concurenței nu garantează creșterea throughput-ului. Trei constrângeri acționează simultan: cât poate suporta site-ul țintă înainte ca limitarea să reducă throughput-ul total, memoria și CPU-ul mașinii locale și dacă un singur mediu sau o singură sesiune poate executa mai multe sarcini în paralel.

O abordare mai stabilă este să începi cu concurență redusă și să crești treptat sarcina, urmărind împreună rata de succes și timpul de răspuns pentru a identifica punctul în care performanța se deteriorează clar. Limitarea ratei este separată: controlează ritmul accesului la aceeași țintă și nu este același lucru cu concurența globală. Când un lot distribuie sarcini către mai multe site-uri, fiecare site are nevoie de propriul ritm.

Reluarea depinde de persistența stării

Pentru o sarcină care rulează ore întregi, o întrerupere este normală; reluarea de la zero este adesea prea costisitoare. Condiția este ca starea să fie salvată persistent: în așteptare, în execuție, finalizată, plus numărul de reîncercări, următorul moment permis de execuție și tipul erorii. La pornirea procesului, coada trebuie restaurată din stocare, nu reconstruită din memorie.

Menținerea cozii doar în memorie este o implementare foarte comună care pare să funcționeze. Când procesul cade, toate sarcinile aflate în așteptare dispar și evidențele nu mai corespund.

Tratează separat defecțiunile proxy-urilor și ale ieșirilor de rețea

Blocarea unei ieșiri de către țintă, căderea unui proxy sau deriva unui nod regional vor apărea constant la scară mare. Nu sunt excepții, ci condiții obișnuite. Tratează ieșirile ca resurse înlocuibile: când o sarcină eșuează, stabilește mai întâi dacă ținta aplică limitare sau dacă ieșirea este indisponibilă; folosește backoff în primul caz, iar în al doilea schimbă ieșirea și reîncearcă. Înregistrează și rata de eșec a fiecărei ieșiri și elimină grupurile care se degradează evident.

În schimb, dacă toate sarcinile folosesc aceeași ieșire, o singură sarcină poate afecta calea și toate sarcinile următoare. Pentru depanare va trebui apoi să parcurgi logurile înapoi ca să identifici sarcina care a provocat problema.

Verificarea consistenței datelor

O execuție reușită nu înseamnă că datele sunt corecte. După salvare trebuie să poți răspunde la câteva întrebări: numărul sarcinilor finalizate corespunde numărului de rânduri salvate, ce proporție din rezultatele de parsare este goală, rata câmpurilor critice lipsă a crescut anormal și câte rânduri duplicate există?

Aceste verificări nu trebuie să fie complicate. Eșantionarea pe loturi este suficientă, dar cineva trebuie să urmărească rezultatele. La scară mare, datele greșite pot fi mai problematice decât lipsa datelor.

Ce metrici merită urmărite

Nu este nevoie de prea multe metrici. Sunt suficiente câteva care reflectă sănătatea sistemului.

  • Rata de succes și distribuția tipurilor de erori, pentru a vedea ce probleme cresc
  • Lungimea cozii și timpul mediu de așteptare; un backlog care crește continuu indică un dezechilibru între intrare și capacitatea de procesare
  • Numărul de medii active și de procese asociate; creșterea îndelungată într-o singură direcție indică adesea scurgeri în eliberarea resurselor
  • Producția pe unitate de timp, pentru a stabili dacă limitarea ratei reduce throughput-ul
  • Rata de eșec a ieșirilor, pentru a decide dacă trebuie schimbat un grup de noduri

Dacă oricare dintre aceste metrici continuă mult timp să se deplaseze într-o singură direcție, verifică mai întâi eliberarea resurselor și logica de reîncercare.

Separă stratul de mediu

Privite împreună, aceste probleme duc la aceeași concluzie: stratul de mediu trebuie administrat separat de scripturi. Pooling-ul mediilor cere planificare centralizată, nu medii împrăștiate prin scripturi; eliberarea resurselor cere o stare ce poate fi interogată, nu mecanisme de salvare proprii fiecărui script; reîncercarea cu alt mediu sau altă ieșire funcționează doar dacă mediile pot fi planificate independent.

Scripturile gestionează logica, iar stratul de mediu gestionează resursele și identitatea. Într-o astfel de arhitectură, PurpleMark acoperă acest strat, oferind resurse de mediu care pot fi create în loturi, asociate cu ieșiri de rețea independente și interogate după stare.

Limite de conformitate

Capacitatea de a scala nu înseamnă că datele pot fi colectate arbitrar. Respectă regulile robots și termenii de utilizare ai site-ului țintă, nu colecta informații personale, nu ocoli măsurile tehnice de protecție și controlează frecvența cererilor pentru a nu afecta funcționarea normală a serviciului. Stabilitatea este o problemă tehnică; dacă ai voie să colectezi este o altă problemă. Ambele condiții trebuie îndeplinite.