Blogue

Acordar Bases de Dados Sem Ligações Mortas

As apps publicadas no Mythex, e as suas bases de dados, entram em suspensão quando ninguém as usa. Quando uma app acordava, podia manter o primeiro pedido 10–12 segundos, porque tentava reutilizar ligações à base de dados que tinham morrido enquanto tudo dormia. Agora damos às apps Spring Boot definições de base de dados seguras depois de uma suspensão, e dizemos ao agente para construir apps de qualquer stack da mesma forma. Na plataforma de alojamento, o primeiro pedido após um despertar passou de 12,7 segundos para 2,3 segundos.

Porque é que as apps e as bases de dados entram em suspensão

Uma app publicada no Mythex corre numa máquina que suspende depois de alguns minutos inativa, e a sua base de dados é um Postgres serverless que adormece após cinco minutos inativa e acorda com o pedido seguinte. É isso que mantém barata uma app tranquila: pagas pelo que a base de dados realmente usou, e uma app adormecida não gasta nada em computação. Escrevemos sobre o lado da faturação em cobrar bases de dados pelo que realmente usam.

O senão é que as duas entram em suspensão separadamente, e não concordam quanto ao que é uma ligação.

O sintoma: uma primeira visita lenta

A maioria dos servidores de apps mantém um pool de ligações: um punhado de ligações abertas à base de dados, mantidas prontas para que cada pedido não pague o custo de abrir uma nova. É o desenho certo para uma app que está sempre ligada.

Eis o que acontece com a suspensão:

  1. A app está a correr, com algumas ligações inativas no pool.
  2. Ninguém visita. A máquina da app suspende — congelada, com o pool intacto.
  3. A base de dados adormece e deixa cair a sua ponta de cada ligação.
  4. Chega um visitante. A app acorda exatamente como estava, ainda com ligações que a base de dados já não conhece.
  5. O pool entrega uma dessas ligações. Tem de descobrir que está morta — tentando-a e esperando — antes de desistir dela.

Numa app Spring Boot, validar essas ligações mortas bloqueava o primeiro pedido durante cerca de 10 segundos antes de falhar com "Connection is not available". Para o visitante, o site simplesmente ficava pendurado e depois mostrava talvez um erro.

Porque é que as apps Spring foram as mais afetadas

Spring Boot é uma framework Java popular, e usa por defeito um pool de ligações chamado HikariCP. O Spring consegue configurar esse pool a partir de definições, incluindo quantas ligações inativas manter.

Mas o Mythex dá a cada app a sua base de dados como uma única DATABASE_URL no formato postgresql://user:pass@host/db. O Spring não consegue ler esse formato diretamente. Assim, as apps Spring construídas no Mythex criavam o seu próprio pool em código, fazendo o parsing desse URL — e um pool construído à mão ignora todas as definições spring.datasource.* do Spring. Mesmo que alguém soubesse as definições certas do pool, não havia onde elas tivessem efeito.

A correção, parte 1: definições que o Spring consegue usar

Quando um projeto tem uma base de dados, agora também lhe damos variáveis de ambiente que o Spring lê nativamente:

  • SPRING_DATASOURCE_URL, SPRING_DATASOURCE_USERNAME e SPRING_DATASOURCE_PASSWORD, convertidas a partir de DATABASE_URL (com SSL obrigatório, a menos que o URL indique outra coisa).
  • Definições do pool que sobrevivem à suspensão:
DefiniçãoValorPorquê
Mínimo de ligações inativas0Não mantém nada aberto entre pedidos, por isso não há nada que fique desatualizado
Tempo limite de inatividade30 segundosFecha cedo as ligações não usadas
Tempo de vida máximo2 minutosRetira cada ligação antes de poder envelhecer
Tempo limite de ligação5 segundosNão deixa um pedido pendurado muito tempo se a base de dados demorar a responder

Sem ligações inativas mantidas, uma app acordada abre uma ligação nova em vez de percorrer as mortas.

