Direkt zum Hauptinhalt
Engineering

Was in den Millisekunden nach dem Tippen auf „Bezahlen“ passiert

Eine Anleitung für eine Databricks-App, die die Routenoptimierung von Model Serving, Lakebase und Autoscaling kombiniert, um Transaktionen im zweistelligen Millisekundenbereich zu bewerten – mit Code und Benchmarks auf jeder Ebene.

von Harsha Pasala und Subhadip Chanda

  • Eine Databricks-Beispiel-App (FastAPI + React), die Kreditkartentransaktionen in Echtzeit auf Betrug prüft. Sie nutzt die Routenoptimierung von Model Serving für Inferenz mit geringer Latenz und Lakebase Postgres für Online-Feature- und Profil-Lookups.
  • Schnelle Inferenz allein reicht nicht aus. Die App kombiniert routenoptimiertes Model Serving mit Lakebase sowie Connection Pooling, OAuth-Token-Rotation und Autoscaling-Mustern, die die Latenz unter Last stabil halten.
  • Bei 5.000 Anfragen antwortete der routenoptimierte Endpunkt End-to-End in 27 ms bei p50 und 37 ms bei p95, mit medianen Lakebase-Feature-Lookups von 8,9 ms und einer Erfolgsquote von 100 % – weit innerhalb der Latenzvorgaben für den Checkout.

Sie stehen an der Kasse. Sie halten Ihre Karte an das Terminal. Ein kleines Ladesymbol erscheint für vielleicht eine halbe Sekunde oder weniger, und dann wird „Genehmigt“ angezeigt. Oder auch nicht.

In dieser kurzen Zeit musste etwas entscheiden, ob diese Abbuchung nach Ihnen aussieht oder nach jemandem, der Ihre Kartennummer vor sechs Monaten bei einer Datenpanne gestohlen hat. Dieses Etwas musste Details über Sie wissen: Ihr Konsumverhalten, Ihr Tageslimit und ob Sie überhaupt Einkäufe im Ausland zulassen. Und all das musste so schnell gehen, dass Sie es gar nicht bemerkt haben.

In diesem Beitrag zeigen wir Ihnen, wie dieses „Etwas“ aussieht, wenn Sie es auf Databricks aufbauen. Wir führen Sie durch die „retail-app“, eine Beispielanwendung (FastAPI-Backend, React-Frontend, bereitgestellt als Databricks App), die zwei Plattformfunktionen miteinander verbindet:

  • Model Serving mit Routenoptimierung, ein schnellerer Netzwerkpfad zu Ihrem bereitgestellten Modell.
  • Lakebase, ein verwaltetes Postgres für die Profil- und Feature-Daten, die das Modell zum Zeitpunkt der Vorhersage benötigt, mit automatischer Skalierung, sodass sich die Datenbank an die Nachfrage anpasst, anstatt zum neuen Engpass zu werden.

Das vollständige Repository finden Sie auf GitHub. Sie können es forken, in Ihrem Workspace bereitstellen und selbst auf „Bezahlen“ tippen.

Der Ablauf: Was bei einer Transaktion tatsächlich passiert

Bevor wir uns den Code ansehen, hier der einfache Ablauf einer einzelnen Zahlung. Zwei Prüfungen laufen nacheinander ab: Ein Modell bewertet die Abbuchung, und anschließend prüft die App Ihre Profilregeln. Jede dieser Prüfungen kann die Transaktion ablehnen.

image2.png

Das Modell wird zuerst ausgeführt, da wir dessen Latenzwerte unabhängig vom Ergebnis erfassen möchten. Anschließend speist die Profilabfrage (tägliches Ausgabenlimit, Schalter für Auslandstransaktionen, Wohnsitzland) eine Reihe von If-Anweisungen. Die Antwort enthält die Zeitmessung für jeden Schritt, sodass Sie genau sehen können, wo die Millisekunden geblieben sind.

Das Aktualisieren Ihres Profils (Ändern Ihres Tageslimits, Aktivieren/Deaktivieren von Auslandstransaktionen) ist ein separater Vorgang. Sie speichern die Änderungen in der Datenbank, und die nächste Zahlung übernimmt sie direkt. Keine erneute Bereitstellung, keine Cache-Invalidierung.

Routenoptimierung: Warum der Netzwerkpfad entscheidend ist

Wenn ein Modell hinter Databricks Model Serving bereitgestellt wird, gibt es einen Netzwerk-Hop zwischen Ihrer Anwendung und dem Inferenz-Container. Bei Batch-Workloads spielen einige zusätzliche Millisekunden pro Anfrage keine Rolle. Für ein reibungsloses Bezahlerlebnis sind sie jedoch entscheidend.

