Bullet e’ un exchange DeFi che offre perpetual, spot e lending su un’unica piattaforma, con regolamento su blockchain e self-custody degli asset. La sua infrastruttura di trading, un rollup app-specific scritto in Rust su Solana, raggiunge tempi sub-millisecondo (circa 500 microsecondi al p50 e 650 al p99). Ma la velocita’ di esecuzione crea un problema diverso: le blockchain sono macchine a stati che non conservano la storia. Per rendere interrogabili tutti gli eventi emessi dall’exchange, Bullet usa ClickHouse Cloud, e il racconto di come ci e’ arrivato e’ un caso interessante per chiunque costruisca analytics real-time.
Da Databricks a ClickHouse
Prima Bullet girava l’analytics su Databricks. L’architettura funzionava, ma c’era un disallineamento di fondo: Spark impiega dai 5 ai 30 secondi solo per avviare la JVM e pianificare una query, troppo lento per servire dati a un frontend dove gli utenti si aspettano risultati in millisecondi. La soluzione tampone era pre-calcolare i risultati ogni ora, spingerli in DynamoDB e servirli da li’. Funzionava, ma significava mantenere due sistemi e avere dati sempre vecchi di almeno un’ora. Con ClickHouse le query tornano in millisecondi, quindi Bullet ora chiama ClickHouse direttamente dal proprio API layer senza caching: il serving layer DynamoDB e’ diventato inutile.
Ingestion, deduplicazione e viste materializzate
La pipeline di ingestion parte dal sequencer del rollup: un indexer Rust ascolta un firehose di migliaia di eventi al secondo su WebSocket e li accumula in un topic Kafka su AWS MSK. Redpanda Connect classifica gli eventi e li instrada ai topic appropriati, con un feed parallelo su S3 Glacier per il disaster recovery, mentre ClickHouse Cloud consuma direttamente da quei topic scrivendo su tabelle dedicate. La pipeline e’ stata testata a carico fino a 3 milioni di transazioni al secondo senza perdita di messaggi, con gli eventi che raggiungono ClickHouse in meno di un secondo. Un pattern chiave e’ il motore ReplacingMergeTree, che risolve la deduplicazione: ogni trade ha un numero evento univoco e un hash di transazione, e ClickHouse tiene solo l’ultima versione dei record con chiavi coincidenti. Il risultato e’ una pipeline idempotente che si puo’ rieseguire e ribackfillare senza creare duplicati. Per i calcoli piu’ pesanti, come la leaderboard di P&L che prima girava come cron da 60 minuti impiegando 20-30 minuti su Databricks, Bullet usa refreshable materialized view che ricalcolano ogni 10 minuti.
I risultati
Il passaggio da Databricks a ClickHouse Cloud ha tagliato la latenza delle query da 10-15 secondi a millisecondi, un miglioramento di circa 10.000x. La freschezza dei dati e’ passata da 1-2 ore a meno di 5 secondi, con un costo mensile comparabile a quello di Databricks ma gestendo 1.000 volte piu’ dati su ambienti di staging, testnet e mainnet, oltre 150 milioni di righe l’ora. Per un team di data engineering ridotto all’osso, il vantaggio non e’ solo la velocita’ ma la minore superficie da manutenere: un unico database per ingestion, analytics e monitoring al posto di un’architettura multi-sistema fragile.
- Per l’analytics real-time servito a un frontend, i tempi di avvio di Spark rendono spesso necessario un serving layer separato che ClickHouse elimina.
- ReplacingMergeTree rende la pipeline idempotente, spostando la deduplicazione dal codice al motore di storage.
- Le refreshable materialized view sostituono i cron batch per i calcoli pesanti, portando la leaderboard da 90 minuti di ritardo a 10.
Fonte: How Bullet uses ClickHouse Cloud for real-time analytics — https://clickhouse.com/blog/bullet-real-time-analytics
Hai qualcosa da aggiungere? Unisciti alla discussione.