[{"data":1,"prerenderedAt":241},["ShallowReactive",2],{"case-study-de-kv-cache-storage-tiering":3,"case-study-related-de-kv-cache-storage-tiering":217},{"id":4,"title":5,"card":6,"diagrams":12,"extension":32,"eyebrow":33,"facts":34,"intro":53,"layout":54,"locale":76,"meta":77,"order":78,"results":79,"slug":96,"stem":97,"storySections":98,"techGroups":113,"__hash__":216},"caseStudies\u002Fcase-studies\u002Fde\u002Fkv-cache-storage-tiering.json","Wo der KV-Cache liegt: Storage-Tiering für LLM-Inferenz unter realem Traffic",{"title":7,"badges":8,"thumb":11},"KV-Cache-Storage-Tiering",[9,10],"vLLM","LMCache","\u002Fcase-studies\u002Fkv-cache-storage-tiering\u002Ftier-hierarchy.webp",[13,16,20,24,28],{"src":11,"alt":14,"caption":15},"Stapel aus vier Storage-Tiers von GPU-HBM bis zu einem geteilten GekkoFS-Tier, der Prefill-Lesepfad hervorgehoben, der Decode-Pfad am Storage vorbei.","Der KV-Cache läuft stufenweise die Hierarchie hinunter. Die Kosten liegen auf dem Lesepfad während des Prefill, und Decode fasst den Storage nie an.",{"src":17,"alt":18,"caption":19},"\u002Fcase-studies\u002Fkv-cache-storage-tiering\u002Fsensitivity-testbed.webp","Experimentpipeline vom Lastgenerator über vLLM und LMCache bis zu einem gedrosselten Disk-Tier, mit getrennten Reglern für Bandbreite und Latenz und einem Metrikpfad.","Der Sensitivitäts-Testbed variiert Bandbreite und Latenz pro Operation unabhängig voneinander, was Vergleiche ganzer Tiers nicht leisten.",{"src":21,"alt":22,"caption":23},"\u002Fcase-studies\u002Fkv-cache-storage-tiering\u002Fshared-cache-topology.webp","Zwei Knoten mit je zwei vLLM-Instanzen, davor ein Load Balancer, und ein GekkoFS-Namespace über die knotenlokalen NVMes beider Knoten.","Vier Instanzen teilen sich einen Cache-Namespace, sodass ein auf einem Knoten berechneter Prefix auf dem anderen nachgeladen statt neu berechnet wird.",{"src":25,"alt":26,"caption":27},"\u002Fcase-studies\u002Fkv-cache-storage-tiering\u002Faws-reference-architecture.webp","AWS-Referenzarchitektur mit GPU-Knoten auf EKS in einer Cluster Placement Group, Instance-Store-NVMe, FSx for Lustre als geteiltem Tier, einem prefix-bewussten Router und Observability.","Referenzarchitektur: wie sich die gemessenen Entwurfsregeln auf AWS-Dienste abbilden.",{"src":29,"alt":30,"caption":31},"\u002Fcase-studies\u002Fkv-cache-storage-tiering\u002Fcore-stack.webp","Kern-Stack","","json","Case Study",[35,38,41,44,47,50],{"label":36,"value":37},"Kontext","Forschungsprojekt, JGU Mainz",{"label":39,"value":40},"Rolle","Forschung und Engineering, durchgängig",{"label":42,"value":43},"Fachgebiet","LLM-Inferenz, HPC-Storage, MLOps",{"label":45,"value":46},"Infrastruktur","Mogon-HPC-Cluster (A40, A100), Workstation mit 2x RTX A6000",{"label":48,"value":49},"Modelle","Llama 3.1 8B und 70B, Qwen3.5-35B-A3B",{"label":51,"value":52},"Jahr","2026","Beim LLM-Serving geht der GPU-Speicher lange vor der Rechenleistung aus. Mit echten Konversations- und Produktions-Traces habe ich gemessen, was jede Storage-Ebene unterhalb der GPU einen laufenden Request kostet, und einen geteilten Cache-Tier auf GekkoFS gebaut, über den mehrere vLLM-Instanzen die Arbeit der jeweils anderen wiederverwenden.",[55,57,59,62,64,66,67,69,70,72,74],{"type":56},"header",{"type":58},"results",{"type":60,"index":61},"section",0,{"type":63,"index":61},"diagram",{"type":63,"index":65},1,{"type":60,"index":65},{"type":63,"index":68},2,{"type":60,"index":68},{"type":63,"index":71},3,{"type":73},"technology",{"type":63,"index":75},4,"de",{},5,[80,84,88,92],{"tag":81,"title":82,"body":83},"Latenz","Nachladen schlägt Neuberechnen um Faktor 3,5 bis 4,6","Einen verdrängten Prefix aus dem CPU-Speicher zurückzulesen dauerte auf einer A100 73 ms, ihn neu zu berechnen 256 ms. Je langsamer die GPU, desto größer die Ersparnis, und damit lohnt sich Cache-Tiering gerade auf kostengünstiger Hardware.",{"tag":85,"title":86,"body":87},"Architektur","Die Kosten bestimmt die Latenz, nicht die Bandbreite","Kontrollierte Messreihen haben zwei Eigenschaften getrennt, die früherer Arbeiten immer gemeinsam verändern. Das Serving hat eine Kürzung auf ein Viertel der Plattenbandbreite überstanden, aber eine Millisekunde zusätzliche Latenz pro Operation hat die Zeit bis zum ersten Token um ein Vielfaches erhöht. Die Decode-Latenz blieb unverändert.",{"tag":89,"title":90,"body":91},"Scale-out","Geteilter Cache gleichauf mit privater NVMe","Bei vier vLLM-Instanzen auf zwei Knoten mit einem gemeinsamen GekkoFS-Namespace lädt eine Instanz KV-Daten nach, die eine andere berechnet hat, statt sie neu zu berechnen. Nach dem Tuning liegt der geteilte Tier auf dem Niveau der privaten lokalen Platte.",{"tag":93,"title":94,"body":95},"Tuning","21x schnelleres Warm-Reload auf dem verteilten Tier","Backend-Tuning und eine größere Chunk-Size haben das Nachladen eines Dokuments mit 16k Token auf rund 1,9 s gedrückt, und alle Lastfälle liefen durch. Mit der Standardkonfiguration kamen die größten Fälle nicht ans Ziel.","kv-cache-storage-tiering","case-studies\u002Fde\u002Fkv-cache-storage-tiering",[99,104,109],{"heading":100,"paragraphs":101},"Die Geschichte",[102,103],"Jedes Token, das ein LLM erzeugt, hängt von den Key- und Value-Vektoren aller vorherigen Token ab. vLLM hält sie in einem KV-Cache, um sie nicht neu zu berechnen, und dieser Cache wächst mit Kontextlänge und Parallelität, bis der GPU-Speicher voll ist. Von dort läuft er in den CPU-DRAM über und danach auf NVMe, und ab da entscheidet der Storage-Pfad mit, wie schnell das erste Token zurückkommt. Veröffentlichte Systeme zeigen, dass Offloading funktioniert. Kaum eines sagt, was der Storage darunter leisten muss.","Die Experimentierplattform habe ich auf vLLM 0.19 mit LMCache als Tiering-Schicht aufgebaut, containerisiert mit Apptainer auf dem Mogon-Cluster und Docker auf einer GPU-Workstation, angetrieben von ShareGPT- und BurstGPT-Traffic. Vierzehn Experimente reichen von einer einzelnen GPU bis zu produktionsnahem Traffic auf einem 70B-Modell mit Tensor-Parallelismus. Die Storage-Variable habe ich mit einem FUSE-Throttling-Shim isoliert, der Bandbreite deckelt und Latenz pro Operation unabhängig davon einspeist, und die Reihenfolge gegen ein dm-delay-Device auf Kernel-Ebene gegengeprüft.",{"heading":105,"paragraphs":106},"Was das bedeutet",[107,108],"Die Ergebnisse verorten die Kosten genau. Das Schreiben des Caches ist im eingeschwungenen Zustand nahezu umsonst, und Decode fasst den Storage nie an, also landet die gesamte Last auf dem Prefill. Innerhalb des Prefill bindet die Latenz pro Operation, die Bandbreite spielt kaum eine Rolle. Das liest sich wie eine Anforderungsliste für jeden Tier unterhalb des Caches: ein Bruchteil der Bandbreite einer einzelnen NVMe genügt, aber jede Millisekunde Round-Trip wird voll bezahlt.","Genau bei vernetztem Storage ist niedrige Latenz schwer zu halten, deshalb habe ich GekkoFS eingebunden, ein Ad-hoc-Dateisystem, das beim Jobstart aus den knotenlokalen NVMes der eigenen Allokation entsteht. Ich habe SharedFSBackend geschrieben, das es als geteilten Disk-Tier an LMCache anbindet. Auf einer einzelnen Instanz verlor es gegen lokale NVMe und las mit rund 0,7 GB\u002Fs gegenüber 6 GB\u002Fs, ohne etwas, hinter dem sich der Round-Trip verstecken könnte. Sein Wert zeigte sich, sobald mehrere Instanzen hinter einem Load Balancer bedienten. Ein privater Cache bedeutet, dass jede Replik Arbeit neu berechnet, die ihre Nachbarn schon erledigt haben, während ein gemeinsamer Namespace jeden Prefix einmal speichert und jede Replik ihn lesen lässt.",{"heading":110,"paragraphs":111},"Entwurfsregel",[112],"Für eine Inferenzplattform ist die Entwurfsregel konkret. Die heißen Tiers bleiben knotenlokal, und jeder geteilte Tier wird zuerst nach seiner Latenz pro Operation beurteilt, erst danach nach Durchsatz. Ein geteilter Tier verdient seinen Platz, sobald die Flotte mehr als eine Replik betreibt und Nutzer sich Prefixe teilen. Das 8B-Modell, mit dem die meisten Läufe entstanden sind, ist der härteste Fall für einen Gewinn durch Nachladen, die hier gemessene Parity ist also eine Untergrenze. Bei 70B, wo Neuberechnung pro Token deutlich mehr kostet, sollte derselbe Entwurf aus Parity einen Latenzgewinn machen.",[114,128,141,160,179],{"title":115,"items":116},"Inferenz",[117,120,124],{"name":9,"role":118,"icon":119},"Serving-Engine mit PagedAttention und Tensor-Parallelismus","\u002Ficons\u002Ftech\u002Fvllm.png",{"name":10,"role":121,"icon":122,"monogram":123},"KV-Cache-Tiering über CPU-Speicher, Platte und geteilte Backends",null,"LM",{"name":125,"role":126,"icon":127},"Hugging Face Hub","Modell-Hosting für Llama 3.1 und Qwen3.5","\u002Ficons\u002Ftech\u002Fhuggingface.svg",{"title":48,"items":129},[130,134,137],{"name":131,"role":132,"icon":133},"Llama 3.1 8B Instruct","Single-GPU-Baseline, 128 KiB KV-Cache pro Token","\u002Ficons\u002Ftech\u002Fmeta.svg",{"name":135,"role":136,"icon":133},"Llama 3.1 70B Instruct","Multi-GPU-Fall mit Tensor-Parallelismus, 320 KiB KV-Cache pro Token",{"name":138,"role":139,"icon":140},"Qwen3.5-35B-A3B (FP8)","Long-Context-Fall, hybride Attention mit 20 KiB pro Token","\u002Ficons\u002Ftech\u002Fqwen.svg",{"title":142,"items":143},"Storage",[144,148,152,156],{"name":145,"role":146,"icon":122,"monogram":147},"GekkoFS","verteiltes Ad-hoc-Dateisystem als geteilter Cache-Tier","GK",{"name":149,"role":150,"icon":122,"monogram":151},"SharedFSBackend","mein LMCache-Backend für geteilte Dateisystem-Tiers","\u003C\u002F>",{"name":153,"role":154,"icon":122,"monogram":155},"FUSE throttling shim","unabhängige Bandbreitengrenzen und Latenzeinspeisung","FS",{"name":157,"role":158,"icon":159},"dm-delay","Latenzeinspeisung auf Kernel-Ebene zur Gegenprobe","\u002Ficons\u002Ftech\u002Flinux.svg",{"title":161,"items":162},"Compute und Betrieb",[163,167,171,175],{"name":164,"role":165,"icon":166},"Slurm","Job-Scheduling auf dem Mogon-Cluster","\u002Ficons\u002Ftech\u002Fslurm.png",{"name":168,"role":169,"icon":122,"monogram":170},"Apptainer","reproduzierbare Container auf HPC-Knoten","AP",{"name":172,"role":173,"icon":174},"Docker","Container auf der lokalen GPU-Workstation","\u002Ficons\u002Ftech\u002Fdocker.svg",{"name":176,"role":177,"icon":178},"NVIDIA A100 and A40","GPU-Testbeds mit unterschiedlichem Verhältnis von Rechenleistung zu Speicher","\u002Ficons\u002Ftech\u002Fnvidia.svg",{"title":180,"items":181},"AWS-Referenzabbildung",[182,186,190,194,200,204,210],{"name":183,"role":184,"icon":185},"EC2 P4d \u002F P5","GPU-Knoten mit lokalem NVMe-Instance-Store","\u002Ficons\u002Faws\u002FAmazon-EC2.svg",{"name":187,"role":188,"icon":189},"FSx for Lustre","verwalteter geteilter Cache-Tier über Repliken","\u002Ficons\u002Faws\u002FAmazon-FSx-for-Lustre.svg",{"name":191,"role":192,"icon":193},"EFA and cluster placement groups","niedrige Round-Trip-Latenz zum geteilten Tier","\u002Ficons\u002Faws\u002FElastic-Fabric-Adapter.svg",{"name":195,"role":196,"icon":197,"icons":198},"EKS with Karpenter","Skalierung der GPU-Repliken hinter einem prefix-bewussten Router","\u002Ficons\u002Faws\u002FAmazon-EKS.svg",[197,199],"\u002Ficons\u002Ftech\u002Fkubernetes.svg",{"name":201,"role":202,"icon":203},"AWS ParallelCluster","Slurm-basierte Alternative, die das HPC-Setup abbildet","\u002Ficons\u002Faws\u002FAWS-ParallelCluster.svg",{"name":205,"role":206,"icon":207,"icons":208},"S3 and ECR","Modellgewichte und Container-Images","\u002Ficons\u002Faws\u002FAmazon-S3.svg",[207,209],"\u002Ficons\u002Faws\u002FAmazon-ECR.svg",{"name":211,"role":212,"icon":213,"icons":214},"Managed Prometheus and Grafana","SLOs für TTFT und Inter-Token-Latenz","\u002Ficons\u002Faws\u002FAmazon-Managed-Prometheus.svg",[213,215],"\u002Ficons\u002Faws\u002FAmazon-Managed-Grafana.svg","zu8uZJcvTt4J5JFIstlMUYZEzCrLXcKZ-kEPPWDDgKQ",[218,226,234],{"slug":219,"card":220},"live-product-data-pipeline",{"title":221,"badges":222,"thumb":225},"Live-Produktdaten-Pipeline",[223,224],"Kafka Streams","Amazon MSK","\u002Fcase-studies\u002Flive-product-data-pipeline\u002Fafter.webp",{"slug":227,"card":228},"product-classification",{"title":229,"badges":230,"thumb":233},"Produktklassifizierung mit MLOps",[231,232],"Amazon Bedrock","PyTorch","\u002Fcase-studies\u002Fproduct-classification\u002Ftraining-pipeline.webp",{"slug":235,"card":236},"property-management-platform",{"title":237,"badges":238,"thumb":240},"Mandantenfähige Hausverwaltungs-Plattform",[239,231],"Mandantenfähigkeit","\u002Fcase-studies\u002Fproperty-management-platform\u002Fsystem-architecture.webp",1790607906809]