Routenoptimierung verkürzt diesen Netzwerkpfad. Wenn Sie die Routenoptimierung für einen Endpunkt aktivieren, verbessert Databricks Model Serving den Netzwerkpfad für Inferenzanfragen. Dies führt zu einer schnelleren, direkteren Kommunikation zwischen Ihrem Client und dem Modell. Dieses optimierte Routing ermöglicht im Vergleich zu nicht optimierten Endpunkten mehr Abfragen pro Sekunde (QPS) und sorgt für stabilere und geringere Latenzen in Ihren Anwendungen.

Sie aktivieren sie bei der Erstellung des Endpunkts und führen Abfragen über den Data-Plane-Fluss mithilfe von OAuth durch, nicht über persönliche Zugriffstoken. Sie erhalten eine geringere Latenz und einen höheren Durchsatz bei gleicher Rechenleistung – genau das, was ein interaktiver Anwendungsfall zur Betrugserkennung (Fraud Scoring) benötigt.

In der Beispiel-App heißt der Endpunkt fraud-detection-lakebase. Hier sind die Konstante und die Funktion, die ihn aufruft:

Einige wichtige Punkte:

  • **serving_endpoints_data_plane.query**: Dies ist der Data-Plane-Abfragepfad, den die Routenoptimierung nutzt. Das Databricks SDK übernimmt im Hintergrund den OAuth-Token-Austausch.
  • **asyncio.to_thread**: Die Abfragemethode des SDKs ist synchron. Das Verpacken in to_thread hält die FastAPI-Ereignisschleife (Event Loop) frei, während das Modell ausgeführt wird.
  • **dataframe_records**: Die Payload ist eine Liste von Dictionaries (eines pro Zeile). Für die Betrugserkennung senden wir jeweils eine Transaktion.

Das Modell selbst gibt fraud_probability, fraud_flag und (entscheidenderweise) seine eigene interne Zeitmessung zurück: lookup_ms (wie lange die Feature-Abfrage im Modell-Container gedauert hat), inference_ms (CatBoost-Vorhersage) und total_ms. Das Backend leitet diese weiter, sodass das Frontend ein Latenz-Wasserfalldiagramm anzeigen kann:

Wenn Sie also die Latenzaufschlüsselung in der UI sehen („Modellinferenz: 45 ms“ mit darunter verschachtelter „Feature-Abfrage: 8 ms“), handelt es sich um die auf jeder Ebene gemessenen Werte, die in einer einzigen Antwort zusammengeführt wurden.

Weitere Informationen zur Einrichtung finden Sie unter: Routenoptimierung · Abfragen von routenoptimierten Endpunkten.

Lakebase: Postgres für die vom Modell benötigten Daten

Das Betrugsmodell betrachtet die Transaktion nicht isoliert. Es fragt die historischen Features des Kunden (durchschnittlicher Transaktionsbetrag, Grenzüberschreitungsquote, Chargeback-Rate, Transaktionshäufigkeit in den letzten 24 Stunden) ab, wobei die ersten sechs Ziffern der Kreditkarte (die BIN) als Abfrageschlüssel dienen. Diese Features befinden sich in einer Lakebase-Postgres-Tabelle namens customer_features.

Dies ist dieselbe Tabelle, aus der das Backend die Profildaten (Name, Tageslimit, Auslandsschalter) ausliest. Eine Tabelle, zwei Leser: Der Modell-Container liest Features für die Inferenz, die FastAPI-App liest Profilfelder für Geschäftsregeln.

Auf der Leseseite leiht sich das Backend eine Verbindung aus dem Pool, führt ein parametrisiertes SELECT nach user_id aus und gibt die Verbindung in einem finally-Block zurück. Einfaches psycopg2, aber die Disziplin beim Ausleihen und Zurückgeben ist entscheidend, wenn dies bei jeder Transaktion geschieht. Die Abfrage verwendet parametrisierte Platzhalter für Benutzereingaben, sodass der Abfrageschlüssel niemals direkt in das SQL eingefügt wird.

Auf der Schreibseite erstellt das Backend, wenn ein Benutzer sein Tageslimit ändert oder Auslandstransaktionen in der UI aktiviert/deaktiviert, ein dynamisches UPDATE aus einer Allowlist editierbarer Spalten. Nur Felder auf dieser Liste werden geschrieben; der Client kann keine beliebigen Spaltennamen einschleusen. Der Schreibvorgang wird mit autocommit = True ausgeführt, sodass die Änderung sofort sichtbar ist: Schon bei der nächsten Transaktion gilt das aktualisierte Limit, ohne dass auf einen Batch-Flush oder eine Cache-Invalidierung gewartet werden muss.

