Assinar
Voltar
Cloud

Cloud Run em várias regiões: o comando único, o load balancer global e a parte que ninguém resolve por você

Serverless nunca significou sem região. Como o gcloud run multi-region-services encurta o deploy, por que ele sozinho não te dá um endereço único, e onde a dificuldade de verdade continua: o estado.

Toda arquitetura serverless carrega uma promessa implícita: “não se preocupe com infraestrutura”. Ela vale até o dia em que uma região inteira do provedor cai, seu serviço vai junto, e você descobre que “serverless” nunca significou “sem região”.

O Cloud Run é regional. Um serviço vive em southamerica-east1 ou em us-central1 — não nos dois. Se a região sai do ar, seu serviço sai do ar, e nenhum autoscaling do mundo resolve. A boa notícia é que o caminho para múltiplas regiões ficou consideravelmente mais curto. A má é que a parte difícil continua exatamente onde sempre esteve.

Por que multi-região, além do medo de apagão

Duas razões, e vale separá-las porque exigem soluções diferentes.

A primeira é disponibilidade. Uma região do Google Cloud é um conjunto de zonas dentro de uma mesma área geográfica. O Cloud Run já distribui suas instâncias entre zonas automaticamente — isso protege contra a queda de um datacenter, não contra um incidente que afete a região inteira (uma falha de rede regional, um problema no plano de controle, um evento físico).

A segunda é latência. Um usuário em Lisboa falando com um serviço em São Paulo paga uns 180 ms só de ida e volta na rede, antes de qualquer processamento. Nenhuma otimização de código recupera isso. A única saída é aproximar o serviço do usuário.

São problemas distintos com a mesma resposta arquitetural, mas com critérios de sucesso diferentes: disponibilidade se mede por failover funcionando; latência se mede por roteamento por proximidade. Guarde isso, porque a configuração precisa entregar as duas coisas.

O comando único: multi-region services

Historicamente, colocar o Cloud Run em três regiões significava rodar três gcloud run deploy, cada um com sua região, e manter os três em sincronia na unha — o que na prática virava um script Terraform e um pipeline com fan-out.

O gcloud run multi-region-services encurta isso para uma chamada:

gcloud run multi-region-services deploy api-pedidos \
  --image=us-docker.pkg.dev/meu-projeto/api/pedidos:1.4.2 \
  --regions=southamerica-east1,us-central1,europe-west1

Um único recurso lógico, várias regiões, deploy atômico do ponto de vista de quem opera. O grupo de comandos tem os verbos que você espera — deploy, describe, list, update, replace e delete — e o update aceita mudar a lista de regiões, o que torna adicionar ou remover um ponto de presença uma operação de um comando.

Em YAML, o equivalente é a anotação run.googleapis.com/regions. Em Terraform, o bloco multi_region_settings com a lista de regiões.

Uma armadilha que custa tempo: os serviços regionais criados por baixo do multi-region service viram recursos somente leitura. Não tente editar um deles direto pelo console para “só testar uma coisa” — a alteração ou é rejeitada ou é sobrescrita no próximo deploy.

O que o comando único não faz

Aqui está o mal-entendido mais comum, e ele derruba gente experiente: o multi-region service não te dá um endereço único. Você terminou o deploy com três serviços rodando e três URLs diferentes. Ninguém vai ser roteado para lugar nenhum sozinho.

Quem faz o roteamento é o Application Load Balancer externo global. Ele é uma peça separada, cobrada à parte, e é ele que entrega as duas coisas que você queria: um IP anycast único, anunciado de todas as bordas da rede do Google, e o roteamento automático do usuário para o datacenter mais próximo dele.

A montagem tem quatro etapas. A primeira é criar um NEG serverless (Network Endpoint Group) por região — é o adaptador que faz um serviço serverless, que não tem IP fixo nem porta, parecer um backend normal para o load balancer:

# um NEG por região
gcloud compute network-endpoint-groups create neg-pedidos-sa \
  --region=southamerica-east1 \
  --network-endpoint-type=serverless \
  --cloud-run-service=api-pedidos

gcloud compute network-endpoint-groups create neg-pedidos-us \
  --region=us-central1 \
  --network-endpoint-type=serverless \
  --cloud-run-service=api-pedidos

A segunda é criar o backend service global, que é o objeto que agrupa os NEGs e concentra a política de balanceamento:

gcloud compute backend-services create bs-pedidos --global \
  --load-balancing-scheme=EXTERNAL_MANAGED

A terceira é registrar cada NEG nesse backend. Repare que o comando pede a região do NEG explicitamente — é assim que o load balancer aprende a topologia:

gcloud compute backend-services add-backend bs-pedidos --global \
  --network-endpoint-group=neg-pedidos-sa \
  --network-endpoint-group-region=southamerica-east1

gcloud compute backend-services add-backend bs-pedidos --global \
  --network-endpoint-group=neg-pedidos-us \
  --network-endpoint-group-region=us-central1

