Optimieren von Modellbereitstellungsendpunkten für die Produktion

Erfahren Sie, wie Sie Die Modellbereitstellungsendpunkte für Produktionsworkloads optimieren, die hohen Durchsatz, niedrige Latenz und zuverlässige Leistung erfordern.

Optimierungsstrategien sind in drei Kategorien unterteilt:

Wann Sie Ihren Endpunkt optimieren sollten

Erwägen Sie die Optimierung Ihres Model Serving-Endpunkts, wenn Sie auf eines der folgenden Szenarien stoßen:

  • Hohes Abfragevolumen: Ihre Anwendung sendet mehr als 50k-Abfragen pro Sekunde (QPS) an einen einzelnen Endpunkt.
  • Latenzanforderungen: Ihre Anwendung erfordert Unter-100 ms-Antwortzeiten.
  • Skalierungsengpässe: Endpunkte stehen in Warteschlangen oder geben HTTP 429-Fehler während Datenverkehrsspitzen zurück.
  • Kostenoptimierung: Sie möchten die Kosten senken und gleichzeitig Leistungsziele beibehalten.
  • Produktionsvorbereitung: Sie bereiten sich darauf vor, von der Entwicklung zu Produktionsworkloads zu wechseln.

Infrastrukturoptimierungen

Infrastrukturoptimierungen verbessern Netzwerkrouting, Skalierungsverhalten und Computekapazität.

Routenoptimierung

Die Routenoptimierung bietet die wichtigste Infrastrukturverbesserung für Workloads mit hohem Durchsatz. Wenn Sie die Routenoptimierung auf einem Endpunkt aktivieren, verbessert Databricks Model Serving den Netzwerkpfad für Rückschlussanforderungen, was zu einer schnelleren, direkteren Kommunikation zwischen Clients und Modellen führt.

Leistungsvorteile:

Merkmal Standardendpunktgrenze Routenoptimierter Endpunktgrenzwert
Abfragen pro Sekunde (QPS) pro Arbeitsbereich 200 50.000+ (Kontaktieren Sie Databricks für höhere Limits)
Clientkoncurrency pro Arbeitsbereich 192-1024 (variiert je nach Region) Kein expliziter Grenzwert (begrenzt durch bereitgestellte Parallelität)
Endpunkt bereitgestellte Parallelität pro bediente Entität 1,024 1.024 (Kontaktieren Sie Databricks für höhere Grenzwerte)

Gründe für die Verwendung der Routenoptimierung:

  • Workloads, die mehr als 200 QPS erfordern
  • Anwendungen mit strengen Latenzanforderungen (Unter-50 ms Overhead)
  • Produktionsbereitstellungen, die mehrere gleichzeitige Benutzer bedienen

Von Bedeutung

Die Routenoptimierung ist nur für benutzerdefinierte Modellbereitstellungsendpunkte verfügbar. Foundation-Modell-APIs und externe Modelle unterstützen keine Routenoptimierung. OAuth-Token sind für die Authentifizierung erforderlich; Persönliche Zugriffstoken werden nicht unterstützt.

Anleitungen zur Einrichtung finden Sie unter Routenoptimierung bei Bereitstellungsendpunkten und Details zum Abfragen unter routeoptimierte Bereitstellungsendpunkte abfragen.

Bereitgestellte Parallelität

Die bereitgestellte Parallelität steuert, wie viele gleichzeitige Anforderungen Ihr Endpunkt verarbeiten kann. Konfigurieren Sie die bereitgestellte Parallelität basierend auf den erwarteten QPS- und Latenzanforderungen.

Konfigurationsrichtlinien:

  • Minimale Parallelität: Legen Sie sie hoch genug fest, um den Basisverkehr ohne Warteschlangen zu verarbeiten.
  • Maximale Parallelität: So hoch festlegen, dass Datenverkehrsspitzen bewältigt werden können, während die Kosten kontrolliert werden.
  • Automatische Skalierung: Automatische Skalierung aktivieren, um die Kapazität basierend auf Bedarf dynamisch anzupassen

Berechnen der erforderlichen Parallelität:

Required Concurrency = Target QPS × Average Latency (seconds)