Connection-Pooling und OAuth-Token-Rotation

Jede Transaktion in dieser App greift mindestens zweimal auf Lakebase zu: einmal im Modell-Container für die Feature-Abfrage und einmal im Backend für die Profilprüfung. Jedes Mal eine neue Verbindung zu öffnen, würde bei jeder einzelnen Anfrage einen TCP-Handshake und eine TLS-Aushandlung bedeuten, was problemlos 20–50 ms Overhead pro Aufruf verursachen würde. Ein Connection-Pool hält eine Reihe von Verbindungen offen und bereit, sodass die meisten Anfragen einfach eine Verbindung übernehmen und direkt starten können.

So sieht das in der Praxis aus. Jede Datenbankoperation folgt demselben Muster aus Ausleihen, Abfragen und Zurückgeben:

Nutzen Sie eine Verbindung, führen Sie Ihre Abfrage aus und geben Sie die Verbindung in einem finally-Block zurück, damit sie immer zurückgegeben wird, selbst wenn ein Fehler auftritt. Jeder Lese- und Schreibvorgang in der App folgt diesem Muster.

Der Pool selbst ist ein psycopg2.pool.ThreadedConnectionPool mit 3–10 Verbindungen. Aber der Aufbau ist der Punkt, an dem es interessant wird, da Lakebase sich über OAuth authentifiziert. Die App tauscht die Anmeldedaten des Service Principals gegen ein Zugriffstoken aus und verwendet dann die Client-ID als Postgres-Benutzernamen und das Token als Passwort. Keine langlebigen Datenbankpasswörter.

Das bedeutet: Wenn das Token abläuft, können Sie nicht einfach das alte Passwort für die Verbindungen im Pool weiterverwenden, da diese bei der nächsten Abfrage fehlschlagen würden. Daher prüft _ensure_pool, ob sich das Token geändert hat, und erstellt gegebenenfalls einen neuen Pool:

Meistens wird der schnelle Pfad gewählt: Der Pool existiert, das Token hat sich nicht geändert und wir kehren sofort zurück. Wenn das Token rotiert, verhindert das Double-Check-Locking, dass zwei Threads gleichzeitig den Pool neu aufbauen, und der 30-Sekunden-Timer zum Schließen des alten Pools gibt laufenden Abfragen Zeit, beendet zu werden, bevor ihre Verbindungen verschwinden.

Die Modellseite: Feature-Lookup im Container

Das Betrugsmodell selbst (bereitgestellt als MLflow-pyfunc) führt zum Zeitpunkt der Vorhersage sein eigenes Lakebase-Lookup durch. Es extrahiert die Karten-BIN, fragt customer_features ab, erstellt einen Feature-Vektor und führt die CatBoost-Inferenz aus. Jeder Schritt wird zeitlich erfasst:

Der Modell-Container unterhält eine eigene ThreadedConnectionPool zu Lakebase (die Klasse LakebaseConnectionPool in fraud_model.py) mit Token-Aktualisierung im Hintergrund, damit der Pool über lang laufende Serving-Instanzen hinweg gültig bleibt. Dies ist dasselbe Muster wie beim Backend (Pool + OAuth-Rotation), läuft jedoch im Modell-Container und nicht im FastAPI-Prozess.

Diese Werte für lookup_ms und inference_ms fließen über die Serving-Antwort zurück durch das Backend in das Frontend. So erhalten Sie eine End-to-End-Transparenz: Das Modell meldet seine interne Zeitmessung, das Backend fügt seine eigene Echtzeitmessung hinzu und der Benutzer sieht alles.

Geschäftsregeln: die Profilprüfung

Nachdem das Modell die Transaktion bewertet hat, liest das Backend das Profil des Kunden aus Lakebase und wendet zwei einfache Regeln an. Zuerst vergleicht es den Transaktionsbetrag mit dem täglichen Ausgabenlimit des Benutzers. Wenn die Belastung das Limit überschreitet, wird die Transaktion mit einer Meldung abgelehnt, dass der Benutzer dieses in seinen Profileinstellungen erhöhen kann. Zweitens: Wenn der Benutzer internationale Transaktionen deaktiviert hat, prüft das Backend, ob das Land der Transaktion mit dem Wohnsitzland des Benutzers übereinstimmt. Eine Abweichung führt zu einer Ablehnung.

