Snilld

Sådan splittede Netflix enorme Cassandra-partitioner uden at ændre applikationen

Netflix beskriver en løsning kaldet Dynamic Repartitioning, der opdeler alt for brede Cassandra-partitioner per TimeSeries‑ID. Ifølge den foreliggende rapport falder gennemsnitlige læse‑tider fra sekunder til lave tocifrede millisekunder, og tail‑latency lander omkring 200 ms – uden ændringer i applikationslaget. Dokumentationen er p.t. baseret på et sekundært referat, så flere primærkilder efterlyses.

9. juli 2026 Peter Munkholm

Netflix har løftet sløret for en teknik til et af Cassandras klassiske problemer ved tidsserier: alt for brede partitioner. Løsningen hedder Dynamic Repartitioning og splitter store partitioner per ID, asynkront og uden at applikationerne skal ændres. Ifølge den tilgængelige beskrivelse falder læse-latency fra sekunder til lave tocifrede millisekunder, og tail-latency stabiliserer sig omkring 200 ms.

Vigtig detalje først: Oplysningerne stammer fra en opsummering hos MarkTechPost, ikke direkte fra Netflix’ egen engineering-blog eller et paper. Der mangler altså primærdokumentation og rå benchmarks, som kan trykprøve tallene. Det gør ideen interessant – men kræver også, at måden de måler på read-pathen afklares.

Hvorfor tidsserier og hvorfor Cassandra

Netflix’ TimeSeries-abstraktion siges at ligge oven på Apache Cassandra 4.x og håndtere petabytes af tidsstemplet begivenhedsdata. Cassandra er valgt for throughput, forudsigelig latenstid, pris pr. skriv\/læs og et modent driftsøkosystem. TimeSeries grupperer data per ID og tidsspand og arbejder med time slices, time buckets og event buckets, så man kan spørge og slette efter tid uden for mange tombstones.

Formålet er at give teams en enkel logisk model, mens det fysiske layout kan justeres, når antagelser skrider. Når nogle få ID’er vokser voldsomt, bliver halen tung – og det ses som sekunder i læsninger, timeouts og støj i nabolagstjenester.

Makro af cyan og grøn gulvmarkering på beton: fysisk metafor for to adskilte ruter efter en splitting.

Problemet med brede partitioner

En “wide” partition i Cassandra opstår, når for mange rækker ender under samme partition key. Over tid ophobes data. Gennemsnittet kan se fint ud, men hale-endene (p95-p99) ryger i vejret til sekunder. Ifølge opsummeringen følger read timeouts, GC-pauser, høj CPU og køer på tråde – den velkendte driftskaskade.

Når halen løber løbsk, kolliderer SLO’er med virkeligheden: downstream-tjenester rammer timeouts, caches misprimes, og retries presser clusteret yderligere. Man kan altid købe flere noder – eller man kan ændre layoutet mere målrettet, hvilket er det, Netflix beskriver her.

Arkitekturen bag Dynamic Repartitioning

Flowet er kernen: brede partitioner opdages på read-pathen via byte-tælling. Når en læsning trækker for mange bytes, udløses et Kafka-event, der sætter en asynkron splitter i gang med at omorganisere partitionen per ID. Klienten læser stadig mod den logiske partition, men under motorhjelmen rutes forespørgslen videre til en eller flere “child”-partitioner.

Routing sker ifølge beskrivelsen med Bloom-filters kombineret med et cachet opslag i wide_row-metadata. Metadatalaget fortæller, hvor rækkerne bor efter splittet, og Bloom-filtrene mindsker unødige SSTable-slug. Pointen er at påvirke det normale request-flow mindst muligt.

Banner

Håndtering af immutable vs mutable data

Splittet prioriterer immutable partitioner først for at undgå samtidige skriver under migrering. Mutable partitioner – hvor der stadig kommer hændelser ind – kræver mere koordination, og den del er kun kort omtalt i materialet. Der nævnes correctness-guards: checksums, fastholdelse af de originale partitioner, Data Bridge Spark-tjek og shadow comparisons, før trafikken omlægges fuldt.

Processfoto: hænder sætter ubrandede tags på en vogn for at opdele ruten — metafor for at oprette child‑partitioner og genoprette flow.

