[{"data":1,"prerenderedAt":296},["ShallowReactive",2],{"blog-post-de-kafka-topic-design-idempotency":3,"blog-latest-de-kafka-topic-design-idempotency":79},{"id":4,"title":5,"body":6,"category":68,"date":69,"description":60,"extension":70,"meta":71,"navigation":72,"order":73,"path":74,"seo":75,"stem":76,"summary":77,"__hash__":78},"blog\u002Fblog\u002Fkafka-topic-design-idempotency.md","Event-getriebene Architektur mit Kafka: Topic-Design, Partitionierung und Idempotenz",{"type":7,"value":8,"toc":59},"minimark",[9,14,18,22,25,29,32,36,39,43],[10,11,13],"h2",{"id":12},"topics-sind-verträge","Topics sind Verträge",[15,16,17],"p",{},"Ich behandle jedes Kafka-Topic als Vertrag zwischen dem, der darauf produziert, und dem, der davon konsumiert, nicht nur als Namen in einer Config-Datei. Namenskonventionen sind wichtig: Der Name eines Topics sollte verraten, welches Domain-Event es trägt und wem es gehört, nicht nur, welcher Service heute zufällig darauf schreibt. Schema-Evolution muss eine explizite, versionierte Entscheidung sein statt etwas, das implizit passiert, weil ein Producer ein Feld hinzugefügt hat. Eine Schema-Registry mit zur Schreibzeit durchgesetzten Kompatibilitätsregeln fängt das ab, bevor es zur Laufzeit-Exception eines Consumers wird. Retention ist die dritte Entscheidung, die ich für jedes Topic bewusst treffe: wie lange Events leben müssen und ob dieses Topic ein transienter Message-Bus oder ein dauerhaftes Log ist, das nachgelagerte Systeme von Anfang an replayen könnten. Keine davon akzeptiere ich als Default. Es sind Entscheidungen, die einmal im Voraus getroffen werden, denn sie später zu ändern bedeutet, jeden Producer und Consumer gleichzeitig zu koordinieren.",[10,19,21],{"id":20},"partitionierung-für-parallelität","Partitionierung für Parallelität",[15,23,24],{},"Partitionsanzahl und die Wahl des Partition-Keys sind der Kern der Design-Arbeit, denn sie bestimmen Ordering-Garantien und wie gleichmäßig sich Last auf Consumer verteilt. Kafka garantiert Ordering nur innerhalb einer Partition, daher brauchen Events, die relativ zueinander in Reihenfolge verarbeitet werden müssen, denselben Partition-Key, typischerweise eine Entity-ID. Wählt man den Key falsch, verliert man entweder benötigtes Ordering oder, häufiger, erzeugt eine heiße Partition, bei der das Volumen eines Keys den Rest überschattet und ein einzelner Consumer zum Flaschenhals für das gesamte Topic wird. Ich dimensioniere Consumer-Groups bewusst nach Partitionsanzahl, denn eine Group kann nie mehr aktive Consumer haben als Partitionen, und zusätzliche Consumer sitzen einfach untätig herum.",[10,26,28],{"id":27},"idempotenz-statt-duplikate","Idempotenz statt Duplikate",[15,30,31],{},"At-least-once-Zustellung ist der praktische Standard für Kafka, was Duplikate über einen ausreichend langen Zeitraum zur Gewissheit macht, sei es durch Producer-Retries oder Consumer-Rebalances. Ich entwerfe Consumer idempotent, statt zu versuchen, Exactly-once-Zustellung auf Broker-Ebene zu garantieren: Jeder Handler erzeugt denselben Endzustand, egal ob ein Event einmal oder zweimal verarbeitet wird, üblicherweise über einen Idempotenz-Key, der vor einem Seiteneffekt gegen einen Store geprüft wird. Genau diese Eigenschaft macht auch Replay sicher: Muss ich ein Topic je von einem früheren Offset neu verarbeiten, um einen Bug zu beheben, machen idempotente Consumer daraus ein Nicht-Ereignis statt eines Risikos für Datenkorruption.",[10,33,35],{"id":34},"für-durchsatz-betreiben","Für Durchsatz betreiben",[15,37,38],{},"Im Tagesgeschäft beobachte ich zwei Hebel: Retention und Consumer-Lag. Die Retention-Strategie (zeitbasiert, größenbasiert oder komprimiert für Topics, die aktuellen Zustand statt eines Event-Logs repräsentieren) wirkt sich direkt auf Speicherkosten und darauf aus, wie weit ein Replay zurückreichen kann. Consumer-Lag ist das mit Abstand nützlichste Gesundheitssignal, das ein Streaming-System liefert: Eine Consumer-Group, die hinter ihre produzierten Offsets zurückfällt, ist die früheste Warnung vor einem nachgelagerten Engpass, lange bevor von außen irgendetwas kaputt aussieht.",[10,40,42],{"id":41},"kernaussagen","Kernaussagen",[44,45,46,50,53,56],"ul",{},[47,48,49],"li",{},"Topic-Namensgebung, Schema-Evolution und Retention als explizite Entscheidungen behandeln, nicht als Defaults.",[47,51,52],{},"Die Wahl des Partition-Keys steuert Ordering und Lastverteilung zugleich. Falsch gewählt entstehen heiße Partitionen.",[47,54,55],{},"Für At-least-once-Zustellung entwerfen: idempotente Consumer machen Duplikate und Replay sicher.",[47,57,58],{},"Consumer-Lag als primäres Frühwarnsignal für die gesamte Pipeline überwachen.",{"title":60,"searchDepth":61,"depth":61,"links":62},"",2,[63,64,65,66,67],{"id":12,"depth":61,"text":13},{"id":20,"depth":61,"text":21},{"id":27,"depth":61,"text":28},{"id":34,"depth":61,"text":35},{"id":41,"depth":61,"text":42},"Tutorials","14. Juli 2026","md",{},true,3,"\u002Fblog\u002Fkafka-topic-design-idempotency",{"title":5,"description":60},"blog\u002Fkafka-topic-design-idempotency","Die Fehlermodi von Streaming-Systemen sind leise: Duplikate, heiße Partitionen, nachhinkende Consumer. Design-Entscheidungen, die das verhindern, vom Partition-Key bis zum replay-sicheren Consumer.","N0LIS9ozRrQQmyuFBlcLwLkJ_QN_CvBb4cHF-FdeTQI",[80,164,232],{"id":81,"title":82,"body":83,"category":68,"date":156,"description":60,"extension":70,"meta":157,"navigation":72,"order":158,"path":159,"seo":160,"stem":161,"summary":162,"__hash__":163},"blog\u002Fblog\u002Fgitops-argocd-helm-regulated-environments.md","GitOps mit ArgoCD und Helm: Auditierbare Releases in regulierten Umgebungen",{"type":7,"value":84,"toc":149},[85,89,101,105,108,112,119,123,130,132],[10,86,88],{"id":87},"warum-push-basierte-deployments-bei-audits-scheitern","Warum Push-basierte Deployments bei Audits scheitern",[15,90,91,92,96,97,100],{},"Ich sehe immer noch Teams, die per ",[93,94,95],"code",{},"kubectl apply"," vom Laptop nach Kubernetes deployen oder eine CI-Pipeline bei jedem Merge direkt in einen Cluster pushen lassen. Beides funktioniert, bis jemand die Frage stellt, die jede regulierte Umgebung irgendwann stellt: Was lief an einem bestimmten Datum in Produktion, wer hat es freigegeben, und können Sie das belegen? Bei Push-basierten Deployments lautet die ehrliche Antwort meist \"wir sind uns nicht ganz sicher\". Der tatsächliche Cluster-Zustand und der dokumentierte Soll-Zustand driften auseinander, sobald ein manuelles ",[93,98,99],{},"kubectl edit"," oder ein Notfall-Hotfix die Pipeline umgeht. Auditoren akzeptieren \"schauen Sie in die Deployment-Logs\" nicht als befriedigende Antwort, und ich sollte das auch nicht.",[10,102,104],{"id":103},"das-gitops-modell","Das GitOps-Modell",[15,106,107],{},"Die Lösung, zu der ich greife, ist GitOps: Der gewünschte Zustand jedes Clusters lebt in einem Git-Repository, und ein Reconciliation-Controller (ich nutze ArgoCD) vergleicht diesen deklarierten Zustand kontinuierlich mit dem, was tatsächlich läuft, und korrigiert jede Abweichung automatisch. Helm-Charts templaten die Kubernetes-Manifeste, sodass ein einzelnes Chart eine Anwendung beschreibt, während umgebungsspezifische Values-Dateien die Unterschiede zwischen Dev, Staging und Produktion liefern. Nichts erreicht einen Cluster außer über eine Änderung in Git, und jede Änderung in Git ist ein geprüfter Merge Request. Genau diese eine Einschränkung, nie direkter Cluster-Zugriff, macht aus \"vertrauen Sie mir\" ein \"hier ist der Commit\".",[10,109,111],{"id":110},"promotion-über-mehrere-umgebungen","Promotion über mehrere Umgebungen",[15,113,114,115,118],{},"Mit dieser Struktur wird die Promotion eines Releases zwischen Umgebungen vom Deploy-Skript zur Git-Operation. Dieselbe Chart-Version wandert von Staging nach Produktion, indem eine Values-Datei-Änderung gemerged wird, die den Image-Tag oder die Konfiguration für diese Umgebung anhebt. Ein Rollback ist ein ",[93,116,117],{},"git revert",", kein Gerangel um die vorherige Helm-Release-Nummer. Weil ArgoCD kontinuierlich abgleicht, folgt der Cluster in dem Moment, in dem der Revert landet, ohne separates Rollback-Tooling und ohne manuellen Eingriff. Das bedeutet auch: Die Promotion-Historie ist die Commit-Historie. Ich kann auf einen Pull Request zeigen und genau belegen, wann eine Version Produktion erreicht hat und wer sie freigegeben hat.",[10,120,122],{"id":121},"security-stages-in-ci","Security-Stages in CI",[15,124,125,126,129],{},"GitOps regelt, was nach der Freigabe einer Änderung passiert, aber ich will trotzdem Vertrauen in das haben, was vorgeschlagen wird. Ich lasse Build, Test und Security-Scanning als eigene Stages in GitLab CI laufen, bevor ein Image oder Chart überhaupt für eine Values-Datei-Änderung infrage kommt. Dependency-Scanning, Container-Image-Scanning und Policy-Checks gaten die Pipeline. Gebaute Artefakte werden in eine zentrale Registry gepusht und über einen unveränderlichen Tag referenziert, nie über ",[93,127,128],{},"latest",", sodass das, was in Git beschrieben ist, exakt dem entspricht, was deployt wird, ohne Zweifel darüber, welcher Build gerade läuft.",[10,131,42],{"id":41},[44,133,134,137,140,143,146],{},[47,135,136],{},"Deklarativer Soll-Zustand in Git schlägt imperative Deploy-Skripte für alles, was später auditiert werden muss.",[47,138,139],{},"Kein manueller Cluster-Zugriff. Jede Änderung an laufender Infrastruktur ist ein geprüfter, gemergter Commit.",[47,141,142],{},"Promotion und Rollback werden zu Git-Operationen: ein Merge oder ein Revert, kein Custom-Tooling.",[47,144,145],{},"Security-Scanning gehört in die CI, bevor eine Änderung überhaupt zum Deployment vorgeschlagen wird.",[47,147,148],{},"Der Audit-Trail ergibt sich daraus, wie das Deployment-Modell funktioniert, und ist damit kein separat zu pflegendes System.",{"title":60,"searchDepth":61,"depth":61,"links":150},[151,152,153,154,155],{"id":87,"depth":61,"text":88},{"id":103,"depth":61,"text":104},{"id":110,"depth":61,"text":111},{"id":121,"depth":61,"text":122},{"id":41,"depth":61,"text":42},"11. August 2026",{},1,"\u002Fblog\u002Fgitops-argocd-helm-regulated-environments",{"title":82,"description":60},"blog\u002Fgitops-argocd-helm-regulated-environments","Wie deklarative, Git-getriebene Deployments Multi-Environment-Releases überprüfbar, auditierbar und rückgängig machbar machen, und warum regulierte Branchen genau das brauchen.","3oE2eTcwu_WKNDa5PmYj6sMYl56pX1ZZJlTOafCJBjA",{"id":165,"title":166,"body":167,"category":224,"date":225,"description":60,"extension":70,"meta":226,"navigation":72,"order":61,"path":227,"seo":228,"stem":229,"summary":230,"__hash__":231},"blog\u002Fblog\u002Faws-multi-account-terraform.md","AWS-Multi-Account-Architekturen mit Terraform entwerfen",{"type":7,"value":168,"toc":217},[169,173,176,180,183,187,194,198,201,203],[10,170,172],{"id":171},"warum-ein-account-nie-genug-ist","Warum ein Account nie genug ist",[15,174,175],{},"Am Anfang ist es verlockend, alles in einem einzigen AWS-Account laufen zu lassen und IAM-Policies sowie Tags die Trennung übernehmen zu lassen. Von diesem Modell bin ich jedes Mal wieder abgerückt, denn eine Account-Grenze ist eine grundlegend stärkere Isolationsebene als eine Policy. Eine falsch konfigurierte IAM-Policy oder ein kompromittiertes Credential in einem Single-Account-Setup hat einen Blast-Radius, der die gesamte Umgebung umfasst: Produktion, Staging und geteiltes Tooling liegen alle hinter demselben Perimeter. Trennt man diese Workloads auf verschiedene Accounts, kann ein Fehler in einer Umgebung eine andere schlicht nicht erreichen. Es gibt keine Policy, mit der man sich an einer harten Account-Grenze vorbeikonfigurieren könnte. Es macht Least Privilege auch leichter nachvollziehbar (Berechtigungen sind auf das begrenzt, was ein Account enthält, statt Ressource für Ressource aufgezählt zu werden), und es macht Kostenzuordnung trivial, denn jeder Euro in einem Account gehört einem bekannten Team oder Workload zu, ohne dass Tagging-Disziplin die Hauptarbeit leisten muss.",[10,177,179],{"id":178},"eine-pragmatische-account-struktur","Eine pragmatische Account-Struktur",[15,181,182],{},"Die Struktur, auf die ich standardmäßig setze, hat einen Management-Account an der Wurzel rein für Billing und organisationsweite Policies, einen dedizierten Security- und Log-Archiv-Account, der Read-only-Kopien der Logs aller anderen Accounts erhält und selbst keine Workloads hält, einen Shared-Services-Account für Dinge wie eine Container-Registry oder CI-Runner, die jede Umgebung braucht, aber nicht selbst besitzen sollte, sowie Workload-Accounts pro Umgebung (Dev, Staging, Produktion), jeweils voneinander isoliert. Das ist nicht exotisch. Es spiegelt, was AWS Organizations und AWS Control Tower ohnehin erwarten, und es hält das mentale Modell einfach: Wenn man den Account benennen kann, weiß man, was in ihm erlaubt ist.",[10,184,186],{"id":185},"terraform-das-mit-ihnen-skaliert","Terraform, das mit Ihnen skaliert",[15,188,189,190,193],{},"Von Hand ist das alles nicht mehr handhabbar, sobald man mehr als zwei oder drei Accounts hat. Deshalb bilde ich die gesamte Struktur in Terraform ab: wiederverwendbare Module für die Teile, die sich über Accounts hinweg wiederholen (Networking, IAM-Baselines, Logging), sowie account- und umgebungsspezifischen State, der getrennt gehalten wird, damit eine Änderung in Staging niemals den State von Produktion berühren kann. Rollouts sind end-to-end automatisiert. Es gibt kein manuelles ",[93,191,192],{},"terraform apply"," von jemandes Laptop gegen einen produktiven Account. Muss sich etwas ändern, geschieht das jedes Mal über dieselbe geprüfte Pipeline, und genau das macht die Account-Struktur überhaupt erst vertrauenswürdig: Die Isolation ist nur so gut wie der Prozess, der sie pflegt.",[10,195,197],{"id":196},"iam-und-logging-grundlagen","IAM- und Logging-Grundlagen",[15,199,200],{},"Innerhalb dieser Struktur halte ich IAM-Rollen standardmäßig nach Least Privilege (Service-Rollen bekommen exakt die Berechtigungen, die ihr Workload braucht, nichts wird \"vorsichtshalber\" angenommen), und jeder Account schickt seine CloudTrail- und CloudWatch-Logs an den zentralen Log-Archiv-Account, wo sie aus Sicht der erzeugenden Accounts unveränderlich sind. Diese Kombination bedeutet, dass ein kompromittierter Workload-Account seine eigenen Spuren nicht löschen kann, und eine Analyse von \"was ist passiert\" hängt nie davon ab, dem untersuchten Account zu vertrauen.",[10,202,42],{"id":41},[44,204,205,208,211,214],{},[47,206,207],{},"Account-Grenzen isolieren den Blast-Radius auf eine Weise, die keine IAM-Policy allein leisten kann.",[47,209,210],{},"Ein kleines, zweckgebundenes Set an Accounts (Management, Security, Shared Services, Workload-Accounts pro Umgebung) deckt die meisten realen Bedürfnisse ab.",[47,212,213],{},"Terraform-Module mit getrenntem State pro Account halten die Struktur wartbar, während sie wächst.",[47,215,216],{},"Zentralisiertes, unveränderliches Logging in einem dedizierten Account lohnt sich, bevor man es braucht.",{"title":60,"searchDepth":61,"depth":61,"links":218},[219,220,221,222,223],{"id":171,"depth":61,"text":172},{"id":178,"depth":61,"text":179},{"id":185,"depth":61,"text":186},{"id":196,"depth":61,"text":197},{"id":41,"depth":61,"text":42},"Artikel","28. Juli 2026",{},"\u002Fblog\u002Faws-multi-account-terraform",{"title":166,"description":60},"blog\u002Faws-multi-account-terraform","Account-Grenzen sind Ihre stärkste Isolationsebene. Eine praxistaugliche Struktur für Workload-, Security- und Shared-Services-Accounts, vollständig in Terraform umgesetzt.","fzUXyAiHHlNkMQVwHMAItPMY8QdSTAHMwHlbMMKUBgQ",{"id":233,"title":234,"body":235,"category":224,"date":288,"description":60,"extension":70,"meta":289,"navigation":72,"order":290,"path":291,"seo":292,"stem":293,"summary":294,"__hash__":295},"blog\u002Fblog\u002Fllm-inference-aws-gpu-rag-bedrock.md","LLM-Inferenz auf AWS betreiben: GPU-Autoscaling, RAG und Bedrock",{"type":7,"value":236,"toc":281},[237,241,244,248,251,255,258,262,265,267],[10,238,240],{"id":239},"managed-vs-self-hosted","Managed vs. Self-Hosted",[15,242,243],{},"Die erste Architekturentscheidung, die ich bei jedem LLM-Projekt treffe, ist die Frage, ob ich einen Managed Service nutze oder Inferenz selbst betreibe, nicht die Wahl des Modells. Bedrock gibt mir verwalteten Zugriff auf eine Reihe von Foundation-Modellen, ohne GPU-Kapazität, Patching oder Scaling-Logik selbst zu besitzen, und für die meisten Produkt-Use-Cases ist das der richtige Standard: Ich will keine Model-Serving-Infrastruktur betreiben, wenn eine verwaltete API die Anforderungen an Latenz und Kontrolle erfüllt. Zu containerisierten GPU-Services wechsle ich, wenn ich etwas brauche, das Bedrock nicht bietet: ein bestimmtes fein-getuntes oder Open-Weight-Modell, engere Kontrolle über Batching und Latenz, oder Datenresidenz-Anforderungen, die einen geteilten Managed Endpoint ausschließen. Das ist ein echtes Infrastruktur-Commitment, deshalb gehe ich es nur ein, wenn der Managed-Weg die Anforderung wirklich nicht erfüllen kann.",[10,245,247],{"id":246},"gpu-workloads-autoscalen","GPU-Workloads autoscalen",[15,249,250],{},"Selbst gehostete GPU-Inferenz muss auf das richtige Signal skalieren, und CPU-Auslastung ist das falsche. Ein GPU-gebundenes Modell kann bei niedriger CPU liegen, während der eigentliche Engpass, die GPU selbst, ausgelastet ist. Ich skaliere containerisierte Inferenz-Services stattdessen nach Queue-Tiefe und Request-Latenz, damit das System auf das reagiert, was tatsächlich degradiert. GPU-Instances haben zudem echte Cold-Start-Kosten: Das Laden von Modellgewichten auf eine frische Instance dauert spürbar länger als ein typischer Container-Start. Deshalb halte ich eine warme Mindestkapazität, dimensioniert auf die erwartete Grundlast, statt von null zu skalieren, und lasse Autoscaling die Lastspitzen darüber hinaus abfangen.",[10,252,254],{"id":253},"rag-als-architekturmuster","RAG als Architekturmuster",[15,256,257],{},"Retrieval-Augmented Generation ist der Bereich, in den ich die meiste Design-Zeit stecke, weil es weniger ein Feature als eine Architekturentscheidung darüber ist, wo Wissen liegt. Statt sich darauf zu verlassen, was ein Modell während des Trainings gelernt hat, holt eine RAG-Pipeline zur Anfragezeit relevanten Kontext aus einer Vektordatenbank und speist ihn zusammen mit der Nutzeranfrage in den Prompt ein. Der Retrieval-Schritt liegt im Request-Pfad vor der Generierung (Anfrage embedden, Vektordatenbank nach den nächstliegenden Treffern durchsuchen, diesen Kontext in den Prompt zusammenstellen), was bedeutet, dass Retrieval-Latenz und -Qualität die Qualität der finalen Antwort direkt begrenzen. Chunking- und Embedding-Strategie upstream richtig hinzubekommen, zählt mehr als jedes Prompt-Tuning downstream davon.",[10,259,261],{"id":260},"kostenkontrolle-von-anfang-an","Kostenkontrolle von Anfang an",[15,263,264],{},"GPU-Kapazität ist teuer genug, dass Kosten von Beginn an eine Architekturfrage sein müssen, kein nachträglicher Aufräumdurchgang. Ich dimensioniere Instance-Typen nach dem tatsächlichen Speicher- und Durchsatzbedarf des Modells, statt standardmäßig zur größten verfügbaren GPU zu greifen, und route unterbrechungstolerante Arbeit (Batch-Embedding-Jobs, Offline-Evaluierung) auf Spot-Kapazität, während nur latenzsensitive Live-Inferenz auf On-Demand-Instances bleibt. Observability muss explizit Tokens und GPU-Auslastung abdecken, nicht nur Request-Anzahl und Antwortzeit, denn das sind die zwei Zahlen, die tatsächlich die Rechnung vorhersagen und verraten, ob die Kapazität richtig dimensioniert ist.",[10,266,42],{"id":41},[44,268,269,272,275,278],{},[47,270,271],{},"Standardmäßig verwalteten Modellzugriff über Bedrock nutzen. Zu selbst gehostetem GPU-Serving nur wechseln, wenn Kontrolle nötig ist, die Bedrock nicht bietet.",[47,273,274],{},"GPU-Inferenz nach Queue-Tiefe und Latenz skalieren, nicht nach CPU, und eine warme Mindestkapazität für Cold Starts vorhalten.",[47,276,277],{},"RAG ist ein Architekturmuster. Retrieval-Qualität upstream begrenzt Generierungsqualität downstream.",[47,279,280],{},"Token-Durchsatz und GPU-Auslastung explizit tracken, Spot-Kapazität für unterbrechungstolerante Batch-Arbeit nutzen.",{"title":60,"searchDepth":61,"depth":61,"links":282},[283,284,285,286,287],{"id":239,"depth":61,"text":240},{"id":246,"depth":61,"text":247},{"id":253,"depth":61,"text":254},{"id":260,"depth":61,"text":261},{"id":41,"depth":61,"text":42},"30. Juni 2026",{},4,"\u002Fblog\u002Fllm-inference-aws-gpu-rag-bedrock",{"title":234,"description":60},"blog\u002Fllm-inference-aws-gpu-rag-bedrock","Selbst gehostete GPU-Inferenz oder verwaltete Modelle über Bedrock? Ein Architekturblick auf den Produktivbetrieb von LLMs, inklusive RAG mit Vektordatenbanken und vernünftigen Kosten.","PnxWjfiqUVDFRdhqRYtwGGGbr8yj_QBxcRzp-VAmZu8",1790607906530]