Jede der beiden Regeln kann eine Modellfreigabe überschreiben. Eine Transaktion, die das Modell für in Ordnung hält, kann dennoch abgelehnt werden, weil der Benutzer ein tägliches Limit von 500 $ festgelegt hat. Das ist so gewollt. Das Modell befasst sich mit dem statistischen Risiko, das Profil mit den Benutzerpräferenzen. Beide lesen aus derselben Lakebase-Tabelle, dienen jedoch unterschiedlichen Zwecken.

Die für das Profil-Lookup und die Regelprüfungen aufgewendete Zeit wird als business_logic_ms erfasst und zusammen mit den Modell-Zeiten zurückgegeben, sodass Sie genau sehen können, wie viel Overhead die Geschäftslogik für jede Transaktion verursacht.

Lakebase-Autoscaling mit Scale-to-Zero: Bewältigung der Nachfrage

In der Produktionsumgebung muss Ihre Postgres-Instanz sowohl die Feature-Lookups des Modell-Containers als auch die Profil-Lesezugriffe des Backends verarbeiten – in Spitzenzeiten potenziell viele davon pro Sekunde. Lakebase skaliert automatisch und passt die Rechenleistung innerhalb eines konfigurierten Min/Max-Bereichs an. So zahlen Sie um 3 Uhr morgens nicht für Spitzenkapazitäten, verlieren aber auch mittags keine Abfragen.

In den folgenden Benchmark-Ergebnissen spiegeln die konsistenten einstelligen Lookup-Zeiten bei p50 bis p75 wider, was eine aufgewärmte Lakebase-Instanz unter gleichmäßiger Last liefert. Der Sprung bei p95 (13,9 ms) is typisch für Fluktuationen im Verbindungspool oder kurze Scale-up-Ereignisse, liegt aber immer noch gut im Latenzbudget für einen Checkout-Flow und ist genau die Art von Spitze, die das Autoscaling abfängt, bevor sie für den Benutzer sichtbar wird. Wenn Scale-to-Zero aktiviert ist, zahlen Sie auch dann nichts mehr, wenn keine Transaktionen fließen.

Zusammenfassung: Aufschlüsselung der End-to-End-Latenz

Hier ist das vollständige Latenzbild für eine einzelne Transaktion:

MessungWas erfasst wirdWo gemessen wird
model_call_msReale Zeit für den gesamten Serving-AufrufBackend (router.py)
model_lookup_msFeature-Lookup im Modell-ContainerModell (fraud_model.py)
model_interfere_msCatBoost-VorhersagezeitModell (fraud_model.py)
model_total_msGesamtzeit im Modell-ContainerModell (fraud_model.py)
business_logic_msProfil-Lesezugriff + RegelprüfungBackend (router.py)
backend_total_msReale Zeit vom Start der Anfrage bis zum Aufruf des BetrugsmodellsBackend (router.py)

Die Lücke zwischen round_trip_ms und model_total_ms ist der Netzwerk-Overhead, und genau hier hilft die Routenoptimierung. Die Lücke zwischen backend_total_ms und model_call_ms ist der Framework-Overhead (Serialisierung, Routing usw.).

Wenn Sie die App ausführen und eine Transaktion senden, zeigt die UI die wichtigsten Werte an: Modell-Inferenz, Feature-Lookup und Geschäftslogik. So lässt sich leicht erkennen, welchen Unterschied die Routenoptimierung macht, oder zeigen, dass ein Lakebase-Feature-Lookup nur einstellige Millisekunden beansprucht und nicht Hunderte, wie man es von einer kalten Datenbankverbindung erwarten würde.

Ergebnisse: Wie schnell ist es wirklich?

Wir haben 5.000 aufeinanderfolgende Anfragen (Gleichzeitigkeit = 1, 50 ms Verzögerung zwischen den Aufrufen) an den routenoptimierten fraud-detection-lakebase-Endpunkt (CPU, Workload-Größe „Small“, einzelne Azure-Region) gesendet und die Latenz auf jeder Ebene erfasst, vom Modell-Container bis zum Roundtrip des Aufrufers. Das Ziel bestand darin, die Latenzanatomie pro Anfrage zu isolieren – also zu sehen, wohin die Millisekunden auf jeder Ebene fließen (Feature-Lookup, Inferenz, Netzwerk-Overhead) –, anstatt den Durchsatz unter Last zu testen. Diese Zahlen stammen aus dem Benchmark-Skript (scripts/benchmark.py), das den Modell-Endpunkt direkt aufruft. Die UI-Latenzaufschlüsselung zeigt einen anderen Ausschnitt (Modell-Inferenz, Feature-Lookup und Geschäftslogik), gemessen über die gesamte Backend-Route.

