Então você está iniciando um novo projeto – ou empresa – e decidiu que vai usar o Postgres. A parte difícil (escolher o banco de dados) terminou e agora começa a parte divertida: garantir que você não precise pensar nisso novamente por mais alguns anos.

Neste artigo, você verá algumas dicas menos conhecidas para configurar o Postgres a longo prazo, desde o pooling de conexões até noções básicas de segurança, extensões e índices.

Configure o pool de conexões para o Postgres com o PGBouncer

Por padrão, o Postgres cria um processo separado para cada conexão de cliente a partir do processo principal do sistema operacional. Com baixo volume, o tempo necessário para criar e destruir esses processos – além do fato de que eles nunca são reutilizados – não importa. Você pode definir um número de max_connections manualmente, mas eventualmente, conforme você escala, provavelmente encontrará problemas aqui. O pooling de conexões ajuda você a, essencialmente, “armazenar em cache” esses processos e reutilizá-los à medida que os clientes se conectam e desconectam do seu banco de dados.

Embora você possa criar o pooling de conexões na lógica do aplicativo, a maioria opta por uma ferramenta de terceiros e, no caso do Postgres, é o PGBouncer. Trata-se de um pooler de conexões leve e de código aberto que você pode instalar no servidor do banco de dados ou no servidor de aplicativos. Você tem três níveis de pooling para escolher:

  • Pooling de sessão: Mantém-se fiel ao modelo “as conexões do cliente são indefinidas” e mantém uma conexão aberta durante todo o tempo em que o cliente estiver conectado.
  • Pooling de transações: As conexões duram uma única transação e, depois disso, são enviadas de volta ao pool.
  • Pooling de instruções: As conexões duram apenas uma consulta, portanto, se você tiver várias como parte de uma transação, isso não funcionará de forma alguma.

A maioria escolhe o pooling de sessões – é o mais conservador e menos arriscado para descartar conexões – mas cada aplicativo é diferente, e você precisará descobrir o modo certo para suas restrições.

Impacto no desempenho do pool de conexões

A questão de um milhão de dólares, no entanto, é: isso realmente funciona? A Percona realizou uma série de benchmarks para descobrir como o PGBouncer impacta o desempenho. Com um pequeno número de clientes simultâneos (<60), o PGBouncer, na verdade, degrada as transações por segundo (TPS) consideravelmente devido à sobrecarga (pooling) do agrupamento. Mas quando você escala para mais de 100, começa a ver benefícios significativos de desempenho.

PGBouncer
PGBouncer.

Então, você precisa de um pooler de conexões imediatamente para dar suporte aos seus primeiros usuários? Provavelmente não. Mas o uso do PGBouncer ajudará você quando atingir um tráfego baixo/moderado.

Segurança do Postgres para leigos

Nas primeiras semanas em que você está trabalhando no seu projeto, geralmente são apenas um ou dois desenvolvedores trabalhando em um banco de dados vazio; a segurança não é a principal preocupação. Mas, à medida que você lançar seu aplicativo para o mundo, ela precisará estar presente. E com os bancos de dados, às vezes parece que há um milhão de maneiras diferentes de bloquear as coisas.

Restringindo o acesso no nível do host ou do usuário

Vamos começar com o acesso. O Postgres restringe o acesso de duas maneiras:

  1. No nível do host – definindo endereços IP e domínios com direitos de acesso.
  2. No nível do usuário – definindo os usuários do banco de dados e suas permissões.

O arquivo pg_hba.conf no diretório PGDATA é onde você define quem pode se conectar a quais bancos de dados. Se você não tiver uma entrada para um cliente nesse arquivo, ele não poderá acessar o banco de dados. Supondo que o servidor de aplicativos esteja sendo executado em outro local, veja como você pode permitir que ele acesse o banco de dados:

# Trust any connection via TCP/IP from this machine
host all 127.0.0.1 255.255.255.255 trust

Além de apenas “confiar em todas as conexões desta máquina”, há várias maneiras diferentes de autenticar seu cliente com o servidor de banco de dados, desde a senha até a identificação e os certificados. E se você tiver evitado os grandes confortos do RDS (ou Kinsta) e estiver executando seu backend no mesmo servidor do banco de dados, poderá se conectar por meio de soquetes Unix em vez de TCP/IP.

Autorização e privilégios

Depois que o próprio cliente for autenticado, você precisará lidar com a questão da autorização. O padrão SQL define um sistema de privilégios e cada objeto no Postgres (como uma tabela, linha etc.) tem privilégios diferentes relacionados a ele que podem ser atribuídos aos usuários: coisas como SELECT e UPDATE, mas também TRUNCATE, REFERENCES, TRIGGER, etc. Você concede privilégios aos usuários com o comando GRANT comando.

