Modulul 6 se termină așa cum s-a terminat Modulul 5: cu o singură companie, un deceniu și postări publice de inginerie care transformă abstracțiile modulului în mașinărie concretă. Modulul 5 s-a închis pe Netflix, unde povestea interesantă era o platformă batch la scară de petabyte. Modulul 6 se închide pe Uber, unde povestea interesantă e mutarea de la batch-only la streaming-first, problema de ingestion care a venit cu ea și proiectul Hudi care a ieșit din ea. Ambele povești sunt despre aceeași suprafață arhitecturală (un lakehouse plus mai multe motoare plus un strat de orchestration), iar diferența e ce a împins construcția: presiunea Netflix era scara și costul; presiunea Uber era latența.
Cadrul lecției 47 stă în spatele acestei lecții. Uber n-a ales deliberat Kappa în locul Lambda; au mers pe drumul pe care a mers industria, în public, cu concluziile vizibile în proiecte open-source. Marmaray și Hudi sunt cele două artefacte care contează pentru acest modul. Marmaray e framework-ul de ingestion. Hudi e stratul de stocare care a făcut din streaming-into-lake un lucru real, nu un workaround.
Scara și problema
Prezentările publice și postările de inginerie ale Uber dau forma generală. Zeci de milioane de curse pe zi în sute de țări, fiecare cursă producând zeci de evenimente: cerută, acceptată, începută, actualizări de locație, plătită, evaluată. Sute de mii de șoferi și milioane de pasageri care generează semnale care trebuie ingerate, joinuite, modelate, scorate și acționate. Petabyți în lake, mii de servicii, sute de echipe. Un mic set de decizii trebuie să se întâmple în timp real; o coadă lungă poate rula nocturn.
Uber Engineering Blog (https://www.uber.com/blog/engineering/data/, consultat 2026-05-01) a fost neobișnuit de generos cu postări publice despre arhitectură. Rezumatul de mai jos cusă împreună postări despre Marmaray, Hudi, platforma de streaming și stack-ul mai larg de date, cu citări la final.
Stack-ul pre-2014 era batch-only. Job-urile Hadoop zilnice agregau evenimentele de cursă pentru analiză, finanțe și machine learning offline. Asta era ok pentru analiză, dar cazurile de utilizare operaționale (surge pricing, detectare de fraudă, modele ETA, dashboard-uri real-time pentru centrele operaționale) aveau nevoie de răspunsuri în secunde sau minute. Până la mijlocul anilor 2010, compania înșuruba pipeline-uri de streaming pe partea stack-ului batch, iar înșurubarea devenea scumpă.
Două dureri specifice au împins rescrierile care au produs Marmaray și Hudi.
Ingestion-ul era custom per sursă. Datele curgeau de la Kafka, replici MySQL, Cassandra, store-uri schemaless interne și o coadă lungă de servicii. Fiecare sursă avea propriul pipeline bespoke spre Hadoop, scris de echipa care construise sursa prima. Schemele se îndepărtau. Eșecurile erau debugate sursă cu sursă. Adăugarea unui sink nou însemna să scrii din nou un pipeline nou pentru fiecare sursă.
Data lake-ul nu putea absorbi update-uri. Datele Uber sunt în mare parte mutabile. Statusul unei curse se schimbă pe măsură ce avansează. Profilul unui șofer e actualizat. Metoda de plată a unui pasager e corectată. Modelul de fișiere append-only al Hadoop era o potrivire proastă, iar workaround-urile (snapshot-uri zilnice complete, tabele de dimensiuni care se schimbă lent în job-uri nocturne) dădeau rezultate corecte o dată pe zi și date vechi de o oră restul timpului. Nu mai bine decât stack-ul batch-only pe care încercau să-l depășească.
Marmaray: framework-ul de ingestion
Marmaray a fost open-source-uit de Uber în 2018 și descris în postarea de pe Uber Engineering Blog „Marmaray: An Open Source Generic Data Ingestion and Dispersal Framework for Apache Hadoop” (https://www.uber.com/blog/marmaray-hadoop-ingestion-open-source/, consultat 2026-05-01). Pitch-ul e în subtitlu: un framework generic pentru mutat date între orice sursă și orice sink.
Ideea arhitecturală e decuplarea. Sursele și sink-urile sunt pluggable. Framework-ul furnizează schela din jur: management de scheme, gestionare de erori, retries, monitoring, dispersia datelor derivate înapoi spre alte sisteme. Cea mai mare parte din munca grea rulează pe Spark.
Deployment-urile la Uber au acoperit Kafka în Hadoop (cazul firehose), Cassandra și MySQL în Hadoop (snapshot-uri și CDC din store-urile operaționale) și calea inversă din Hadoop spre store-urile operaționale când modelele antrenate batch trebuiau servite în producție. Un singur framework, multe perechi sursă-sink, cu munca per pereche limitată la connectori.
Lecția generalizată: valoarea unui framework de ingestion nu sunt connectorii. Connectorii sunt partea ușoară. Valoarea e consistența. Fiecare pipeline trece prin același framework, cu aceeași observabilitate, retries, management de scheme și poveste operațională. Adăugarea unui pipeline nou devine configurație plus un connector, nu un exercițiu de design proaspăt. La scara Uber, asta era diferența între sute de pipeline-uri bespoke și o singură platformă.
Hudi: stocare construită pentru streaming-into-lake
Apache Hudi a început la Uber în 2016 ca răspuns la problema upsert. A fost open-source-uit în 2017, a devenit un proiect Apache Incubator și a ajuns la status top-level în 2020. Postarea originală de pe Uber Engineering Blog „Uber’s Big Data Platform: 100+ Petabytes with Minute Latency” (https://www.uber.com/blog/uber-big-data-platform/, consultat 2026-05-01) expune motivația, iar documentația Apache Hudi (https://hudi.apache.org/, consultat 2026-05-01) descrie formatul în detaliu.
Hudi a fost proiectat pentru o formă specifică de workload: stream-uri de evenimente, dintre care multe sunt update-uri la entități care există deja în lake. Un eveniment de cursă sosește și ar putea fi primul eveniment pentru acea cursă (insert), sau un update la o cursă deja în desfășurare (update), sau o corecție la o cursă care s-a încheiat ieri (update întârziat). Stratul de stocare trebuia să facă toate cele trei cazuri eficiente și atomice.
Hudi expune trei concepte cheie.
Tabele Copy-on-Write (CoW). Fiecare upsert rescrie fișierele de date care conțin rândurile afectate. Citirile sunt rapide (fără pas de merge la read time), dar scrierile sunt scumpe: schimbarea unui rând într-un fișier Parquet de o sută de megabytes înseamnă rescrierea întregului fișier. CoW e alegerea potrivită când citirile domină și scrierile sunt concentrate într-un număr mic de fișiere (partiții recente), care e pattern-ul comun pentru telemetrie de tip time-series.
Tabele Merge-on-Read (MoR). Fiecare upsert adaugă un delta la nivel de rând într-un fișier de log alături de Parquet-ul de bază. Citirile îmbină baza și delta-urile la query time. Scrierile sunt ieftine (doar adaugă un delta), dar citirile sunt mai lente pentru că plătesc costul îmbinării. Compactarea periodică rescrie delta-urile înapoi în fișierele de bază, restaurând performanța de citire. MoR e alegerea potrivită când scrierile domină sau când înregistrări individuale sunt actualizate frecvent peste tabel, ca în cazul oglinzilor CDC ale bazelor de date operaționale.
Snapshot-uri și time travel. Hudi urmărește un timeline imutabil de commit-uri. Fiecare citire alege un snapshot pe care să-l interogheze și poți cere tabelul așa cum era la un timestamp sau commit specific. Aceeași mașinărie alimentează query-urile incrementale: „dă-mi rândurile care s-au schimbat între commit T1 și commit T2”, care e primitiva naturală pentru pipeline-urile din aval care vor să consume doar ce e nou.
Hudi a fost primul format de stocare open-source care a luat în serios toate cele trei funcționalități împreună. Până când Delta Lake (2019) și Iceberg (donat în 2018) se maturizau, Hudi avea deja deployment-uri în producție la Uber și era alegerea naturală pentru workload-uri grele de upsert. Lecția 37 a acoperit războaiele de format și unde a aterizat industria.
Forma pipeline-ului Uber
Punând Marmaray, Hudi, Kafka și Flink împreună dă stack-ul streaming-first pe care-l descriu postările publice ale Uber. Forma e recognoscibil aromată Kappa (lecția 47), cu un singur strat de stocare care alimentează atât consumatorii real-time, cât și pe cei batch.
flowchart LR
SVC[Application services<br/>rides, payments, location]
K[(Kafka<br/>event log)]
F[Flink<br/>real-time aggregates]
M[Marmaray<br/>ingestion]
H[(Hudi tables<br/>on HDFS or S3)]
P[Presto / Trino<br/>interactive queries]
S[Spark<br/>batch analytics]
OPS[Operations dashboards<br/>surge, ETA]
BI[BI and finance]
ML[ML training]
SVC --> K
K --> F
K --> M
F --> OPS
M --> H
H --> P
H --> S
P --> BI
S --> ML
S --> BI
Diagramă de creat: o versiune polisată a diagramei Mermaid de mai sus, cu serviciile în extrema stângă, Kafka ca șira spinării centrală, cele două căi de consumator (Flink pentru real-time, Marmaray pentru ingestion) ramificându-se din șira spinării, Hudi ca strat de stocare în mijloc, cele trei motoare de query (Flink, Presto, Spark) ca compute peste Hudi și consumatorii (dashboard-uri operaționale, BI, ML) la dreapta. Ideea vizuală e că există un singur log de evenimente care alimentează atât lumea real-time, cât și pe cea batch, și un singur strat de stocare care alimentează multiple motoare de query.
Un eveniment de cursă curge din serviciul aplicație în Kafka. Din Kafka se desparte în două direcții. Flink îl citește pentru agregatele real-time care alimentează surge pricing și dashboard-urile operaționale. Marmaray îl citește (împreună cu tot ce vine din Kafka, MySQL și Cassandra) și-l așază în tabele Hudi pe data lake. Presto și Spark citesc din Hudi pentru query-uri interactive și analiză batch. Aceleași tabele Hudi susțin dashboard-urile, rapoartele financiare, dataset-urile de antrenament ML și calea de replay istoric.
Două proprietăți arhitecturale ies din această formă.
Un singur strat de stocare, multiple motoare de query. Tabelele Hudi sunt singurul store fizic. Alegerea motorului de query e per workload: Presto pentru analiză interactivă, Spark pentru ETL greu, Flink pentru streaming. Comutarea motoarelor nu cere migrarea datelor. Adăugarea unui motor nou e un connector plus un benchmark. Această decuplare e victoria arhitecturală și de aceea munca pe formate de tabel deschise (lecția 37) contează atât de mult: formatul e contractul pe care toate motoarele cad de acord.
Streaming-first schimbă rolul lake-ului. Pre-streaming, data lake-ul era o destinație batch read-mostly. Post-streaming, e un store tranzacțional cu scrieri continue și update-uri atomice. Contractul lake-ului s-a schimbat. Hudi (și Iceberg și Delta) sunt cum arată noul contract în practică. Pattern-urile pe care data engineers le folosesc ca să interacționeze cu lake-ul (query-uri incrementale, citiri de snapshot, time travel) sunt pattern-urile care decurg din această schimbare de contract.
Lecțiile
Cinci concluzii, structurate în felul în care le-a structurat cazul Netflix din Modulul 5.
Streaming-first schimbă rolul lake-ului. Cea mai mare schimbare arhitecturală în călătoria Uber nu e „folosim acum Kafka și Flink”. E că data lake-ul a încetat să fie o destinație batch și a devenit un store tranzacțional. Pattern-urile de interacționare cu el s-au schimbat. Formatul a trebuit să se schimbe ca să suporte asta. Modelul mental a trebuit să se schimbe. Asta e mutarea de la „citim datele de ieri” la „citim date actualizate continuu cu semantică de snapshot” și e mutarea pentru care s-a pregătit Modulul 6. Întrebarea Lambda-versus-Kappa din lecția 47 e, la un nivel, o întrebare despre dacă stratul tău de stocare poate suporta ambele citiri în același timp.
Open-source ce construiești. Investiția Uber în Hudi a fost răsplătită prin contribuții ale comunității, suport mai larg de motoare și standardizare. Povestea Iceberg (lecția 40) la Netflix și povestea Hudi la Uber sunt aceeași formă: o companie rezolvă o problemă internă grea, open-source-uiește soluția și călărește valul îmbunătățirilor comunității după aceea. Costul deschiderii e real; beneficiul (software durabil, hiring mai ușor, aliniere de ecosistem) e mai mare la scară. Echipele mai mici ar trebui să adopte aceste formate, nu să inventeze altele noi.
Un singur strat de stocare, multiple motoare. Decuplarea dintre formatul de tabel și motorul de query e cea mai consecventă schimbare modernă în stack-ul de date. Un warehouse din 2010 deținea stocarea și motorul împreună; un lakehouse din 2026 le separă. Hudi (sau Iceberg sau Delta) e stocarea; Spark, Presto, Flink și o duzină de altele sunt motoarele. Această separare lasă o singură echipă să ruleze query-uri interactive, ETL batch și job-uri streaming pe aceleași date fără să le copieze între sisteme.
Build versus buy la scară. Uber a construit Hudi pentru că în 2016 nicio opțiune gata de raft nu suporta nevoile lor de upsert peste object storage. Calculul ăla a fost corect pentru Uber. E greșit pentru aproape orice altă echipă și e tot mai greșit acum că Hudi, Iceberg și Delta există și sunt mature. Principiul general: construiește componente de platformă doar când cele standard chiar nu se potrivesc și acceptă că pragul pentru „construiește” e mult mai sus decât pare. Povestea Maestro de la Netflix (lecția 40) a făcut același punct despre orchestratoare.
Platforma absoarbe complexitatea ca data engineers să nu o facă. Marmaray ascunde complexitatea de ingestion în spatele unui framework uniform. Hudi ascunde complexitatea de upsert în spatele unei abstracții uniforme de tabel. Data engineers care scriu job-uri Spark pe tabele Hudi nu văd mecanica merge-on-read, planificarea compactării sau expirarea snapshot-urilor. Echipa de platformă o vede. Scopul arhitectural e să faci lucrul corect lucrul ușor pentru echipele de aplicație, absorbind complexitatea în componentele de platformă, în loc să ceri fiecărei echipe s-o gestioneze ea însăși.
Referințe încrucișate înapoi în Modulul 6
Stack-ul Uber exersează fiecare primitivă pe care a introdus-o Modulul 6. Kafka (lecția 42) e log-ul durabil de evenimente, șira spinării sistemului. Procesoarele de stream (lecția 43) sunt Flink, calculând agregate real-time. Watermark-urile și event time-ul sunt felul în care acele agregate gestionează cursele întârziate și actualizările de locație în afara ordinii pe care datele reale de ride-hailing le conțin inevitabil. Alegerea Lambda-versus-Kappa (lecția 47) e implicită: Uber rulează streaming și batch ca pipeline-uri separate care împart aceeași stocare, ceea ce e structural Kappa cu doi consumatori. Hudi (introdus în lecția 37 în contextul lakehouse) e stocarea care face întreaga formă să meargă.
Pattern-urile se transferă. O echipă care rulează un tabel Hudi de o sută de gigabytes pe un cluster Kafka mic face același lucru pe care-l face Uber pe petabyți. Diagramele sunt aceleași, preocupările operaționale sunt aceleași, formatul e același. Constantele sunt diferite. Forma nu.
Modulul 6 se închide aici și ce vine
Modulul 6 a parcurs streaming-ul end to end. De ce streaming-ul e structural diferit de batch (lecția 41), Kafka și log-ul durabil (lecția 42), procesoarele de stream și operatorii cu stare (lecția 43), event time-ul și watermark-urile (lecția 44), semantica exactly-once în streaming (lecția 45), CDC-ul și unificarea datelor operaționale și analitice (lecția 46), Lambda versus Kappa ca încadrare arhitecturală (lecția 47), și acum Uber ca studiu de caz care le exersează pe toate.
Modulele 5 și 6 împreună sunt jumătatea de platformă-de-date a cursului. Modulele 1-4 au acoperit fundamentele arhitecturale. Modulele 5 și 6 au acoperit batch-ul și streaming-ul, cele două jumătăți ale modului în care datele se mișcă și se transformă la scară. Cele două studii de caz (Netflix în Modulul 5, Uber în Modulul 6) sunt dovada concretă că pattern-urile se generalizează.
Modulul 7 începe o conversație diferită. Cod, version control, CI/CD și practicile de inginerie software din jur care transformă designurile arhitecturale în sisteme care rulează. Platforma de date va continua să apară ca exemplu, dar subiectul se schimbă spre cum livrează inginerii software efectiv, ceea ce e practica în care stă toată arhitectura. Vocabularul se schimbă. Disciplina de „fă lucrul corect lucrul ușor” nu.
Citări și lecturi suplimentare
- Uber Engineering Blog, „Marmaray: An Open Source Generic Data Ingestion and Dispersal Framework for Apache Hadoop”, 2018,
https://www.uber.com/blog/marmaray-hadoop-ingestion-open-source/(consultat 2026-05-01). Introducerea în Marmaray, cu arhitectura și cazurile de utilizare la Uber. - Uber Engineering Blog, „Uber’s Big Data Platform: 100+ Petabytes with Minute Latency”, 2018,
https://www.uber.com/blog/uber-big-data-platform/(consultat 2026-05-01). Postarea care a introdus Hudi unei audiențe mai largi și a explicat motivația streaming-into-lake. - Uber Engineering Blog, postări de date și platformă indexate la
https://www.uber.com/blog/engineering/data/(consultat 2026-05-01). Seria mai largă care acoperă deployment-ul Kafka, platforma de streaming, stack-ul de analiză real-time și evoluțiile ulterioare ale arhitecturii. - Documentația Apache Hudi,
https://hudi.apache.org/(consultat 2026-05-01). Referința canonică pentru format, tipurile de tabel (Copy-on-Write și Merge-on-Read), modelul de timeline și ghidarea operațională pe compactare și clustering. - „Designing Data-Intensive Applications” (Martin Kleppmann, O’Reilly, 2017), capitolele 11 și 12. Referința standard pentru pattern-urile de streaming pe care le instanțiază stack-ul Uber.