Com estas variáveis presentes, o Spring configura o próprio pool, e as definições aplicam-se. O que o projeto tiver definido por si tem sempre prioridade; nós só preenchemos o que falta. As apps que não são Spring ignoram estas variáveis.

O detalhe que quase não fazia nada

O Spring mapeia variáveis de ambiente para as suas definições segundo uma regra fácil de errar. A definição minimum-idle tem de ser escrita como SPRING_DATASOURCE_HIKARI_MINIMUMIDLE — sem hífenes, palavras juntas. Escrevê-la como SPRING_DATASOURCE_HIKARI_MINIMUM_IDLE, que parece mais natural, mapeia para uma definição diferente e inexistente (minimum.idle) e é ignorada em silêncio.

Este é o tipo de erro que passa em todas as revisões e não faz nada em produção. Por isso, um teste verifica tanto que os valores estão definidos como que nenhuma variável usa a forma com underscores.

A correção, parte 2: todas as outras stacks

O Spring não é a única framework com um pool, e não conseguimos pré-configurar todas as bibliotecas em todas as linguagens. Por isso, o agente do Mythex — a IA que escreve a tua app — recebe agora uma instrução permanente para qualquer stack: as apps publicadas e as suas bases de dados entram em suspensão quando estão inativas, por isso uma ligação mantida aberta pode estar morta no pedido seguinte. Deve:

  • não manter ligações inativas à base de dados abertas, ou verificar cada uma antes de a usar,
  • tentar de novo uma vez em caso de erro de ligação, e
  • usar as definições de base de dados que a plataforma fornece no ambiente, em vez de construir o seu próprio pool a fazer parsing de DATABASE_URL.

Este último ponto fecha o ciclo com a parte 1: uma app construída com as definições fornecidas apanha automaticamente a configuração segura para suspensão.

O resultado

Medido na plataforma de alojamento onde corremos as apps publicadas, o primeiro pedido após um despertar passou de 12,7 segundos para 2,3 segundos.

O que tirámos disto

  • Cada camada que entra em suspensão precisa de concordar sobre o que sobrevive. Uma app congelada e uma base de dados a adormecer fizeram, cada uma, uma escolha razoável. Juntas, a app acordou a segurar um estado que já não era verdadeiro.
  • Predefinições pensadas para servidores sempre ligados não servem apps que escalam para zero. Manter ligações quentes é boa ideia até tudo à volta delas arrefecer.
  • Dá às frameworks os seus dados no formato delas. Um único URL era simples para nós, mas obrigava cada app Spring a construir à mão um pool que ignorava a sua própria configuração.
  • Testa se uma definição está escrita da forma como a framework a lê. Um valor correto com o nome errado não faz nada, em silêncio.

Se és novo em como as bases de dados funcionam no Mythex, vê a documentação das bases de dados e o nosso guia sobre o que é o Postgres.

Mythex · Pricing · Crie qualquer coisa com IA · Modelos de sites e apps · Mythex comparado · Glossário de criação de apps com IA · Ferramentas grátis para criar apps com IA · English

English አማርኛ العربية Български বাংলা Bosanski Català Čeština Dansk Deutsch Ελληνικά Español Español (España) Eesti فارسی Suomi Français Français (Canada) ગુજરાતી हिन्दी Hrvatski Magyar Հայերեն Bahasa Indonesia Íslenska Italiano 日本語 ქართული Қазақ тілі ಕನ್ನಡ 한국어 Lietuvių Latviešu Македонски മലയാളം Монгол मराठी Bahasa Melayu မြန်မာ Norsk bokmål Nederlands ਪੰਜਾਬੀ Polski Português (Brasil) Română Русский Slovenčina Slovenščina Soomaali Shqip Srpski Svenska Kiswahili தமிழ் తెలుగు ไทย Tagalog Türkçe Українська اردو Tiếng Việt 简体中文 繁體中文(香港) 繁體中文(台灣)