A prática recomendada é seguir o princípio do menor privilégio, de modo que o usuário do banco de dados que você criar para o(s) seu(s) cliente(s) só poderá acessar o que for necessário.

Segurança em nível de linha

O último ponto a ser abordado aqui é a segurança em nível de linha. A RLS existe sob a perspectiva da tabela (não do usuário) e restringe quais linhas podem ser acessadas, atualizadas, etc. Por padrão, as tabelas não têm a RLS ativada, portanto, o usuário poderá fazer o que as políticas de acesso dele determinarem. Para ativar o RLS para uma tabela, você deve começar com:

ALTER TABLE [table_name] ENABLE ROW LEVEL SECURITY

E, em seguida, você adiciona uma política. Digamos que você queira restringir o acesso de leitura à tabela lightsaber_internals a indivíduos confiáveis, que já estão definidos no grupo de usuários jedi, de modo que somente o proprietário de lightsaber pode ver seus detalhes internos. Veja como você faria isso:

ALTER TABLE lightsaber_internals ENABLE ROW LEVEL SECURITY
CREATE POLICY jedi_only ON lightsaber_internals TO jedi
    USING (jedi = lightsaber_jedi);

Políticas de RLS como essa são úteis quando você precisa de segurança em um nível mais granular do que apenas tabelas (situações com PII, etc).

Pense com antecedência nos problemas de dimensionamento

Em todas as startups em que trabalhei, houve algum grau de dimensionamento manual no que se refere ao banco de dados. Um dia, você acorda e o Datadog está surtando porque o seu servidor Postgres está completamente sem espaço. Você investigará, atualizará a página de incidentes e, por fim, atualizará o tamanho do disco até que isso aconteça novamente (embora, da próxima vez, possa ser um problema de RAM). Você pode se antecipar a essas coisas! Algumas sugestões:

1. Configure o monitoramento do banco de dados

A maioria das empresas em que trabalhei usa o Datadog para monitorar o banco de dados. Se você estiver usando um serviço de banco de dados gerenciado, provavelmente poderá se virar um pouco usando o material nativo deles. O Datadog tem um bom artigo em seu blog sobre as principais métricas que você deve observar, como taxa de transferência de leitura e escrita, varreduras sequenciais, dados escritos no disco, etc.

2. Elabore diretrizes para escalonamento verticalmente

Quando sua equipe receber um alerta – e isso vai acontecer – a última coisa que você quer é que todos precisem se mobilizar para resolver o problema, quando na maioria dos casos, um simples aumento de escala resolve. É bom elaborar um plano básico para sua equipe sobre o que está dentro do escopo quando você está ficando sem espaço ou capacidade de processamento.

3. Limpeza e ajuste do seu Autovacuum

Quando você exclui (DELETE) dados no Postgres ou atualiza (UPDATE) dados (o que é funcionalmente equivalente a excluir e inserir), o Postgres não apaga esses dados imediatamente (😱). Em vez disso, eles são “marcados” como excluídos armazenando o ID da transação da exclusão em um cabeçalho xmax; o motivo disso é que facilita o MVCC no Postgres. Mas se essas linhas não forem realmente excluídas eventualmente, começarão a desperdiçar espaço em disco e causar problemas.

A maneira mais fácil de se livrar dessas linhas é usando o comando VACUUM. Você poderia executar uma limpeza manualmente sempre que linhas mortas se acumulassem ou até mesmo configurá-la para ser executada a cada x minutos, mas uma estratégia melhor é autovacuum baseada em quantas linhas mortas se acumularam. Ajustar seu autovacuum é um tópico complexo que vai além do escopo deste post: Eu recomendaria fortemente a leitura do artigo da 2ndQuadrant sobre isso.

4. Configure uma réplica de leitura (ou duas)

Esta é fácil. Se você prevê um aumento significativo no tráfego (um lançamento em breve, etc.), pode criar facilmente réplicas somente de leitura (ou pelo menos uma); elas ajudarão a descarregar algum trabalho da instância principal do banco de dados.

Se optar por várias réplicas, você terá o benefício adicional de aumentar a disponibilidade se alguma delas ficar inativa por qualquer motivo. A adição de réplicas é bastante simples na maioria dos provedores de DBaaS; apenas fique atento ao custo: elas geralmente têm o mesmo preço de uma instância principal de banco de dados, apesar de serem somente leitura.

Adicione índices às suas tabelas (previstas) mais grandes

