Práticas recomendadas para plug-ins

Nesta página, você encontra dicas para escrever plug-ins de extensões de serviço corretos, com bom desempenho e bem isolados. A correção é fundamental porque os plug-ins são executados em uma sandbox de mecanismo restrita com uma superfície de API limitada. O desempenho é fundamental porque os plug-ins são executados durante as solicitações do usuário final, com pequenas quantidades de recursos. O isolamento é fornecido no nível do projeto.

Primeiros passos

Começar com os exemplos

Uma boa maneira de começar é navegar pelos nossos exemplos de código de plug-in. Estes são exemplos de padrões de plug-in comuns, como análise de caminho ou consulta, reescrita de cabeçalho, geração de registros e autenticação personalizadas.

Usar APIs compatíveis

Os plug-ins precisam ser compilados com a interface binária (ABI) Proxy-Wasm. As extensões de serviço são compatíveis com um subconjunto da ABI Proxy-Wasm que inclui mutações de cabeçalho e corpo HTTP, respostas locais, registros personalizados e configuração de plug-in. O Proxy-Wasm também é compatível com um pequeno subconjunto da prévia 1 do WASI, incluindo stdout e stderr para geração de registros, clock_time_get e random_get.

As extensões de serviço não são compatíveis com timers, métricas personalizadas, dados compartilhados, filas compartilhadas ou chamadas de rede de saída. As extensões de serviço também não aceitam valores de retorno de callback de plug-in que tentam pausar o processamento de solicitações e os ignoram.

Executar testes funcionais e comparativos

Para avaliar a correção e o desempenho, oferecemos uma ferramenta local de teste de plug-in que pode executar, testar e comparar seu plug-in. Você invoca essa ferramenta em um contêiner do Docker, transmitindo um binário de plug-in e um proto de texto de entradas e expectativas. Consulte a documentação do testador local e o exemplo de entrada de teste.

Correção

Não confie em relógios

Por motivos de segurança, a hora do relógio é definida na criação do contexto (para um plug-in ou uma solicitação) e permanece congelada durante as invocações do plug-in. Isso significa que os plug-ins do WebAssembly não podem entrar em modo de espera. Um modo de espera atinge o tempo limite porque o tempo não avança. Isso também significa que os plug-ins não podem medir o próprio tempo de execução, embora essas informações estejam disponíveis no Cloud Monitoring.

Tratar nomes de cabeçalho sem diferenciação entre maiúsculas e minúsculas

De acordo com a semântica HTTP, os nomes dos campos de cabeçalho HTTP não diferenciam maiúsculas de minúsculas. O uso de maiúsculas e minúsculas em um cabeçalho escrito por um plug-in pode ser alterado antes do envio para clientes ou back-ends.

Desempenho

Evitar falhas de plug-ins

Quando um plug-in falha, a solicitação que acionou o problema recebe um erro. Se isso acontecer com frequência, as reinicializações de plug-ins serão limitadas, o que vai gerar picos de erros que afetam vários usuários.

Para evitar falhas no plug-in, tente o seguinte:

  • Evite declarações de todos os tipos. Em vez disso, configure o registro de erros ou respostas locais para os usuários.
  • Em Rust, evite usar métodos, como unwrap, que podem resultar em falhas. Além disso, é possível configurar o plug-in para processar falhas usando panic::set_hook.
  • Teste seu plug-in usando o testador de plug-ins fornecido pelo Google e verifique se entradas malformadas ou vazias são processadas sem que o plug-in falhe.

Compilar para velocidade de execução

Compile seu código WebAssembly para alcançar a melhor velocidade de execução usando a opção de build -O3 (para C++) ou opt-level=3 (para Rust).

Pré-compilar expressões regulares

Evite operações que exigem muita computação no caminho por solicitação (em manipuladores HTTP). Em vez disso, faça qualquer trabalho que não seja específico da solicitação no momento da configuração do plug-in e transmita qualquer estado pré-calculado para cada contexto de solicitação HTTP (também conhecido como contexto de fluxo).

Em particular, pré-compile todas as expressões regulares no momento da configuração do plug-in. Nosso exemplo de código de regex mostra como fazer isso.

Evite copiar dados para contextos HTTP

Ao compartilhar dados entre o contexto raiz e os contextos HTTP, evite cópias ou chamadas de clonagem caras. Em vez disso, compartilhe indicadores ou referências. Em C++, isso pode ser feito com std::shared_ptr ou ponteiros e referências brutos porque o contexto raiz dura mais que qualquer contexto HTTP. Em Rust, os valores podem ser compartilhados usando std::rc::Rc. Em Go, os valores podem ser compartilhados armazenando ponteiros para eles, que são removidos pelo coletor de lixo.

Segurança

Isolar cargas de trabalho por projeto

Na infraestrutura do Google, plug-ins pertencentes ao mesmo projeto Google Cloud podem ser executados na mesma sandbox segura. Isso significa que o ambiente de execução do WebAssembly é a única barreira de segurança entre plug-ins no mesmo projeto.

Use projetos Google Cloud separados para cargas de trabalho que precisam de separação de segurança. Essa prática também oferece separação de recursos e permissões.

Restringir secrets na Media CDN

Por design, a Media CDN é executada em uma frota de hardware operada fora do controle físico do Google. Ao escrever plug-ins relacionados à segurança para a Media CDN, use nomes de host ou subdomínios dedicados e configure plug-ins com chaves de assinatura que são trocadas com frequência.