Questa pagina fornisce suggerimenti per scrivere plug-in di Service Extensions corretti, con buone prestazioni e ben isolati. La correttezza è fondamentale perché i plug-in vengono eseguiti in un sandbox del motore vincolato con una superficie API limitata. Le prestazioni sono fondamentali perché i plug-in vengono eseguiti durante le richieste degli utenti finali, con piccole quantità di risorse. L'isolamento è fornito a livello di progetto.
Per iniziare
Inizia dagli esempi
Un buon modo per iniziare è sfogliare i nostri esempi di codice dei plug-in. Questi sono esempi di pattern di plug-in comuni, come l'analisi di percorsi o query, la riscrittura di intestazioni, la registrazione personalizzata e l'autenticazione personalizzata.
Utilizzare le API supportate
I plug-in devono essere compilati in base all'interfaccia binaria (ABI) Proxy-Wasm. Service Extensions supporta un sottoinsieme dell'ABI Proxy-Wasm
che include mutazioni di intestazione e corpo HTTP, risposte locali, logging personalizzato
e configurazione dei plug-in. Proxy-Wasm supporta anche un piccolo sottoinsieme di
WASI preview 1,
inclusi stdout e stderr per la registrazione, clock_time_get e random_get.
Service Extensions non supporta timer, metriche personalizzate, dati condivisi, code condivise o chiamate di rete in uscita. Le estensioni di servizio non supportano i valori restituiti del callback del plug-in che tentano di sospendere l'elaborazione delle richieste e li ignorano.
Esegui test funzionali e benchmark
Per valutare la correttezza e le prestazioni, forniamo uno strumento di test dei plug-in locali che può eseguire, testare e confrontare il tuo plug-in. Richiami questo strumento in un container Docker, passando un binario del plug-in e un proto di testo di input e aspettative. Consulta la documentazione relativa ai test locali e l'esempio di input di test.
Correttezza
Non fare affidamento sugli orologi
Considera i nomi delle intestazioni senza distinzione tra maiuscole e minuscole
Non fare affidamento sugli orologi
Per motivi di sicurezza, l'ora viene impostata al momento della creazione del contesto (per un plug-in o una richiesta) e rimane invariata durante le chiamate del plug-in. Ciò significa che i plug-in WebAssembly non devono andare in sospensione; un periodo di sospensione scade perché il tempo non avanza. Significa anche che i plug-in non possono misurare il proprio tempo di esecuzione, anche se queste informazioni sono disponibili in Cloud Monitoring.
Considera i nomi delle intestazioni senza distinzione tra maiuscole e minuscole
Secondo la semantica HTTP, i nomi dei campi di intestazione HTTP devono essere trattati come se non facessero distinzione tra maiuscole e minuscole. La distinzione tra maiuscole e minuscole dell'intestazione scritta da un plug-in può essere modificata prima dell'invio ai client o ai backend.
Prestazioni
Evita arresti anomali dei plug-in
Compila per la velocità di esecuzione
Precompila le espressioni regolari
Evita di copiare i dati nei contesti HTTP
Evitare arresti anomali dei plug-in
Quando un plug-in si arresta in modo anomalo, la richiesta di attivazione riceve un errore. Se questo si verifica di frequente, i riavvii dei plug-in vengono limitati, il che porta a picchi di errori che interessano più utenti.
Per evitare arresti anomali dei plug-in, prova a eseguire le seguenti operazioni:
- Evita affermazioni di ogni tipo. Configura invece la registrazione degli errori o risposte locali agli utenti.
- In Rust, evita di utilizzare metodi, come
unwrap, che possono causare panico. Inoltre, puoi configurare il plug-in per gestire gli arresti anomali utilizzandopanic::set_hook. - Testa il plug-in utilizzando lo strumento di test dei plug-in fornito da Google e assicurati che gli input non validi o vuoti vengano gestiti senza che il plug-in si arresti in modo anomalo.
Compilare per la velocità di esecuzione
Compila il codice WebAssembly per ottenere la migliore velocità di esecuzione utilizzando
l'opzione di compilazione -O3 (per C++) o opt-level=3 (per Rust).
Precompila le espressioni regolari
Evita operazioni che richiedono molte risorse di calcolo nel percorso per richiesta (nei gestori HTTP). Esegui invece qualsiasi lavoro non specifico della richiesta durante la configurazione del plug-in e passa qualsiasi stato precalcolato nel contesto di ogni richiesta HTTP (noto anche come contesto di flusso).
In particolare, precompila tutte le espressioni regolari al momento della configurazione del plug-in. Il nostro esempio di codice regex mostra come ottenere questo risultato.
Evita di copiare i dati nei contesti HTTP
Quando condividi dati tra il contesto principale e i contesti HTTP, evita copie o chiamate di clonazione costose. Condividi invece suggerimenti o riferimenti. In C++, questa operazione può essere eseguita con std::shared_ptr o con puntatori e riferimenti non elaborati, perché il contesto radice sopravvive a qualsiasi contesto HTTP. In Rust, i valori possono essere condivisi utilizzando
std::rc::Rc. In Go, i valori possono essere condivisi memorizzando i puntatori ai valori,
che vengono rimossi dal garbage collector.
Sicurezza
Isolare i carichi di lavoro per progetto
Nell'infrastruttura di Google, i plug-in di proprietà dello stesso Google Cloud progetto possono essere eseguiti nella stessa sandbox sicura. Ciò significa che il runtime WebAssembly è l'unica barriera di sicurezza tra i plug-in nello stesso progetto.
Utilizza progetti Google Cloud separati per i carichi di lavoro che richiedono la separazione della sicurezza. Questa pratica prevede anche la separazione di risorse e autorizzazioni.
Limitare i secret su Media CDN
Per progettazione, Media CDN viene eseguita su una flotta di hardware gestita al di fuori del controllo fisico di Google. Quando scrivi plug-in correlati alla sicurezza per Media CDN, utilizza nomi host o sottodomini dedicati e configura i plug-in con chiavi di firma che vengono ruotate di frequente.