46 Punkte von GN⁺ 2025-07-10 | 18 Kommentare | Auf WhatsApp teilen
  • Beim Neubau eines US-Vergleichssystems für Medicare-Krankenversicherungspläne wurde die Erfahrung geteilt, mit einer einfachen Architektur, die ausschließlich aus bewährten Technologien (Postgres, golang, React usw.) besteht, mehr als 1 Milliarde Webanfragen stabil verarbeitet zu haben
  • Die Architektur wurde mit dem Ziel von Einfachheit und Stabilität entworfen und erreichte eine durchschnittliche Antwortzeit von unter 10 ms sowie eine sehr niedrige Ausfallrate
  • Innovation Tokens wurden nur minimal dort eingesetzt, wo die strukturelle Trennung entscheidend war (3 große Module, gRPC-Kommunikation); ansonsten wurden bewusst langweilige, aber verlässliche Methoden gewählt
  • DB-Schema-Verwaltung, ETL-Pipeline, Tests, Logging, Dokumentation und CLI-Tools wurden durchgängig auf wiederholbare und einfache Weise aufgebaut, sodass ein System entstand, das das ganze Team leicht verstehen und warten kann
  • Das Beispiel zeigt anschaulich, dass kontinuierliche Qualitätssicherung und starke Teamarbeit auch bei großen Regierungsprojekten funktionieren

Serving a billion web requests with boring code

High level

  • Über zweieinhalb Jahre hinweg leitete der Autor die Entwicklung einer Website der US-Regierung zum Vergleichen und Kaufen von Medicare-Plänen
  • Verarbeitung von durchschnittlich 5 Millionen API-Anfragen pro Tag, mit einer mittleren Antwortzeit von unter 10 ms; 95 % der Anfragen blieben unter 100 ms
  • Die Ausfallhäufigkeit war extrem niedrig, sodass reale nächtliche Einsätze für Engineers an einer Hand abzuzählen waren
  • Ausschließlich mit bewährten Technologien wie Postgres, golang und React, die jeder verstehen kann, wurde schrittweise ein stabiles System aufgebaut

Boring über alles

  • Das oberste Prinzip war, nur „langweilige und bewährte Technologien“ zu priorisieren (Choose Boring Technology)
  • Versuche mit Innovation wurden nur dort unternommen, wo sie wirklich nötig waren, und Innovation Tokens wurden sparsam eingesetzt
  • Statt komplexer und spektakulärer Lösungen wurden stabile und klare Technologien und Prozesse bevorzugt

The boring bits

  • Postgres: Kern der Datenspeicherung, erfüllte sowohl Anforderungen an Zuverlässigkeit als auch an Skalierbarkeit. Auch komplexe Suchen (Faceted Search usw.) wurden mit Postgres gelöst
  • golang: Schnelle Builds und Deployments, klare Binärartefakte. Error Handling ist direkt nachvollziehbar, und neue Teammitglieder können sich leicht einarbeiten
  • React: Das am stärksten bewährte SPA-Framework, mit dem das Team bereits vertraut war. Auch Barrierefreiheit und Unterstützung verschiedener Geräte waren wichtige Faktoren
    • Langfristig gab es Probleme bei Bundle-Größe und sinkender Geschwindigkeit, aber unter den damaligen Bedingungen war es die beste Wahl, um rechtzeitig Ergebnisse zu liefern

The innovation tokens

  • Modular backend: Das gesamte Backend wurde weder als Microservices noch als Monolith aufgebaut, sondern als 3 große Module (druginfo, planinfo, beneinfo)
    • Jedes Modul nutzt eine eigene Postgres-Datenbank, und Datenaustausch erfolgt ausschließlich über gRPC
    • druginfo: Indexiert Medikamentenpreisdaten äußerst präzise, bei denen Kombinationen aus Apotheke, Versicherung, Verpackung usw. exponentiell anwachsen; dafür waren komplexe Vorverarbeitung und Performance-Optimierung nötig
    • planinfo: Empfängt täglich neue CMS-Daten und erstellt daraus jeweils die komplette Datenbank neu, um Unveränderlichkeit zu bewahren
    • beneinfo: Der einzige Bereich, der echte Teilnehmerdaten speichert; sensible PII (personenbezogene Daten) werden nur minimal gehalten. Design und Betrieb wurden so ausgerichtet, das Risiko von Datenlecks zu minimieren
  • gRPC: Bietet den Vorteil, Kommunikationsschnittstellen zwischen Modulen klar im Code definieren zu können. Sehr gut in Automatisierungswerkzeuge integrierbar
    • Allerdings wurden auch Nachteile erlebt: Build, Tooling und Debugging sind komplex, und im Vergleich zu JSON-APIs ist es weniger intuitiv
    • Über grpc-gateway wurden Webclients unterstützt und auch große Traffic-Mengen problemlos verarbeitet

