Este guia fornece práticas recomendadas para conceber, implementar, testar e implementar um serviço do Cloud Run. Para mais sugestões, consulte o artigo Migrar um serviço existente.
Escreva serviços eficazes
Esta secção descreve as práticas recomendadas gerais para conceber e implementar um serviço do Cloud Run.
Atividade em segundo plano
A atividade em segundo plano é tudo o que acontece depois de a resposta HTTP ter sido enviada. Para determinar se existe atividade em segundo plano no seu serviço que não seja imediatamente evidente, verifique os registos para ver se existe algo registado após a entrada do pedido HTTP.
Configure a faturação baseada em instâncias para usar atividades em segundo plano
Se quiser suportar atividades em segundo plano no seu serviço do Cloud Run, defina o serviço do Cloud Run para faturação baseada em instâncias, para que possa executar atividades em segundo plano fora dos pedidos e continuar a ter acesso à CPU.
Evite atividades em segundo plano se usar a faturação baseada em pedidos
Se precisar de definir o seu serviço para a faturação baseada em pedidos, quando o serviço Cloud Run terminar de processar um pedido, o acesso da instância à CPU é desativado ou severamente limitado. Não deve iniciar threads ou rotinas em segundo plano que sejam executadas fora do âmbito dos processadores de pedidos se usar este tipo de faturação.
Reveja o seu código para se certificar de que todas as operações assíncronas terminam antes de enviar a resposta.
A execução de threads em segundo plano com a faturação baseada em pedidos ativada pode resultar num comportamento inesperado, porque qualquer pedido subsequente à mesma instância do contentor retoma qualquer atividade em segundo plano suspensa.
Elimine ficheiros temporários
No ambiente do Cloud Run, o armazenamento em disco é um sistema de ficheiros na memória. Os ficheiros escritos no disco consomem memória que, de outra forma, estaria disponível para o seu serviço e podem persistir entre invocações. Se não eliminar estes ficheiros, pode ocorrer um erro de falta de memória e, posteriormente, os contentores podem demorar mais tempo a iniciar.
Comunique erros
Trate todas as exceções e não permita que o seu serviço falhe devido a erros. Uma falha do sistema leva a um início lento do contentor enquanto o tráfego está em fila para uma instância de substituição.
Consulte o guia de relatórios de erros para obter informações sobre como comunicar corretamente os erros.
Otimize o desempenho
Esta secção descreve as práticas recomendadas para otimizar o desempenho.
Inicie contentores rapidamente
Uma vez que as instâncias são dimensionadas conforme necessário, o respetivo tempo de arranque tem impacto na latência do seu serviço. O Cloud Run desvincula o arranque da instância e o processamento de pedidos, pelo que, em alguns casos, um pedido tem de aguardar que uma nova instância seja iniciada antes de ser processado. Isto acontece frequentemente quando um serviço é dimensionado a partir de zero.
A rotina de arranque consiste no seguinte:
- Transferir a imagem do contentor (através da tecnologia de streaming de imagens de contentores do Cloud Run)
- Iniciar o contentor executando o comando entrypoint
- A aguardar que o contentor comece a ouvir na porta configurada.
A otimização da velocidade de arranque do contentor minimiza a latência de processamento de pedidos.
Use o aumento da CPU de arranque para reduzir a latência de arranque
Pode ativar o aumento da CPU no arranque para aumentar temporariamente a atribuição da CPU durante o arranque da instância de modo a reduzir a latência do arranque.
Use instâncias mínimas para reduzir os tempos de arranque dos contentores
Pode configurar instâncias mínimas e a concorrência para minimizar os tempos de início do contentor. Por exemplo, usar um mínimo de 1 instância significa que o seu serviço está pronto para receber até ao número de pedidos simultâneos configurados para o seu serviço sem precisar de iniciar uma nova instância.
Tenha em atenção que um pedido que aguarda o início de uma instância é mantido pendente numa fila da seguinte forma:
Os pedidos ficam pendentes até 3, 5 vezes o tempo de arranque médio das instâncias de contentores deste serviço ou 10 segundos, consoante o que for superior.
Use as dependências de forma inteligente
Se usar uma linguagem dinâmica com bibliotecas dependentes, como importar módulos no Node.js, o tempo de carregamento desses módulos é adicionado à latência de arranque.
Reduza a latência do arranque das seguintes formas:
- Minimize o número e o tamanho das dependências para criar um serviço simples.
- Carregue em diferido o código que é usado com pouca frequência, se o seu idioma o suportar.
- Use otimizações de carregamento de código, como a otimização do carregamento automático do Composer do PHP.
Use variáveis globais
No Cloud Run, não pode assumir que o estado do serviço é preservado entre pedidos. No entanto, o Cloud Run reutiliza instâncias individuais para publicar tráfego contínuo, pelo que pode declarar uma variável no âmbito global para permitir que o respetivo valor seja reutilizado em invocações subsequentes. Não é possível saber antecipadamente se um pedido individual vai receber o benefício desta reutilização.
Também pode colocar objetos em cache na memória se for dispendioso recriá-los em cada pedido de serviço. Mover isto da lógica de pedido para o âmbito global resulta num melhor desempenho.
Node.js
Python
Ir
Java
Realize a inicialização em diferido de variáveis globais
A inicialização das variáveis globais ocorre sempre durante o arranque, o que aumenta o tempo de arranque do contentor. Use a inicialização tardia para objetos usados com pouca frequência para diferir o custo de tempo e diminuir os tempos de arranque do contentor.
Uma desvantagem da inicialização tardia é o aumento da latência para os primeiros pedidos a novas instâncias. Isto pode causar um aumento excessivo da escala e pedidos ignorados quando implementa uma nova revisão de um serviço que está a processar ativamente muitos pedidos.
Node.js
Python
Ir
Java
Use um ambiente de execução diferente
Pode ter tempos de arranque mais rápidos se usar um ambiente de execução diferente.
Otimize a simultaneidade
As instâncias do Cloud Run podem processar vários pedidos em simultâneo, "em simultâneo", até uma simultaneidade máxima configurável.
O Cloud Run ajusta automaticamente a concorrência até ao máximo configurado.
A simultaneidade máxima predefinida de 80 é adequada para muitas imagens de contentores. No entanto, deve:
- Diminua-o se o seu contentor não conseguir processar muitos pedidos simultâneos.
- Aumente-o se o seu contentor conseguir processar um grande volume de pedidos.
Ajuste a simultaneidade do seu serviço
O número de pedidos simultâneos que cada instância pode publicar pode ser limitado pela pilha de tecnologia e pela utilização de recursos partilhados, como variáveis e ligações à base de dados.
Para otimizar o seu serviço em função da simultaneidade estável máxima:
- Otimize o desempenho do seu serviço.
- Defina o nível esperado de suporte de simultaneidade em qualquer configuração de simultaneidade ao nível do código. Nem todas as stacks de tecnologia requerem esta definição.
- Implemente o seu serviço.
- Defina a simultaneidade do Cloud Run para o seu serviço igual ou inferior a qualquer configuração ao nível do código. Se não existir uma configuração ao nível do código, use a concorrência esperada.
- Use ferramentas de testes de carga que suportem uma concorrência configurável. Tem de confirmar que o seu serviço permanece estável sob a carga e a concorrência esperadas.
- Se o serviço tiver um desempenho fraco, avance para o passo 1 para melhorar o serviço ou para o passo 2 para reduzir a simultaneidade. Se o serviço tiver um bom desempenho, regresse ao passo 2 e aumente a simultaneidade.
Continue a iterar até encontrar a concorrência estável máxima.
Faça corresponder a memória à simultaneidade
Cada pedido que o seu serviço processa requer uma certa quantidade de memória adicional. Por isso, quando ajustar a concorrência para cima ou para baixo, certifique-se de que também ajusta o limite de memória.
Evite o estado global mutável
Se quiser tirar partido do estado global mutável num contexto concorrente, tome medidas adicionais no seu código para garantir que isto é feito em segurança. Minimize a contenção limitando as variáveis globais à inicialização única e à reutilização, conforme descrito acima em Desempenho.
Se usar variáveis globais mutáveis num serviço que processa vários pedidos ao mesmo tempo, certifique-se de que usa bloqueios ou exclusões mútuas para evitar condições de corrida.
Equilíbrios entre o débito, a latência e o custo
Ajustar a definição de pedidos simultâneos máximos pode ajudar a equilibrar a relação de compromisso entre o débito, a latência e o custo do seu serviço.
Em geral, uma definição de pedidos concorrentes máximos mais baixa resulta numa latência mais baixa e num débito mais baixo por instância. Com um número máximo de pedidos simultâneos inferior, menos pedidos competem por recursos em cada instância e cada pedido alcança um melhor desempenho. No entanto, como cada instância pode publicar menos pedidos de cada vez, a taxa de transferência por instância é inferior e o serviço precisa de mais instâncias para publicar o mesmo tráfego.
Na direção oposta, uma definição de pedidos simultâneos máximos mais elevada resulta geralmente numa latência mais elevada e num débito mais elevado por instância. Os pedidos podem ter de aguardar o acesso a recursos como a CPU, a GPU e a largura de banda da memória na instância, o que leva a um aumento da latência. No entanto, cada instância pode processar mais pedidos em simultâneo, pelo que o serviço precisa de menos instâncias no geral para processar o mesmo tráfego.
Considerações sobre o custo
A preçário do Cloud Run é por tempo de instância. Se definir a faturação baseada em instâncias, o tempo de instância é a duração total de cada instância. Se definir a faturação baseada em pedidos, o tempo de instância é o tempo que cada instância passa a processar, pelo menos, um pedido.
O impacto dos pedidos simultâneos máximos na faturação depende do seu padrão de tráfego. Diminuir os pedidos simultâneos máximos pode resultar numa fatura mais baixa se a definição mais baixa levar a
- Latência reduzida
- As instâncias concluem o respetivo trabalho mais rapidamente
- As instâncias encerram mais rapidamente, mesmo que sejam necessárias mais instâncias no total
No entanto, também é possível o contrário: diminuir os pedidos simultâneos máximos pode aumentar a faturação se o aumento no número de instâncias não for compensado pela redução no tempo de execução de cada instância, devido à latência melhorada.
A melhor forma de otimizar a faturação é através de testes de carga
com diferentes definições de pedidos simultâneos máximos para identificar a definição
que resulta no menor tempo de instância faturável, conforme apresentado na
container/billable_instance_time
métrica de monitorização.
Segurança do contentor
Muitas práticas de segurança de software de uso geral aplicam-se a serviços contentorizados. Existem algumas práticas específicas dos contentores ou que se alinham com a filosofia e a arquitetura dos contentores.
Para melhorar a segurança do contentor:
Use imagens base seguras e ativamente mantidas, como as imagens base da Google ou as imagens oficiais do Docker Hub.
Aplique atualizações de segurança aos seus serviços recriando regularmente imagens de contentores e reimplementando os seus serviços.
Inclua no contentor apenas o que for necessário para executar o seu serviço. O código, os pacotes e as ferramentas adicionais são potenciais vulnerabilidades de segurança. Consulte acima o impacto no desempenho relacionado.
Implemente um processo de compilação determinístico que inclua versões específicas de software e bibliotecas. Isto impede a inclusão de código não validado no seu contentor.
Defina o contentor para ser executado como um utilizador diferente de
root
com a declaração DockerfileUSER
. Algumas imagens de contentores podem já ter um utilizador específico configurado.Impeça a utilização de funcionalidades de pré-visualização através de políticas de organização personalizadas.
Automatize a análise de segurança
Ative a análise de vulnerabilidades para a análise de segurança de imagens de contentores armazenadas no Artifact Registry.
Crie imagens de contentores mínimas
As imagens de contentores grandes aumentam provavelmente as vulnerabilidades de segurança porque contêm mais do que o código precisa.
Devido à tecnologia de streaming de imagens de contentores do Cloud Run, o tamanho da sua imagem de contentor não afeta os tempos de arranque do contentor nem o tempo de processamento de pedidos. O tamanho da imagem do contentor também não é contabilizado na memória disponível do contentor.
Para criar um contentor minimalista, considere trabalhar a partir de uma imagem de base simples, como:
O Ubuntu tem um tamanho maior, mas é uma imagem base usada com frequência com um ambiente de servidor mais completo pronto a usar.
Se o seu serviço tiver um processo de compilação com muitas ferramentas, considere usar compilações de várias fases para manter o seu contentor leve no tempo de execução.
Estes recursos oferecem mais informações sobre a criação de imagens de contentores otimizadas:
- Práticas recomendadas do Kubernetes: como e porquê criar imagens de contentores pequenas
- 7 práticas recomendadas para criar contentores