Wenn Ihr Ziel beispielsweise 100 QPS mit einer durchschnittlichen Latenz von 200 ms beträgt:

Required Concurrency = 100 × 0.2 = 20

Verwenden Sie Auslastungstests , um die tatsächliche Latenz zu messen und optimale Parallelitätseinstellungen zu ermitteln.

Instanztypen

Wählen Sie Instanztypen basierend auf den Computeanforderungen Ihres Modells aus:

Instanztyp Am besten geeignet für: Trade-offs
CPU (Klein, Mittel, Groß) Einfache Modelle, einfache Rückschlusslogik Niedrigere Kosten, langsamer für rechenintensive Modelle
GPU (Klein, Mittel, Groß) Große Modelle, komplexe Berechnungen, Bild-/Videoverarbeitung Höhere Kosten, optimale Leistung für Deep Learning

Tipp

Beginnen Sie mit CPU-Instanzen für Entwicklung und Tests. Wechseln Sie nur dann zu GPU-Instanzen, wenn Sie eine hohe Ableitungslatenz beobachten oder ihr Modell eine spezielle Berechnung erfordert (z. B. Deep Learning-Vorgänge).

Modelloptimierungen

Modelloptimierungen verbessern die Ableitungsgeschwindigkeit und die Ressourceneffizienz.

Modellgröße und Komplexität

Modellgröße und Komplexität: Kleinere, weniger komplexe Modelle führen in der Regel zu schnelleren Rückschlüssen und höheren QPS. Berücksichtigen Sie Techniken wie Modellquantisierung oder Beschnitt, wenn Ihr Modell groß ist.

Batchverarbeitung

Wenn Ihre Anwendung mehrere Anforderungen in einem einzigen Aufruf senden kann, aktivieren Sie die Batchverarbeitung auf der Clientseite. Dies kann den Aufwand pro Vorhersage erheblich reduzieren.

Vorverarbeitung und Nachbearbeitungsoptimierung

Lagern Sie komplexe Vorverarbeitungs- und Nachbearbeitungsschritte von den Diensten bereitgestellten Endpunkten aus, um die Last auf die Inference-Infrastruktur zu reduzieren.

Clientseitige Optimierungen

Clientseitige Optimierungen verbessern, wie Anwendungen mit bereitstellenden Endpunkten interagieren.

Verbindungspooling

Durch die Verbindungspooling werden vorhandene Verbindungen wiederverwendet, anstatt neue Verbindungen für jede Anforderung zu erstellen, wodurch der Aufwand erheblich reduziert wird.

  • Verwenden des Databricks SDK, das automatisch bewährte Methoden für die Verbindungspooling implementiert
  • Wenn Sie benutzerdefinierte Clients verwenden, implementieren Sie den Verbindungspool selbst.

Fehlerbehandlung und Wiederholungsstrategien

Implementieren Sie eine robuste Fehlerbehandlung, um temporäre Fehler ordnungsgemäß zu behandeln, insbesondere bei automatischen Ereignissen oder Netzwerkunterbrechungen.

Optimierung der Nutzlastgröße

Minimieren Sie die Anforderungs- und Antwortnutzlastgrößen, um die Netzwerkübertragungszeit zu reduzieren und den Durchsatz zu verbessern.

Messen und Verbessern der Leistung

Leistungsüberwachung

Überwachen der Endpunktleistung mithilfe der tools, die von Model Serving bereitgestellt werden:

Metric Was sie misst Ziel Maßnahme bei Überschreitung
Latenz (P50, P90, P99) Antwortzeit für Anforderungen Anwendungsabhängig (in der Regel <100-500 ms) Suchen nach Warteschlangen, Optimieren des Modells oder Clients
Durchsatz (QPS) Abgeschlossene Anfragen pro Sekunde Abhängig von der Arbeitslast Aktivieren der Routenoptimierung, Erhöhen der bereitgestellten Parallelität
Fehlerrate Prozentsatz der fehlgeschlagenen Anforderungen <1% Überprüfen von Dienstprotokollen, Überprüfen auf Kapazitätsprobleme
Warteschlangenlänge Anforderungen, die auf die Verarbeitung warten 0 (keine Warteschlange) Erhöhen der bereitgestellten Parallelität oder Aktivieren der automatischen Skalierung
CPU-/Arbeitsspeicherauslastung Ressourcenverwendung <80% Instanztyp skalieren oder Parallelität erhöhen