Strict backwards compatibility

  • Abwärtskompatibilität von API und Datenbank wurde strikt eingehalten
    • Felder öffentlicher APIs werden niemals entfernt und bleiben, sofern kein Sicherheitsproblem vorliegt, dauerhaft bestehen
    • Auch DB-Spalten können zwar frei hinzugefügt werden, beim Entfernen gilt aber ein mehrstufiges Prüfverfahren (Referenzen entfernen → einige Wochen warten → tatsächlich löschen)
  • Diese Disziplin war die zentrale Grundlage für hohe Änderungsgeschwindigkeit sowie stabile Deployments und den laufenden Betrieb

Faceted search

  • Faceted Search nur mit Postgres statt mit ElasticSearch umgesetzt
    • Die gesamte Suchlogik wurde in einer einzigen Funktion mit 250 Zeilen umgesetzt, die Bedingungen auf eine gut indexierte plan-Tabelle kombiniert
    • Der Fokus lag auf den Geschäftsanforderungen, und die Lösung blieb ohne unnötige Komplexität einfach

Database

  • creation

    • Das DB-Schema wurde über nummerierte .sql-Dateien verwaltet, die in Reihenfolge geladen werden und so Zuverlässigkeit sicherstellen
    • Die planinfo-/beneinfo-Datenbanken werden täglich neu erstellt, Migrationen sind nicht nötig. Bei Konfigurationsfehlern wie Versionsabweichungen startet die Anwendung bewusst gar nicht erst
  • ETL

    • Daten werden per Shell-Skript je Quelle nach S3 geladen; per cron holen EC2-Instanzen den neuesten ETL-Code und die Daten ab und erzeugen eine neue RDS-Datenbank
    • Die COPY-Anweisung von Postgres wurde aktiv genutzt, um Massendaten effizienter als mit INSERT zu laden
    • Innerhalb von 2 bis 4 Stunden pro Tag konnten so Datenbanken mit hunderten Millionen Zeilen auf neue Versionen umgestellt werden
  • models

    • Mit der Bibliothek xo wurden DB-Modelle automatisch erzeugt; per Custom Templates wurde die Codegenerierung ans Team angepasst
  • testing

    • Der größte Fehler war, Tests mit sqlmock übermäßig auszubauen, sodass sie bei häufig wechselnden Daten sehr aufwendig zu pflegen waren
    • Bei einer real unveränderlichen Datenbank wären Tests gegen eine echte DB effizienter gewesen
  • Local database for development

    • Mit Skripten, die automatisch Teilmengen jeder Tabelle erzeugen, konnte jede Entwicklerin und jeder Entwickler mit einer kleinen lokalen DB auf Basis realer Daten testen und entwickeln
    • Solche Werkzeuge früh bereitzustellen, bevor die DB zu groß wird, maximiert die Entwicklungseffizienz des gesamten Teams

Miscellaneous tooling

  • Für verschiedenste Betriebs- und Observability-Automatisierungen wurden CLI-Tools als Shell-Skripte umgesetzt und sämtliche Utility-Funktionen zentral gebündelt
  • Praxisnahe Werkzeuge wurden aktiv entwickelt und genutzt, etwa um Splunk-Logs direkt per Slack-Befehl als Diagramme zu visualisieren

Logging

  • Beim Eintreffen einer Anfrage wird eine Request-ID erzeugt, die an alle Logging-Kontexte angehängt wird und so Nachverfolgung an jeder Stelle ermöglicht
  • Mit zerolog wurde ein sicheres und strukturiertes Logging-Design umgesetzt
  • An wichtigen Punkten wie Systemeintritt und -austritt oder Ausnahmesituationen werden zwingend Logs geschrieben

Documentation

  • GitHub-Markdown-Dokumente wurden mit sphinx-book-theme in ein Wiki-Book umgewandelt
  • Das gesamte Team trug aktiv zur Dokumentation bei, sodass sämtliche Systemdokumente an einer zentralen Stelle auffindbar waren
  • Eine starke Dokumentationskultur verbesserte Teamwachstum, Wartbarkeit und die Effizienz beim Onboarding neuer Mitarbeitender deutlich

