Wróć do bloga

Stabilność zbierania danych na dużą skalę: problemy ujawniające się dopiero po skalowaniu

Zadanie może działać stabilnie dla dziesięciu celów, a przy tysiącach tracić niezawodność. Kluczowe stają się klasyfikacja błędów i deduplikacja, limity tempa i współbieżność, wznawianie, awarie wyjść sieciowych, kontrola spójności oraz kilka podstawowych metryk.

Skrypt zbierający dane może działać bez problemu dla dziesięciu celów, a po rozszerzeniu do tysięcy zacząć tracić skuteczność. Dodajesz ponowienia, zmieniasz proxy, regulujesz współbieżność, lecz problemy wracają. Przy dokładniejszej analizie okazuje się, że wąskie gardło często nie leży w logice parsowania, ale w brakujących warstwach inżynieryjnych. Przy małej skali takie problemy mogą się w ogóle nie ujawnić.

Najpierw klasyfikuj błędy, aby ponowienia miały sens

Błędy w zbieraniu danych są nieuniknione. Kluczowe jest ich rozróżnienie: wahania sieci i zerwania połączenia można ponowić od razu; przy tymczasowym ograniczeniu tempa trzeba zastosować backoff; jeśli zmiana struktury strony powoduje pusty wynik parsowania, nawet dziesięć tysięcy prób nie pomoże — trzeba to zapisać i zgłosić alert; jeśli cel nie istnieje, wystarczy oznaczyć zadanie jako zakończone; jeśli środowisko lub wyjście sieciowe nie może się uruchomić, należy przełączyć się na inne i spróbować ponownie.

Ponawianie wszystkiego bez rozróżnienia to jeden z najczęstszych błędów. Ukrywa w pętli problemy wymagające interwencji człowieka, a jednocześnie niepotrzebnie zużywa limity i zasoby wyjściowe. Backoff też jest konieczny: odstępy między próbami powinny rosnąć, bo inaczej cały pakiet zadań wróci w tym samym oknie czasowym i jeszcze bardziej nasili ograniczenia.

Ponowienia prowadzą bezpośrednio do deduplikacji. Zadanie może zostać wykonane wiele razy, dlatego każde powinno mieć stabilny, unikalny identyfikator — na przykład wartość po normalizacji URL — a zapis do bazy powinien być idempotentny względem tego identyfikatora. W przeciwnym razie więcej ponowień oznacza więcej zanieczyszczonych danych.

Ograniczanie tempa i współbieżność to dwie różne rzeczy

Zwiększenie współbieżności nie gwarantuje większej przepustowości. Jednocześnie działają trzy ograniczenia: ile wytrzyma witryna docelowa, zanim rate limiting obniży łączną przepustowość, pamięć i CPU lokalnej maszyny oraz to, czy pojedyncze środowisko lub sesja może równocześnie uruchamiać wiele zadań.

Stabilniejsze podejście polega na rozpoczęciu od niskiej współbieżności i stopniowym zwiększaniu obciążenia, przy jednoczesnym obserwowaniu skuteczności i czasu odpowiedzi, aby znaleźć punkt wyraźnego pogorszenia. Ograniczanie tempa to osobny mechanizm: kontroluje rytm dostępu do tego samego celu i nie jest tym samym co globalna współbieżność. Gdy partia zadań trafia do wielu witryn, każda z nich powinna mieć własne tempo.

Wznawianie wymaga trwałego stanu

Przy zadaniu działającym przez kilka godzin przerwa jest czymś normalnym; start od początku bywa zbyt kosztowny. Warunkiem jest trwałe zapisanie stanu: oczekujące, w toku, zakończone, a także liczby ponowień, najbliższego dozwolonego czasu wykonania i typu błędu. Po uruchomieniu proces powinien odtworzyć kolejkę z magazynu danych, zamiast budować ją ponownie z pamięci.