Weitere Informationen zum Überwachen der Modellqualität und der Endpunktintegrität finden Sie unter "Überwachen der Modellqualität" und "Endpunktintegrität " sowie " Nachverfolgen und Exportieren von Endpunktintegritätsmetriken nach Prometheus" und "Datadog ", um Metriken in Observability-Tools zu exportieren.

Auslastungstests

Load-Tests messen die Endpunktleistung (Performance des Endpunkts) unter realistischen Verkehrsbedingungen und ermöglichen es Ihnen:

  • Ermitteln optimal bereitgestellter Parallelitätseinstellungen
  • Erkennen von Leistungsengpässen
  • Überprüfen der Latenz- und Durchsatzanforderungen
  • Verstehen Sie die Beziehung zwischen Clientnebenläufigkeit und Servernebenläufigkeit

Siehe Ladentests für die Bereitstellung von Endpunkten.

Häufige Leistungsprobleme beheben

Queuing

Die Modellbereitstellung unterstützt die automatische Skalierung, um die Kapazität basierend auf Datenverkehrsmustern anzupassen. Plötzlicher Datenverkehrsanstieg kann jedoch zu Warteschlangen führen, da die automatische Skalierung Zeit erfordert, um erhöhte Last zu erkennen und zusätzliche Kapazität bereitzustellen. Während dieses Zeitraums können eingehende Anforderungen vorübergehend die verfügbare Kapazität überschreiten, was dazu führt, dass Anforderungen in die Warteschlange gestellt werden.

Queuing tritt auf, wenn die Anforderungsrate oder Parallelität die aktuelle Verarbeitungskapazität des Endpunkts übertrifft. Dies geschieht in der Regel bei starken Datenverkehrsspitzen, Arbeitslastspitzen oder wenn der Endpunkt über unzureichende zugewiesene Parallelität verfügt. Mithilfe von Modellbereitstellungsendpunkten können temporäre Warteschlangen zur Handhabung von Anfragenüberlastungen genutzt werden, aber über einen definierten Schwellenwert hinaus gibt der Endpunkt HTTP 429-Fehler (Zu viele Anfragen) zurück, um die Systemstabilität zu schützen.

Warteschlangen erhöhen die Latenz, da in die Warteschlange eingereihte Anforderungen warten, bevor sie verarbeitet werden. So minimieren Sie die Warteschlangen:

  • Legen Sie die minimale bereitgestellte Kapazität hoch genug fest, um den Basis-Datenverkehr und typische Spitzenlasten zu bewältigen.
  • Aktivieren der Routenoptimierung für höhere Kapazitätsgrenzen
  • Implementieren von Wiederholungslogik mit exponentiellem Backoff in Ihren Clientanwendungen

Externe API-Engpässe

Modelle rufen häufig externe APIs für Datenanreicherung, Featureabruf oder andere Aufgaben während der Ableitung auf. Diese externen Abhängigkeiten können zu Leistungsengpässen werden:

  • Latenz: Messen Sie die Antwortzeit jedes externen API-Aufrufs. Hohe Latenz bei diesen Aufrufen erhöht direkt die Gesamtlatenz bei der Bereitstellung und reduziert den Durchsatz.
  • Durchsatzgrenzwerte: Externe APIs können Geschwindigkeitsbeschränkungen oder Kapazitätsbeschränkungen auferlegen. Das Überschreiten dieser Grenzwerte kann zu Drosselung, Fehlern und Leistungsbeeinträchtigungen führen.
  • Fehlerraten: Häufige Fehler von externen APIs können Wiederholungsversuche auslösen und die Last für Den bereitgestellten Endpunkt erhöhen.
  • Zwischenspeichern: Implementieren Sie die Zwischenspeicherung für häufig verwendete Daten aus externen APIs, um die Anzahl der Anrufe zu reduzieren und die Reaktionszeiten zu verbessern.