A quarta é o encanamento de frente: certificado gerenciado, URL map, target HTTPS proxy e a forwarding rule que finalmente reserva o IP anycast. É burocrático, é sempre igual, e é exatamente o tipo de coisa que deve morar no Terraform e nunca mais ser digitada à mão.

Failover: automático de verdade ou “automático”?

Com os NEGs registrados, o load balancer distribui por proximidade. A pergunta que importa é o que acontece quando uma região começa a responder erro em vez de parar de responder.

Existem dois modos. O manual é tirar o NEG do backend service com remove-backend — funciona, e é a ferramenta certa para uma manutenção planejada, mas depende de um humano perceber o incidente e agir. O automático se apoia no Cloud Run service health: o load balancer passa a considerar a saúde reportada pelo serviço e para de mandar tráfego para a região doente sozinho.

O detalhe que decide se isso funciona é o seu health check. Um endpoint /health que devolve 200 OK incondicionalmente é decorativo: a região continua “saudável” enquanto o banco está inacessível e cada requisição real falha. O health check precisa exercitar as dependências críticas — conexão com o banco, credencial válida, fila alcançável — sem virar uma consulta cara que derruba o serviço sob carga. É um teste de fumaça, não um diagnóstico completo.

A parte difícil que ninguém resolve por você: o estado

Se você chegou até aqui, tem três cópias do seu contêiner em três continentes e um IP único na frente. Se a sua aplicação é stateless — uma API que só transforma dados, uma renderização de front, um gateway — acabou. Está pronto.

Se ela grava alguma coisa, o trabalho de verdade começa agora, e o Cloud Run não tem nada a dizer sobre ele.

Três instâncias em três regiões falando com um único banco em southamerica-east1 resolvem disponibilidade da camada de aplicação e não resolvem mais nada. A instância de europe-west1 vai pagar a travessia do Atlântico em cada consulta — trocando 180 ms na rede do usuário por 180 ms na rede do banco. E se a região do banco cair, as três instâncias caem juntas: você montou um sistema com três pontos de presença e um único ponto de falha.

As saídas existem, e nenhuma é gratuita:

  • Banco com réplicas regionais de leitura. Cloud SQL com réplicas, ou Spanner com configuração multi-região. Resolve leitura, mantém a escrita centralizada. É o caminho mais comum e o mais barato de raciocinar.
  • Particionamento por região. Cada região é dona de um subconjunto dos dados, e o roteamento leva o usuário sempre para a sua região de origem. Escrita local e rápida — ao custo de resolver “e quando o usuário viaja?” no seu código.
  • Multi-master com resolução de conflito. Escrita em qualquer lugar, convergência eventual. Poderoso e caro em complexidade: você passa a lidar com conflitos de escrita explicitamente, no domínio.

Escolher entre elas é uma decisão de produto disfarçada de decisão de infraestrutura. “Pode haver alguns segundos de atraso entre o que o usuário grava no Brasil e o que ele lê na Europa?” não é uma pergunta para o time de plataforma responder sozinho.

Uma ordem de adoção que evita retrabalho

  1. Comece pelo que é stateless. Front-end, BFF, APIs de leitura. O ganho é imediato e o risco é quase nulo.
  2. Suba o load balancer global antes de precisar dele. Com uma região só. Assim, quando a segunda entrar, é um add-backend — e não uma migração de DNS no meio de um incidente.
  3. Torne o health check honesto. Antes de configurar qualquer failover automático. Um health check mentiroso transforma failover automático em roleta.
  4. Só então ataque o dado. É a etapa cara, e é a única que exige decisão de negócio.

A promessa do serverless nunca foi “sem infraestrutura” — foi “sem servidores”. Continente ainda é uma coisa física, a velocidade da luz continua sendo o limite, e distribuir estado continua sendo o problema difícil de sistemas distribuídos. O que mudou é que a parte mecânica virou um comando. Aproveite o atalho, mas não confunda o atalho com o percurso.

Perguntas frequentes

Multi-region service substitui o load balancer global?

Não. Ele cria e sincroniza os serviços nas várias regiões; o endereço único, o roteamento por proximidade e o failover vêm do Application Load Balancer externo global. São duas peças complementares.

Dá para usar o domínio direto do Cloud Run em vez do load balancer?

Dá, mas o domínio do Cloud Run aponta para uma região específica. Você perde exatamente as duas coisas que motivaram o multi-região.

Quanto custa a mais?

Três frentes: o load balancer global (regra de encaminhamento mais tráfego processado), o egresso entre regiões se sua aplicação atravessa fronteira para falar com o banco, e o piso de instâncias mínimas multiplicado pelo número de regiões. A terceira é a que mais surpreende — se você mantém min-instances maior que zero, agora paga por região.

Preciso de três regiões?

Quase nunca. Duas já eliminam o ponto único de falha regional e cobrem a maior parte dos casos de latência. Cada região adicional multiplica custo, superfície operacional e complexidade do dado — só entre quando houver um usuário concreto do outro lado.

Fontes

Deixe um comentário

O seu endereço de e-mail não será publicado. Campos obrigatórios são marcados com *