Utrzymywanie kolejki wyłącznie w pamięci to bardzo częsta implementacja, która pozornie działa. Gdy proces się zatrzyma, wszystkie oczekujące zadania znikają i przestają zgadzać się rozliczenia.

Osobno obsługuj awarie proxy i wyjść sieciowych

Blokowanie wyjścia przez cel, utrata proxy czy zmiany węzłów regionalnych będą przy dużej skali występować stale. To nie są wyjątki, lecz normalne warunki pracy. Traktuj wyjścia jako zasoby wymienne: gdy zadanie kończy się błędem, najpierw ustal, czy cel ogranicza tempo, czy wyjście jest niedostępne; w pierwszym przypadku zastosuj backoff, w drugim zmień wyjście i ponów zadanie. Rejestruj też współczynnik awarii każdego wyjścia i wycofuj grupy, które wyraźnie się pogarszają.

Jeśli natomiast wszystkie zadania korzystają z jednego wyjścia, pojedyncze zadanie może przeciążyć ścieżkę i wpłynąć na wszystko, co nastąpi później. Diagnostyka wymaga wtedy cofania się po logach, aby znaleźć zadanie, które wywołało problem.

Kontrola spójności danych

Pomyślne wykonanie nie oznacza jeszcze poprawnych danych. Po zapisie trzeba umieć odpowiedzieć na kilka pytań: czy liczba zakończonych zadań zgadza się z liczbą zapisanych wierszy, jaki odsetek wyników parsowania jest pusty, czy udział brakujących pól krytycznych nie wzrósł nienaturalnie i ile jest duplikatów?

Takie kontrole nie muszą być złożone. Wystarczy próbkowanie według partii, ale ktoś musi analizować wyniki. Przy dużej skali błędne dane mogą być większym problemem niż brak danych.

Które metryki monitorować

Nie trzeba śledzić zbyt wielu metryk. Wystarczy kilka pokazujących stan systemu.

  • Skuteczność i rozkład typów błędów, aby zobaczyć, które problemy narastają
  • Długość kolejki zadań i średni czas oczekiwania; stale rosnące zaległości oznaczają niedopasowanie napływu do możliwości przetwarzania
  • Liczba aktywnych środowisk i powiązanych procesów; długotrwały wzrost w jednym kierunku często wskazuje na wyciek przy zwalnianiu zasobów
  • Wynik na jednostkę czasu, aby ocenić, czy rate limiting tłumi przepustowość
  • Współczynnik awarii wyjść, aby zdecydować, czy wymienić grupę węzłów

Jeśli choć jedna z tych metryk przez dłuższy czas zmienia się tylko w jednym kierunku, najpierw sprawdź zwalnianie zasobów i logikę ponowień.

Wydziel warstwę środowiska

Wszystkie te kwestie prowadzą do tego samego wniosku: warstwa środowiska powinna być zarządzana niezależnie od skryptów. Pula środowisk wymaga centralnego harmonogramowania zamiast rozproszenia ich po poszczególnych skryptach; zwalnianie zasobów wymaga stanu możliwego do odczytu zamiast liczenia na mechanizmy awaryjne w skryptach; ponowienie z innym środowiskiem lub wyjściem działa tylko wtedy, gdy środowiska mogą być planowane niezależnie.

Skrypty zajmują się logiką, a warstwa środowiska zasobami i tożsamością. W takiej architekturze PurpleMark pełni tę rolę, udostępniając zasoby środowisk, które można tworzyć seryjnie, wiązać z niezależnymi wyjściami sieciowymi i odpytywać o status.

Granice zgodności

Możliwość skalowania nie oznacza dowolności w zbieraniu danych. Przestrzegaj reguł robots i warunków korzystania z witryny docelowej, nie zbieraj danych osobowych, nie obchodź technicznych zabezpieczeń i kontroluj częstotliwość żądań tak, aby nie zakłócać normalnego działania usługi. Stabilność to problem techniczny, a dopuszczalność zbierania danych to osobna kwestia. Oba warunki muszą być spełnione.