Performance og påstande om forbedringer

MarkTechPost refererer forbedringer fra sekunder til lave tocifrede millisekunder på gennemsnitlige læsninger og en tail-latency omkring 200 ms. Dertil at partitioner over 500 MB fortsat er tilgængelige. Det er betydelige tal, som – hvis de holder – kan flytte praksis for time buckets og key-design. Men vurderingen kræver indblik i workload: QPS, læse\/skrive-blanding, antal SSTables pr. partition, komprimering osv.

Benchmark-metoden er afgørende: Produktionstrafik, syntetisk load eller skygge-kopi? Hvilke SLO’er og retry-politikker? Uden de brikker er tallene lovende, men ikke generaliserbare.

Hvad løsningen betyder i drift

Read-routing med Bloom-filters og metadata-cache lægger nye krav på CPU og hukommelse. Et lavt falsk-positiv-niveau i Bloom-filtre koster RAM; for aggressive filtre giver flere falsk-positive og ekstra disk-hop. Metadata-cachen skal have høj hit-rate under højt QPS, ellers forsvinder gevinsten.

Backup, compaction og repair får også en ny profil. Når en logisk partition fysisk bor i flere child-partitioner, skal snapshots og repairs dække alle dele. Anti-entropy kører stadig på SSTable-niveau, men overhead kan stige, hvis fordelingen bliver fragmenteret. Overvågning bør inkludere metrics som antal aktive splits, gennemløb i split-køen, Bloom-filter hit-rate, metadata cache-miss-rate og andel af lykkede checksum-verifikationer per tidsenhed.

Hvorfor ikke bare re-partitionere ved nye time slices

Netflix beskriver også en baggrundsarbejder, der bruger Cassandras introspektion – fx tablehistograms – til at justere fremtidige time slices. Det retter det strukturelle. Men hjælper ikke når nogle få ID’er er ekstreme outliers. Dynamic Repartitioning er mere kirurgi: adresser outliers uden applikationsændringer.

Det er en måde at afkoble produktteams fra akutte nøgleændringer, når en håndfuld ID’er laver balladen.

Processfoto: hænder sætter ubrandede tags på en vogn for at opdele ruten — metafor for at oprette child‑partitioner og genoprette flow.

Implementeringskrav og kontrolpunkter

Byggestenene er: Cassandra 4.x, byte-måling på read-path per forespørgsel, en Kafka-bus til split-events og en hurtig metadata-cache tæt på læseservicen. Bloom-filtre kræver tuning af falsk-positiv-rate mod RAM-budget og nøglerum. Staging-tests bør inkludere fejl-injektion i routing for at måle effekten af forkerte rutevalg.

Overvågning: detektionsrate for brede reads (events\/sek.), længde og latens i split-køer, antal child-partitioner pr. logisk ID, Bloom-filter hit-rate, metadata miss-rate og GC-pause-varighed på læsenoder før\/efter. Dertil P50\/P95\/P99-latency opdelt i “pre-split” og “post-split”.

Korrekthed og rollback

Checksums, shadow comparisons og retention af de originale partitioner er sikkerhedsnettet. Det muliggør side-om-side-sammenligning og rollback, hvis data ikke matcher bit for bit. Data Bridge Spark-tjek nævnes som endnu et lag, formodentlig til batchvis verifikation i stor skala. Det koster lager og CPU midlertidigt, men kan være billigere end vedvarende timeouts i produktion.

Den praktiske knast er skifteøjeblikket: 1) opbyg child-partitioner, 2) beregn checksums per segment, 3) kør shadow-reads mod child, 4) skift gradvist læserouting ved 100 procent match, 5) behold originalen i en periode til nødtilbageførsel. Her bør Netflix’ primærmateriale levere detaljer, da fejl oftest opstår i overgangen.

Banner

Hvad tallene betyder i praksis

Hvis læsninger går fra sekunder til 10–20 ms, er gevinsten størst i realtidsforbrug: feature stores, online inferens, sessionscoring, anti-fraud. En p99 omkring 200 ms reducerer timeouts i kaldkæder og giver mere stabil datatilførsel til modeller – mindre behov for defensiv caching. Det handler om stabil distributionshale mere end om p50.

