7.8 KiB
Data ingest strategy
Cel
Zachowac niski latency dla logiki tradingowej i read-side, ale rownoczesnie miec trwala persystencje danych do UI, replayu, debugowania i analityki.
Nie robimy modelu DB-first jako jedynej sciezki
przetwarzania.
Rekomendowany model
Stosujemy dual-path:
hot pathYellowstone gRPC / Agave RPC -> consumer -> Redis / internal state -> strategy / read-sidedurable pathten sam consumer -> Postgres -> UI / Hasura / replay / debug
Opcjonalnie pozniej:
history / analytics pathconsumer lub batch exporter -> ClickHouse
Dlaczego nie DB-first
Model:
gRPC / RPC -> DB -> dopiero potem przetwarzanie
nie jest dobry jako glowna sciezka, bo:
- dodaje latency do kazdego eventu
- uzaleznia ingest od kondycji bazy
- pogarsza odpornosc calego pipeline
- zwieksza write amplification przy duzym wolumenie zdarzen
- utrudnia low-latency strategie i read-side
DB ma byc miejscem persystencji i read modelu, nie bramka przed logika runtime.
Rola Yellowstone gRPC
Yellowstone ma byc glownym zrodlem live feed:
- account updates
- tx updates
- slot updates
- program updates
Sciezka:
Yellowstone -> consumer -> hot state
oraz rownolegle:
Yellowstone -> normalization / persistence -> Postgres
Yellowstone nie powinien byc uzalezniony od tego, czy Postgres aktualnie pisze szybko.
Rola Agave RPC
RPC nie jest naturalnym feedem eventowym.
RPC powinno sluzyc glownie do:
- point reads
- bootstrapu klienta
- recovery
- getAccountInfo / getMultipleAccounts
- getHealth / getSlot
- write path dla tx, jesli nie idziemy przez TPU/Jito
RPC nie powinno byc traktowane jak glowny event stream do zrzucania wszystkiego do DB.
Rola Redis
Redis powinien byc hot state layer:
- szybki stan DLOB
- cache
- fanout wewnetrzny
- ewentualnie stream / queue dla workerow
To jest warstwa pod:
- strategy engine
- orderbook read-side
- szybkie projekcje
Nie trzymamy tam historii jako source of truth.
Rola Postgres
Postgres powinien byc durable read model:
- dane dla UI
- dane dla Hasury
- znormalizowane ticki
- pochodne tabele DLOB
- stan aplikacji
- konfiguracja
- historia operacyjna
Postgres jest dobry do:
- frontend
- dashboard
- replay lekkiego zakresu
- audyt aplikacyjny
Kiedy ClickHouse
ClickHouse dodajemy dopiero, gdy:
- wolumen raw feedu bedzie duzy
- potrzebna bedzie ciezsza analityka historyczna
- bedziemy chcieli trzymac dluzsza historie eventow i tx
Na obecnym etapie nie jest konieczny do uruchomienia runtime.
Docelowy przeplyw
mevnode_sol
Agave RPC
Yellowstone gRPC
|
v
mevnode_bot
consumer
|\
| +--> Redis -> DLOB/read-side -> strategy/workers
|
+----> Postgres -> Hasura/API -> frontend
Zasada architektoniczna
gRPC / RPCdostarcza dane do runtimeRedisutrzymuje szybki stan operacyjnyPostgresutrzymuje trwaly stan i read modelfrontendiHasuraczytaja z Postgresastrategyiworkersnie czekaja na zapis do DB, aby przetwarzac dane
Rekomendacja dla projektu
Na teraz:
Yellowstone -> consumer -> Redisconsumer -> PostgresHasura / API / UI <- Postgresstrategy / read-side <- RedisRPCzostawic do bootstrapu, point reads i write path
To daje najlepszy kompromis:
- niski latency
- odpornosc runtime
- sensowna persystencja
- dobra baza pod UI i replay
Ocena obecnego ukladu na k3s
Obecny runtime na mevnode_bot / trade-staging jest tylko
czesciowo zgodny z docelowym modelem.
Co jest zgodne
postgresjest postawiony jakoStatefulSet, wiec nadaje sie na trwały storagedlob-redisjest osobna lekka usluga i pasuje do roli cache / hot statehasuraitrade-apisiedza nadPostgresem, co jest poprawne dla durable read modelufrontendkorzysta zAPI/Hasury, a nie bezposrednio zRedis
Co nie jest zgodne
dlob-publisheridlob-servernie sa zdrowe, wiec hot path nie jest operacyjnie domknietydlob-publisherjest podpiety dogRPC, ale nie jest glownym i pewnym writerem doPostgresatrade-ingestornie ingestuje danych bezposrednio z chain source, tylko polluje dane pochodne zHasury- persistent path jest wiec dzisiaj czesciowo odwrocony:
derived view -> ingest -> Postgres- zamiast:
chain source -> normalize -> Postgres
Plan zmian
Cel koncowy
Chcemy dojsc do ukladu:
Yellowstone gRPC / Agave RPC
|
v
consumer
|\
| +--> Redis -> hot state / workers / strategy
|
+----> Postgres -> Hasura / API / frontend / replay
Etap 1. Naprawa hot path
Najpierw trzeba przywrocic dzialanie:
dlob-publisherdlob-server
Bez zdrowego publishera nie ma sensu budowac dalszej warstwy
Redis = hot state.
Zakres:
- ustabilizowac
Agave RPCiYellowstone - doprowadzic
dlob-publisherdoReady - potwierdzic, ze
Redisdostaje aktualny stan - doprowadzic
dlob-serverdoReady
Etap 2. Uczynic publisher glownym consumerem danych chain
Obecnie trade-ingestor korzysta z danych pochodnych z
Hasury.
To trzeba zmienic tak, aby glownym miejscem wejscia danych byl komponent konsumujacy:
Yellowstone gRPCAgave RPC
Rekomendacja:
- rozszerzyc
dlob-publisher - albo wydzielic nowy
market-consumer
ale w obu przypadkach komponent ma robic:
- odczyt live z
Yellowstone - wymagane point reads z
RPC - normalizacje danych
- jednoczesny zapis do
RedisiPostgresa
Etap 3. Ustalic twardy podzial rol Redis / Postgres
Redis
Do Redis trafia tylko to, co potrzebne jako szybki stan
runtime:
- latest DLOB state
- latest L2
- quick cache dla workerow
- fanout do read-side i strategii
- dane z TTL lub dane odtwarzalne
Redis nie jest source of truth.
Postgres
Do Postgresa trafia trwaly model danych:
- znormalizowane ticki
- znormalizowane snapshoty rynku
- pochodne tabele pod
Hasure - historia operacyjna
- stan aplikacji
Postgres jest source of truth dla aplikacji i UI.
Etap 4. Przebudowac worker path
Docelowy model dla workerow:
Redis inPostgres out
To znaczy:
- workery czytaja szybki stan z
Redis - licza projekcje
- zapisują wynik do
Postgresa
Dotyczy to szczegolnie:
dlob-workerdlob-depth-workerdlob-slippage-worker
Etap 5. Wygasic obecny odwrocony ingest
Obecny trade-ingestor zapisuje dane do
Postgresa na podstawie danych juz pochodnych z
Hasury.
To nie powinno byc glowna sciezka ingestu.
Mozliwe role po zmianie:
- backfill
- sanity check
- fallback
- testowy importer
Ale nie:
- glowny chain ingest
Etap 6. Utrwalic read model pod UI
Po zmianach:
Hasuraczyta tylko zPostgresatrade-apiczyta tylko zPostgresafrontendczyta przezAPI/Hasure
Frontend nie powinien zalezec od Redis.
Etap 7. Zostawic RPC w waskiej roli
Agave RPC zostawiamy do:
- bootstrapu
- point reads
- recovery
- write path dla tx
Nie robimy z RPC glownej magistrali trwałego
ingestu.
Plan wdrozenia krok po kroku
- Naprawic
dlob-publisheridlob-server. - Potwierdzic, ze
Redisjest zasilany poprawnym hot state. - Rozszerzyc publisher albo dodac nowy consumer tak, aby pisal
rownolegle do:
RedisPostgresa
- Zdefiniowac schemat tabel normalized data w
Postgresie. - Przepiac workery na model:
- read z
Redis - write do
Postgresa
- read z
- Zostawic
Hasureitrade-apijako warstwe odczytowa nadPostgresem. - Zdegradowac
trade-ingestorz roli glownego ingestu do roli pomocniczej albo go usunac z glownej sciezki.
Rekomendacja praktyczna
Najmniejsza sensowna zmiana to nie budowac od razu nowego systemu od zera, tylko:
- naprawic obecny
dlob-publisher - dodac mu zapis do
Postgresa - stopniowo wyprowadzac
trade-ingestorz glownego path
To jest najmniej ryzykowna droga do modelu:
Redis = cache / hot statePostgres = persistent normalized store