Runtime integrations

  • Kundenwünsche, die die Performance des Clients verschlechtern konnten (z. B. das Einfügen von Analyse-Skripten), wurden nach Möglichkeit auf ein Minimum reduziert
  • Auch Queries wurden von Browser-Runtime auf Build-Time verlagert, um die Service-Performance zu erhalten
  • In der Praxis ließen sich allerdings nicht alle Kundenanforderungen abwehren, sodass einige tatsächlich zu Performance-Verlusten führten

And more

  • Es wird betont, dass neben der Technik vor allem eine positive, kooperative Teamatmosphäre und starke Motivation der eigentliche Antrieb für den Erfolg großer Systeme sind
  • Der Fall zeigte eindrücklich die Wirkung kleiner, aber wichtiger praktischer Entscheidungen und konsequenter Qualitätsarbeit

18 Kommentare

 
bugprone 2025-08-03

2,5 Jahre lang so etwas Langweiliges?!

 
kimjj81 2025-07-14

Ich habe mich gefragt, was Faceted Search ist, und bin dem nachgegangen; dort gibt es noch mehr Lesenswertes.

https://www.cybertec-postgresql.com/en/faceting-large-result-sets/
https://roaringbitmap.org/about/
https://github.com/cybertec-postgresql/pgfaceting

 
choijaekyu 2025-07-13

Die Meinungen zu „langweilig“ sind ja interessant, haha. Wenn man es anders ausdrücken wollte, was wäre gut? Vorhersehbar, gewöhnlich?

 
aqqnucs 2025-07-13

Die Übersetzung von boring mit „langweilig“ trifft die eigentliche Bedeutung leider überhaupt nicht. boringness ist eine der Go-Designphilosophien.

 
iolothebard 2025-07-11

Sooo langweilig …

 
sinbumu 2025-07-11

In Korea ist am Ende doch alles Java-Land, deshalb wirkt das wohl ungewohnt, haha

 
ethanhur 2025-07-10

Ich halte sowohl Golang als auch React für langweilige („boring“) Enterprise-Coding-Sprachen des neuen Zeitalters.

Da sich boring nicht zu 100 % treffend mit „langweilig“ übersetzen lässt, scheint die Nuance bei koreanischen Lesern nicht richtig anzukommen.

 
white9s 2025-07-10

Ich möchte in einer langweiligen Welt mit Postgres, golang und React leben.

 
helio 2025-07-11

Stimmt, ich dachte beim Lesen des Titels auch zuerst, das wäre ein Witz.

 
riki3 2025-07-10

Im Ausland scheint das ein langweiliger Stack zu sein.
Tatsächlich ist Go einfach die leichteste Wahl, wenn man einen Webserver bauen will …

Offenbar gilt es nur dann nicht als langweilig, wenn man mit Rust oder Sprachen aus dem FP-Bereich entwickelt.

 
kandk 2025-07-10

Allzu selbstverständliche Dinge … so selbstverständlich, dass man wichtige Punkte übersieht.

 
vwjdalsgkv 2025-07-10

Dieser Stack wirkt auf diesem Niveau gar nicht so langweilig. Wenn es wirklich langweilig wäre, müssten wohl eher Java 1.8 oder älter oder vielleicht VB auftauchen … so ein etwas respektloser Gedanke kommt mir dabei.

 
beoks 2025-07-10

>Das Schöne an der Banalität (so eingeschränkt) ist, dass die Fähigkeiten dieser Dinge gut verstanden sind. Aber noch wichtiger: Auch ihre Ausfallmodi sind gut verstanden.

Im Original gibt es einen Link zu boring; dem Inhalt nach scheint boring hier „so vertraut“ zu bedeuten.

 
beoks 2025-07-10

Es gäbe passendere Wörter wie experienced, verified oder skillful, aber dass hier unbedingt boring verwendet wurde, wirkt, als hätte das die Absicht gehabt, Aufmerksamkeit zu erregen.

 
cocofather 2025-07-10

Ist damit nicht eher gemeint, dass es kein langweiliger Stack zum Schreiben ist, sondern ein „Gukbap-Stack“, der langweilig wirkt, weil man ihn einfach zu oft geschrieben hat?

 
dongjinahn 2025-07-10

Etwa Linux-Kernel 2.6.29 ...

 
kandk 2025-07-10

Allein schon die Tatsache, dass gRPC verwendet wurde … haha

 
click 2025-07-10

Ich dachte auch zuerst: Go soll langweilig sein?
So etwas wie Classic ASP könnte man vielleicht als langweilig bezeichnen.