Effekten er dog ikke garanteret: write-tunge mønstre eller workloads med mange små nøgler vil se mindre forbedring. Mål først, og verificér at tailen korrelerer med få brede partitioner, før man går i gang.

Alternativer og konkurrenceperspektiv

Andre tilgange: applikationssharding med en ekstra dimension i partition key, TTL-baseret pruning for mindre partitioner, eller databaser med native tidsserie-sharding. Hver strategi har omkostninger i applikationsændringer, migration og drift. Dynamic Repartitioning tilbyder en mellemvej: behold API’et, flyt byrden ned i lagringen.

Bloom-filter-baseret routing og metadata-lag er kendte komponenter; nyheden her er koblingen til automatisk detektion på læsevejen og efterfølgende splitting bag kulissen. Lykkes det, kan man designe nøgler mindre konservativt uden at frygte fremtidig halevækst.

Risici, begrænsninger og åbne spørgsmål

Fire felter kræver primærkilder: 1) præcis algoritme for byte-tælling på read-path (per-request, sampling eller estimat via interne metadata), 2) procedurer for splitting af mutable partitioner under løbende writes, 3) Bloom-filtrenes falsk-positiv-rate og opdateringsfrekvens for metadata-cachen, 4) de operationelle omkostninger i CPU, RAM, lager og Kafka-trafik. Uden dem er cost\/benefit svær at kvantificere.

Derudover: effekt på compaction-strategi og repair-vinduer, når mange child-partitioner skabes hurtigt; backpressure på split-jobbet; cap på antal child-partitioner per ID, før man bør ændre key-design. Alt sammen relevant i enterprise-drift.

Hvornår bør man vælge denne vej

Overvej Dynamic Repartitioning, hvis: 1) tail-latency domineres af få brede partitioner, 2) applikationslaget ikke kan ændres hurtigt, 3) infrastrukturen kan køre splitter og metadata-lag robust. Hvis problemet er bredt i hele tabellen, kan re-partitionering ved næste time slice være enklere. Hvis det primært er økonomi, kan “scale up” være kortsigtet billigere.

For AI-nære systemer – feature stores, online retraining, realtidsberigelse – er en stabil p99 vigtigere end en lav p50. En p99 under et par hundrede millisekunder reducerer dataglitchs i pipelines og giver ro i drift.

Praktiske anbefalinger til teams

PoC i fem trin: 1) mål baseline-tail-latency og identificér outlier-ID’er, 2) implementér read-path byte-tælling i staging og log detektionsevents, 3) kør test-splitting på immutable partitioner med original beholdt og shadow-sammenligning, 4) mål effekt på compaction og repair med realistisk data, 5) rul gradvist ud med alarmer på checksum-fejl og cache-miss-rate. Overvåg især Bloom-filter hit-rate mod en defineret tærskel, fx 95 procent.

Etabler governance: hvem må igangsætte splits, SLO for split-køen, hvornår retention af de originale partitioner udløber, og hvordan rollback dokumenteres. Hav en afbrydermekanisme til peak-dage.

Hvad mangler for fuld verifikation

Dækningen hviler på en sekundær kilde, MarkTechPost. For at verificere implementeringen og tallene vil følgende hjælpe: 1) officiel Netflix engineering-blogpost eller talk med arkitektur- og state-diagrammer for splitting, 2) benchmark-detaljer med QPS, datafordeling, cluster-størrelse, compaction-strategi og retry-politikker, 3) konkrete metrics for Bloom-filter-konfiguration og metadata-cache-størrelse\/hit-rate, 4) eventuel kode eller pseudo-kode for byte-tælling og rutevalg.

Indtil da er konklusionen nøgtern: idéen er solid, de rapporterede gevinster er plausible for workloads domineret af brede partitioner, og mekanismerne – detektion på read-path, asynkron splitting, Bloom-filters, metadata-caching og correctness-guards – hænger fagligt sammen. En bred anbefaling kræver dog primære kilder og målbare beviser.

Kilder

    Gør brugeroplevelsen bedre.
    Hvilket firma arbejder du for?