MetrikWas gemessen wirdp50p75p90p95
Feature-Lookup (model_lookup_ms)Lakebase-Lesezugriff im Modell-Container8,9 ms9,8 ms11,7 ms13,9 ms
Inferenz (model_inference_ms)CatBoost-Vorhersage0,4 ms0,5 ms1,6 ms6,0 ms
Gesamtmodellzeit (model_total_ms)Lookup + Inferenz + Container-Overhead9,5 ms10,9 ms14,9 ms17,6 ms
End-to-End-Roundtrip (round_trip_ms)Vollständiger Data-Plane-Aufruf vom Aufrufer bis zur Antwort27,2 ms29,6 ms33,8 ms37,3 ms
Netzwerk-Overhead (round_trip_ms - model_total_ms)Roundtrip minus Modellzeit17,4 ms18,5 ms19,8 ms21,1 ms

Einige Dinge fallen auf:

  • Der End-to-End-Roundtrip liegt im Median bei 27 ms und bei p95 bei 37 ms. Das ist der gesamte Weg: Aufrufer → routenoptimierte Data Plane → Modell-Container → Lakebase-Lookup → CatBoost-Inferenz → Antwort. Liegt absolut im Latenzbudget für einen Checkout-Prozess.
  • Der Feature-Lookup liegt bei p50 im einstelligen Millisekundenbereich (8,9 ms). Der Connection-Pool des Modells zu Lakebase hält die Verbindungen warm, sodass die meisten Lesevorgänge den TLS-Handshake komplett überspringen. Selbst bei p95 bleibt der Lookup unter 14 ms.
  • Die Inferenz ist praktisch kostenlos. Die CatBoost-Vorhersage auf einem Vektor mit 12 Features dauert im Median 0,4 ms. Die Zeit des Modells wird durch den Feature-Lookup dominiert, nicht durch die Vorhersage selbst.
  • Der Netzwerk-Overhead beträgt ~17 ms. Die Differenz zwischen dem, was der Modell-Container meldet, und dem, was der Aufrufer sieht, ist die Serving-Infrastruktur: Request-Routing, Serialisierung und der Data-Plane-Hop. Die Routenoptimierung sorgt hier für Konsistenz: Die Spanne zwischen p50 und p95 beträgt nur 4 ms.

Probieren Sie es selbst aus: Stellen Sie die App in Ihrem Workspace bereit

Die App ist als Databricks-App (FastAPI-Backend, React-Frontend) mit apx erstellt. Installieren Sie sie mit:

Sie müssen außerdem die Databricks-CLI-Authentifizierung für den Workspace konfigurieren, in dem der Model-Serving-Endpunkt und die Lakebase-Instanz bereitgestellt werden.

Lokal ausführen:

Im Workspace bereitstellen:

Die wichtigsten Dateien:

  • src/retail_app/backend/router.py: Transaktionsendpunkt, Betrugsprüfung, Geschäftsregeln
  • src/retail_app/backend/postgres.py: Lakebase-Connection-Pool, Profil-CRUD
  • model_training/fraud_model.py: MLflow-pyfunc mit Feature-Lookup und CatBoost
  • app.yml: Bereitstellungskonfiguration (Uvicorn-Entrypoint, Umgebungsvariablen)

Zugehörige Dokumentation

Echtzeit-Anwendungsfälle mit Latenzanforderungen von unter 50 ms wie Betrugsbewertung (Fraud Scoring), Personalisierung und dynamische Preisgestaltung können nativ auf Databricks erstellt werden. Die Routenoptimierung von Model Serving und Lakebase bringen den Inferenzpfad und den Datenpfad auf dieselbe kontrollierte Plattform. Wenn Sie bisher dachten, dass eine Lakehouse-Architektur keine Latenzen auf Checkout-Niveau erreichen kann, sind die Benchmark-Zahlen hier (27 ms Median End-to-End mit einstelligen Feature-Lookups) einen zweiten Blick wert. Wenn ein Echtzeit-Workload bisher auf der Liste „Zu schwierig“ stand, ist jetzt der richtige Zeitpunkt, dies noch einmal zu überdenken. Stellen Sie die App in Ihrem eigenen Workspace bereit, um den Latenz-Wasserfall selbst zu sehen, und erkunden Sie Lakebase und Databricks Model Serving.

(Dieser Blogbeitrag wurde mit KI-gestützten Tools übersetzt.) Originalbeitrag

Erhalten Sie die neuesten Beiträge in Ihrem Posteingang

Abonnieren Sie unseren Blog und erhalten Sie die neuesten Beiträge direkt in Ihren Posteingang.