Scoring oszustw w czasie rzeczywistym na dużą skalę
Jak tracio.ai przetwarza 50 tys. zdarzeń na sekundę ze scoringiem poniżej 50 ms dzięki przetwarzaniu strumieniowemu, wstępnie obliczanym wektorom sygnałów i cache'owaniu na brzegu sieci.
Scoring oszustw na dużą skalę wymaga fundamentalnie innej architektury niż przetwarzanie wsadowe. Gdy autoryzowana jest płatność lub tworzone jest konto, na dostarczenie oceny ryzyka masz milisekundy — nie minuty. W tracio.ai przetwarzamy ponad 50 000 zdarzeń na sekundę przy medianie opóźnienia scoringu 22 ms. Ten artykuł wyjaśnia architekturę, która to umożliwia.
Potok scoringu
Każde napływające zdarzenie trafia do trzyetapowego potoku: wzbogacanie sygnałów, obliczanie wektora i scoring ryzyka. Wzbogacanie sygnałów dołącza do surowego zdarzenia dane device intelligence — fingerprint odwiedzającego, wyniki bot detection, IP intelligence oraz historyczne zachowanie. Obliczanie wektora przekształca te wzbogacone sygnały w wektor cech o stałej długości, zoptymalizowany pod nasz model scoringowy. Scoring ryzyka przepuszcza wektor przez nasz wytrenowany model i zwraca wynik z zakresu od 0.0 do 1.0.
Kluczową decyzją projektową jest oddzielenie wzbogacania i obliczania wektora od samego scoringu. Dane wzbogacające są obliczane wstępnie i cache'owane. Gdy odwiedzający ładuje stronę, obliczamy jego profil urządzenia i zapisujemy go w Redis z TTL wynoszącym 60 minut. Gdy nadchodzi żądanie scoringu — zwykle wyzwolone przez płatność lub logowanie — pobieramy wstępnie obliczony profil zamiast liczyć go od nowa. Skraca to opóźnienie scoringu z ponad 200 ms do poniżej 30 ms.
Przetwarzanie strumieniowe w Go
Nasza warstwa ingestii jest napisana w Go i wykorzystuje architekturę fan-out. Napływające zdarzenia trafiają przez HTTP POST i są natychmiast umieszczane w wewnętrznym kanale. Pula goroutyn roboczych czyta z tego kanału, wykonuje wzbogacanie i zapisuje wzbogacone zdarzenia do ClickHouse na potrzeby analityki oraz do kolejki scoringu dla przetwarzania w czasie rzeczywistym. Pula fan-out skaluje się dynamicznie w zależności od głębokości kolejki.
Wybraliśmy Go dla warstwy ingestii ze względu na jego doskonałe prymitywy współbieżności i przewidywalną alokację pamięci. Każda goroutyna robocza zajmuje około 4 KB przestrzeni stosu, co pozwala nam uruchamiać tysiące współbieżnych workerów na pojedynczym węźle. Pauzy garbage collectora poniżej milisekundy są kluczowe dla utrzymania spójnego opóźnienia przy wysokiej przepustowości.
Cache'owanie na brzegu sieci i wektory sygnałów
Dla naszych klientów o największym wolumenie wdrażamy modele scoringowe na brzegu sieci, korzystając ze wstępnie obliczanego cache wektorów sygnałów. Gdy urządzenie widziane jest po raz pierwszy, obliczamy jego pełny wektor sygnałów i zapisujemy go w naszym cache brzegowym (wdrożonym na Cloudflare Workers KV). Kolejne żądania scoringu dla tego samego urządzenia pobierają zbuforowany wektor i uruchamiają scoring lokalnie na brzegu sieci, osiągając opóźnienie poniżej 10 ms.
Model scoringowy na brzegu sieci to zdystylowana wersja naszego pełnego modelu — mniejsza i szybsza, ale zoptymalizowana pod te same cele dokładności. Model brzegowy trenujemy ponownie co tydzień i wdrażamy aktualizacje poprzez rolling deployment, aby uniknąć lawin unieważniania cache. Pełny model działa po stronie serwera w przypadkach, gdy pewność modelu brzegowego jest poniżej konfigurowalnego progu.
ClickHouse dla analityki
Wszystkie wzbogacone zdarzenia są przechowywane w ClickHouse, naszej kolumnowej bazie analitycznej. Kompresja i wydajność zapytań ClickHouse pozwalają nam przechowywać miliardy zdarzeń, jednocześnie obsługując analityczne zapytania w czasie rzeczywistym. Nasi klienci wykorzystują tę analitykę do zrozumienia wzorców oszustw, strojenia progów scoringu i badania pojedynczych zdarzeń.
Używamy widoków zmaterializowanych w ClickHouse do utrzymywania wstępnie zagregowanych metryk: wskaźnik oszustw według kraju, rozkład scoringu według typu urządzenia oraz wskaźniki fałszywych trafień według progu. Te widoki zmaterializowane aktualizują się w czasie rzeczywistym w miarę napływania zdarzeń, dostarczając gotowych do wyświetlenia metryk bez kosztownych zapytań agregujących.
Wyciągnięte wnioski
Budowa systemu scoringu w czasie rzeczywistym nauczyła nas kilku rzeczy. Po pierwsze, wstępne obliczanie to najważniejsza optymalizacja — każda praca, którą możesz wykonać przed nadejściem żądania scoringu, to praca, która nie obciąża twojego budżetu opóźnień. Po drugie, model współbieżności Go dobrze nadaje się do przetwarzania zdarzeń o wysokiej przepustowości, ale trzeba zachować dyscyplinę w alokacji pamięci, aby uniknąć presji na GC. Po trzecie, wdrożenie na brzegu sieci jest przełomowe dla opóźnień, ale wymaga starannego zarządzania modelem, aby uniknąć nieaktualnych predykcji.