Auf dieser Seite finden Sie Tipps zum Schreiben von Service Extensions-Plug-ins, die korrekt sind, eine gute Leistung bieten und gut isoliert sind. Die Korrektheit ist von entscheidender Bedeutung, da Plug-ins in einer eingeschränkten Engine-Sandbox mit einer begrenzten API-Oberfläche ausgeführt werden. Die Leistung ist von entscheidender Bedeutung, da Plug-ins während Endnutzeranfragen mit geringen Ressourcenmengen ausgeführt werden. Die Isolation erfolgt auf Projektebene.
Erste Schritte
Mit den Beispielen beginnen
Unterstützte APIs verwenden
Funktionstests und Benchmarks ausführen
Mit den Beispielen beginnen
Ein guter Ausgangspunkt sind unsere Plug-in-Codebeispiele. Dies sind Beispiele für gängige Plug-in-Muster, z. B. das Parsen von Pfaden oder Abfragen, das Umschreiben von Headern, benutzerdefiniertes Logging und benutzerdefinierte Authentifizierung.
Unterstützte APIs verwenden
Plug-ins müssen für die Proxy-Wasm-Binärschnittstelle (ABI) kompiliert werden. Diensterweiterungen unterstützen eine Teilmenge der Proxy-Wasm-ABI, die HTTP-Header- und ‑Textänderungen, lokale Antworten, benutzerdefinierte Protokollierung und Plug-in-Konfiguration umfasst. Proxy-Wasm unterstützt auch eine kleine Teilmenge von WASI-Vorabversion 1, einschließlich stdout und stderr für das Logging sowie clock_time_get und random_get.
Diensterweiterungen unterstützen keine Zeitgeber, benutzerdefinierten Messwerte, freigegebenen Daten, freigegebenen Warteschlangen oder ausgehenden Netzwerkaufrufe. Serviceerweiterungen unterstützen auch keine Rückgabewerte für Plug-in-Callbacks, mit denen versucht wird, die Verarbeitung von Anfragen zu pausieren. Diese werden ignoriert.
Funktionstests und Benchmarks ausführen
Um die Richtigkeit und Leistung zu bewerten, stellen wir ein lokales Plug-in-Testtool zur Verfügung, mit dem Sie Ihr Plug-in ausführen, testen und benchmarken können. Sie rufen dieses Tool in einem Docker-Container auf und übergeben ein Plug-in-Binärprogramm sowie ein Text-Proto mit Eingaben und Erwartungen. Weitere Informationen finden Sie in der Dokumentation zum lokalen Tester und im Beispiel für Testeingaben.
Richtigkeit
Verlassen Sie sich nicht auf Uhren
Aus Sicherheitsgründen wird die Uhrzeit beim Erstellen des Kontexts (für ein Plug-in oder eine Anfrage) festgelegt und während der Plug-in-Aufrufe beibehalten. Das bedeutet, dass WebAssembly-Plug-ins nicht in den Ruhezustand versetzt werden dürfen. Ein Ruhezustand führt zu einem Zeitüberschreitungsfehler, da die Zeit nicht voranschreitet. Das bedeutet auch, dass Plug-ins ihre eigene Ausführungszeit nicht messen können. Diese Informationen sind jedoch in Cloud Monitoring verfügbar.
Bei Headernamen wird nicht zwischen Groß- und Kleinschreibung unterschieden.
Gemäß der HTTP-Semantik muss bei HTTP-Headerfeldnamen die Groß-/Kleinschreibung ignoriert werden. Die Groß- und Kleinschreibung von Headern, die von einem Plugin geschrieben werden, kann geändert werden, bevor sie an Clients oder Back-Ends gesendet werden.
Leistung
Plug-in-Abstürze vermeiden
Für Ausführungsgeschwindigkeit kompilieren
Reguläre Ausdrücke vorkompilieren
Vermeiden, Daten in HTTP-Kontexte zu kopieren
Plug-in-Abstürze vermeiden
Wenn ein Plug-in abstürzt, wird für die auslösende Anfrage ein Fehler zurückgegeben. Wenn dies häufig geschieht, werden Neustarts von Plug-ins gedrosselt, was zu einer Häufung von Fehlern führt, die mehrere Nutzer betreffen.
So vermeiden Sie Plug-in-Abstürze:
- Vermeiden Sie Behauptungen jeglicher Art. Konfigurieren Sie stattdessen die Fehlerprotokollierung oder lokale Antworten an Nutzer.
- Vermeiden Sie in Rust die Verwendung von Methoden wie
unwrap, die zu Panik führen können. Außerdem können Sie das Plug-in so konfigurieren, dass Abstürze mitpanic::set_hookbehandelt werden. - Testen Sie Ihr Plug-in mit dem von Google bereitgestellten Plug-in-Tester und prüfen Sie, ob fehlerhafte oder leere Eingaben verarbeitet werden, ohne dass das Plug-in abstürzt.
Für Ausführungsgeschwindigkeit kompilieren
Kompilieren Sie Ihren WebAssembly-Code, um die beste Ausführungsgeschwindigkeit zu erzielen. Verwenden Sie dazu die Build-Option -O3 (für C++) oder opt-level=3 (für Rust).
Reguläre Ausdrücke vorkompilieren
Vermeiden Sie rechenintensive Vorgänge im Pfad pro Anfrage (in HTTP-Handlern). Führen Sie stattdessen alle Arbeiten, die nicht anfragespezifisch sind, bei der Plug-in-Konfiguration aus und übergeben Sie alle vorab berechneten Status in den Kontext jeder HTTP-Anfrage (auch als Stream-Kontext bezeichnet).
Kompilieren Sie insbesondere alle regulären Ausdrücke bei der Plug‑in-Konfiguration vorab. Unser Beispielcode für reguläre Ausdrücke zeigt, wie das geht.
Vermeiden Sie das Kopieren von Daten in HTTP-Kontexte.
Vermeiden Sie beim Freigeben von Daten zwischen dem Stammkontext und HTTP-Kontexten aufwendige Kopien oder Klonaufrufe. Geben Sie stattdessen Zeiger oder Referenzen an. In C++ kann dies mit std::shared_ptr oder Rohzeigern und ‑referenzen erfolgen, da der Stammkontext jeden HTTP-Kontext überdauert. In Rust können Werte mit std::rc::Rc freigegeben werden. In Go können Werte freigegeben werden, indem Zeiger auf die Werte gespeichert werden, die vom Garbage Collector entfernt werden.
Sicherheit
Arbeitslasten nach Projekt isolieren
In der Infrastruktur von Google können Plugins, die demselben Google Cloud Projekt gehören, in derselben sicheren Sandbox ausgeführt werden. Das bedeutet, dass die WebAssembly-Laufzeit die einzige Sicherheitsbarriere zwischen Plug-ins im selben Projekt ist.
Verwenden Sie separate Google Cloud -Projekte für Arbeitslasten, die eine Sicherheitsseparation erfordern. Außerdem werden so Ressourcen und Berechtigungen getrennt.
Secrets in Media CDN einschränken
Media CDN wird auf einer Hardwareflotte ausgeführt, die sich außerhalb der physischen Kontrolle von Google befindet. Wenn Sie sicherheitsrelevante Plugins für Media CDN schreiben, verwenden Sie dedizierte Hostnamen oder Subdomains und konfigurieren Sie Plugins mit Signaturschlüsseln, die häufig rotiert werden.