Os índices de banco de dados ajudam a acelerar as consultas de leitura, criando estruturas de dados auxiliares que tornam as varreduras mais rápidas. Para muitos casos de uso, adicionar um índice a uma ou duas tabelas é basicamente uma tarefa fácil. No Postgres, você pode criar um índice com o comando CREATE INDEX (duh). Quando você consultar uma tabela, o banco de dados verificará se existe um índice e o usará se existir (você pode verificar se isso está acontecendo com EXPLAIN a propósito).

O tipo mais popular de índice no Postgres – e o padrão quando você usa CREATE INDEX – é um índice B-Tree. Essencialmente, ele pega a coluna na qual você deseja criar um índice, classifica e armazena ponteiros para as linhas classificadas. Dessa forma, você pode obter eficiência de pesquisa binária em qualquer coluna que desejar, não apenas na coluna em que a tabela real está classificada (se é que existe uma). Você pode ler mais detalhadamente sobre como essas árvores são implementadas nos documentos do Postgres aqui.

Embora úteis, os índices não são só diversão; eles ocupam espaço e, se você não tomar cuidado com a quantidade e o tipo que cria, eles podem começar a prejudicar o desempenho do banco de dados. Ninguém diz isso melhor do que os próprios documentos do Postgres:

“Os índices são usados principalmente para melhorar o desempenho do banco de dados (embora o uso inadequado possa resultar em um desempenho mais lento).”

Nos bastidores, quando você cria um índice, o Postgres materializa uma tabela de pesquisa que tem o índice e um ponteiro para o registro do índice. Um número excessivo dessas tabelas consome espaço em disco, torna as consultas INSERT mais demoradas e força o mecanismo de consulta a considerar mais opções antes de escolher como executar uma consulta.

Bônus: Adicione algumas extensões do Postgres

Um aspecto que torna o Postgres único é o suporte nativo a extensões de terceiros. Você pode criá-las a partir de SQL e C, e elas podem ser tão pequenas quanto algumas instruções ou tão grandes quanto uma biblioteca de software inteira. O uso de extensões de código aberto/disponíveis publicamente ajuda você da mesma forma que o uso de um pacote de software; por que escrever seu próprio código quando você pode usar o de outra pessoa? Aqui estão algumas das extensões mais populares do Postgres:

Timescale

O Timescale é uma extensão do Postgres para que você trabalhe com dados de séries temporais. Em resumo, ele torna suas consultas (muito) mais rápidas e armazena dados de séries temporais com muita eficiência. Você pode encontrar instruções de instalação aqui ou considerar a opção de hospedagem na nuvem do Timescale se estiver realmente executando seus negócios com dados de séries temporais (embora você provavelmente já esteja ciente disso se for o caso).

PostGIS

O PostGIS adiciona suporte ao Postgres para armazenamento, indexação e consulta de dados geográficos (pense em linhas, polígonos, locais, etc.). Se você estiver usando um provedor de nuvem, a maioria pré-instala o PostGIS. Mas se você precisar instalá-lo por conta própria, poderá encontrar instruções de instalação aqui.

pg_stat_statements

O pg_stat_statements cria uma visualização em seu banco de dados Postgres com estatísticas sobre cada consulta executada no banco de dados. Você pode ver estatísticas como o tempo que a consulta leva para ser executada (média, mediana), quem executou a consulta, acessos ao cache de blocos, número de blocos gravados e muito mais (44 colunas no total nessa visualização). Para instalar, basta adicioná-lo ao seu arquivo .conf e reiniciar o servidor.

pg_audit

O pg_audit ajuda as empresas que podem estar sujeitas a auditorias detalhadas (por exemplo, governamentais, financeiras, etc.). Você pode fazer com que o Postgres registre todas as instruções do banco de dados configurando `log_statement=all`, mas isso não significa que as informações de que você precisa serão fáceis de pesquisar e encontrar. O pg_audit utiliza as funções de registro interno do Postgres para facilitar a localização e o trabalho com os registros de que um auditor pode precisar. Você pode encontrar instruções de instalação aqui.

Resumo

O Postgres é uma opção excelente (e muito popular) para você construir sua empresa e que temos orgulho de apoiar na Kinsta. Esperamos que essas dicas ajudem você a começar a trabalhar e a se preparar para o escalonamento. Tem outras dicas ou pensamentos baseados em sua experiência? Deixe-nos saber aqui.

Justin Gage

Justin is a technical writer and author of the popular Technically newsletter. He did his B.S. in Data Science before a stint in full-stack engineering and now focuses on making complex technical concepts accessible to everyone.