Überwachen Sie diese Faktoren, um Engpässe zu identifizieren und gezielte Optimierungen für Workloads mit hohem Durchsatz zu implementieren.

Blockierende Aufrufe im Modellcode auf CPU-Endpunkten

Bei CPU-Custom-Model-Serving-Endpunkten, die gevent-Worker verwenden, kann ein Aufruf, der in kompiliertem Code blockiert, jede Anfrage auf diesem Worker blockieren, selbst wenn der Aufruf in einem Hintergrundthread ausgeführt wird. Um dies zu vermeiden, führen Sie solche Aufrufe in einem separaten Pool von Betriebssystem-Threads aus.

Ein gevent-Worker kann mehrere Anfragen gleichzeitig erfüllen. Python-Threads, die dein Modellcode startet, einschließlich threading.Thread und concurrent.futures.ThreadPoolExecutor, laufen als kooperative gevent-Tasks im Worker-Thread. Sie schalten nur bei Aufrufen, die gevent kooperativ ermöglicht, wie Socket-I/O, time.sleep, und Sperren, sodass reine Python-Netzwerk-I/O, zum Beispiel mit requests, wie erwartet funktioniert. Ein Aufruf, der in kompiliertem Code wie einer C-, C++- oder Rust-Erweiterung, einigen Datenbanktreibern oder einigen SDKs blockiert, gibt die Ausführung nicht frei, sodass der gesamte Worker blockiert wird, bis er zurückkehrt. Ein häufiges Symptom sind Latenzspitzen oder Timeouts bei vielen Anfragen gleichzeitig, die zeitlich mit einem langsamen Downstream-Dienst zusammenfallen.

Um zu prüfen, ob dein Endpunkt gevent-Worker verwendet, logge gevent.monkey.is_module_patched("threading"), wenn dein Modell geladen wird. Bei Endpunkten, die kein gevent verwenden, verzögert ein blockierender Aufruf nur die Anfrage, die ihn ausgelöst hat.

Der folgende Helfer führt einen Aufruf auf einem dedizierten Pool von OS-Threads aus, wenn gevent aktiv ist, und ruft ihn ansonsten direkt auf:

_pool = None


def run_blocking(fn, *args, **kwargs):
    """Run fn on an OS thread when gevent is active. Otherwise, call fn directly."""
    try:
        from gevent import monkey
        from gevent.threadpool import ThreadPool
    except ImportError:
        return fn(*args, **kwargs)
    if not monkey.is_module_patched("threading"):
        return fn(*args, **kwargs)
    global _pool
    if _pool is None:
        _pool = ThreadPool(8)
    return _pool.apply(fn, args, kwargs)

Zum Beispiel in einem Hintergrundthread, der Datensätze mit einem SDK-Client schreibt, der in kompiliertem Code wartet, run_blocking(client.write, record) statt client.write(record) aufrufen. Beachten Sie Folgendes:

  • fn läuft auf einem anderen Thread als der Aufrufer, und mehrere Aufrufe können gleichzeitig ausgeführt werden. Verwenden Sie es nur mit thread-sicheren Objekten, erstellen Sie threadgebundene Objekte wie Datenbankverbindungen innerhalb fnund übergeben Sie anforderungsspezifische Werte als Argumente. contextvars und die thread-lokalen Werte, die der Aufrufer festlegt, sind innerhalb von fn nicht sichtbar. Rufe run_blocking aus dem Python-Code, den dein Modell ausführt, nicht aus einem Callback, der von einer kompilierten Bibliothek auf ihrem eigenen Thread ausgeführt wird.
  • Setze direkt für den blockierenden Aufruf ein Timeout. Ein Pool-Thread kann nicht abgebrochen werden, daher behält ein Aufruf, der nie zurückkehrt, seinen Thread. Wenn alle Pool-Threads besetzt sind, warten neue Aufrufe auf einen freien Thread.
  • Offloading hilft nur, wenn der kompilierte Aufruf die Python Global Interpreter Lock (GIL) freigibt, während er wartet.
  • Wenn fn eine Ausnahme auslöst, löst run_blocking sie beim Aufrufer aus.

Weitere Ressourcen