Costruire una pipeline di analytics antifrode in tempo reale
Panoramica dell'architettura: ingestione di 50K eventi/secondo, arricchimento con smart signals e scoring del rischio in meno di 10ms usando il nostro motore di streaming.
Elaborare 50.000 eventi di fingerprint al secondo, arricchire ciascuno con smart signals e restituire un punteggio di rischio in meno di 10 millisecondi richiede un'architettura di streaming progettata con cura. Questo articolo percorre la nostra pipeline dall'ingestione alla decisione.
Livello di ingestione
Gli eventi arrivano come richieste HTTPS POST dal nostro agente JavaScript in esecuzione nei browser dei visitatori. Ogni evento contiene il payload cifrato dei segnali — tipicamente 8-12KB di dati compressi che coprono 130+ segnali del browser. I nostri server edge terminano il TLS, validano la firma della richiesta e inoltrano il payload alla pipeline di elaborazione.
Usiamo un deployment multi-regione in cui i server edge sono colocati con i nodi CDN dei nostri clienti. Questo mantiene il round-trip di rete sotto i 20ms per il 95% delle richieste a livello globale. I server edge sono servizi Go senza stato in esecuzione dietro un load balancer, che scalano orizzontalmente in base al volume di richieste.
Estrazione dei segnali
Il primo stadio di elaborazione decifra e analizza il payload dei segnali. Ogni segnale viene estratto, validato e tipizzato. Gli hash canvas sono verificati rispetto a valori noti come impossibili (che indicano blocco o falsificazione del canvas). I parametri WebGL sono validati in modo incrociato per coerenza. Le proprietà navigator sono controllate rispetto a combinazioni valide note.
Questo stadio esegue anche la normalizzazione dei segnali. Le stringhe user agent vengono analizzate in componenti strutturati (browser, versione, OS, dispositivo). Le dimensioni dello schermo vengono normalizzate per tenere conto dello scaling DPI. Gli offset del fuso orario vengono validati rispetto ai dati di geolocalizzazione dell'IP.
Arricchimento Smart Signals
I segnali estratti vengono poi arricchiti con l'analisi Smart Signals — il nostro livello di intelligence lato server. Questo include il rilevamento di incognito (confronto dei pattern dei segnali rispetto a firme note di navigazione privata), il rilevamento di VPN (correlazione incrociata dei dati IP con i segnali di fuso orario e locale), il rilevamento della manomissione del browser (identificazione di incoerenze che indicano la falsificazione dei segnali) e il rilevamento di macchine virtuali (riconoscimento di profili hardware associati a VMware, VirtualBox e VM cloud).
Ogni smart signal viene calcolato in modo indipendente e produce sia un risultato booleano sia un punteggio di confidenza. Lo stadio di arricchimento aggiunge 24 segnali aggiuntivi a ciascun evento, fornendo una valutazione della minaccia completa che va oltre ciò che la sola raccolta lato client può ottenere.
Motore di scoring del rischio
L'evento arricchito viene passato al nostro motore di scoring del rischio — un modello ad albero decisionale con gradient boosting addestrato su milioni di eventi etichettati. Il modello considera tutti i 130+ segnali grezzi, i 24 smart signals e diverse feature derivate: metriche di velocità (quanti eventi da questo dispositivo negli ultimi 5 minuti, 1 ora e 24 ore), pattern comportamentali storici e punteggi di reputazione di rete.
Il modello produce un punteggio di rischio tra 0 e 100, insieme ai principali fattori contribuenti. Un punteggio di 85, per esempio, potrebbe essere accompagnato da fattori come «VPN rilevata», «modalità incognito» e «velocità elevata — 47 eventi in 5 minuti». Questa spiegabilità è critica per gli analisti antifrode che devono capire perché un particolare evento è stato segnalato.
Livello di storage e query
Tutti gli eventi vengono persistiti su ClickHouse — un database colonnare ottimizzato per query analitiche su grandi dataset. ClickHouse gestisce il nostro volume di scrittura (50K eventi/secondo) senza battere ciglio, e il suo storage colonnare abilita query analitiche in meno di un secondo su miliardi di righe.
Usiamo una strategia di retention multi-livello. I dati caldi (ultimi 7 giorni) sono archiviati su SSD NVMe per una risposta alle query in meno di 100ms. I dati tiepidi (7-90 giorni) sono su SSD standard. I dati freddi (90+ giorni) sono compressi e spostati su object storage, interrogabili ma con latenza più alta.
Kafka come spina dorsale
Apache Kafka tiene insieme la pipeline. Ogni stadio legge da e scrive su topic Kafka. Il livello di ingestione scrive gli eventi grezzi. Lo stadio di estrazione dei segnali legge gli eventi grezzi e scrive gli eventi estratti. Lo stadio di arricchimento Smart Signals legge gli eventi estratti e scrive gli eventi arricchiti. Il motore di scoring del rischio legge gli eventi arricchiti e scrive gli eventi valutati.
Questa architettura offre diversi vantaggi: gli stadi possono essere scalati in modo indipendente, i guasti in uno stadio non influenzano gli altri, e possiamo rieseguire gli eventi attraverso qualsiasi stadio per debug o rielaborazione. I consumer group di Kafka abilitano l'elaborazione parallela all'interno di ogni stadio, e la sua semantica exactly-once garantisce che nessun evento venga elaborato due volte o perso.
Budget di latenza
Il nostro obiettivo di latenza end-to-end è 10ms dal momento in cui il payload di segnali arricchito arriva alla pipeline di elaborazione al momento in cui il punteggio di rischio viene restituito. Ecco come si scompone il budget: l'estrazione dei segnali richiede 1-2ms, l'arricchimento Smart Signals richiede 3-4ms, lo scoring del rischio richiede 2-3ms, e la serializzazione e risposta richiede 1-2ms. Il salto Kafka tra gli stadi aggiunge meno di 1ms nel nostro deployment colocato.
Rispettare questo budget in modo costante a 50K eventi/secondo richiede un'ottimizzazione attenta a ogni stadio. Usiamo pool di memoria pre-allocati, serializzazione zero-copy e scritture ClickHouse in batch. Il modello di scoring del rischio è compilato in codice nativo usando ONNX Runtime, eliminando l'overhead dell'interprete Python.
Mark ha passato due settimane a profilare la pipeline prima di trovare il collo di bottiglia nel nostro livello di lookup distribuito — un singolo mutex serializzava i lookup su tutte le goroutine. Dopo il passaggio a un design a lock sharded, il p99 è sceso da 48ms a 9ms. A volte la soluzione è imbarazzantemente semplice, una volta che la si trova.