Pontos Principais
- Pensando em adicionar outro armazenamento de dados como Redis ou Elasticsearch? Tome um minuto e pense novamente. O Postgres oferece recursos poderosos que não são tão óbvios à primeira vista;
- O Postgres possui um sistema de cache na memória com páginas, contagens de uso e logs de transações;
- O Postgres possui um tipo de dado especial, tsvector, para pesquisar rapidamente o texto;
- O Postgres pode ser dimensionado para cargas pesadas, oferecendo índices especializados para pesquisar com eficiência dados baseados em tempo, grandes conjuntos de dados de texto e dados estruturados;
- No entanto, há momentos em que é necessário outro armazenamento de dados, como para tipos de dados especiais, processamento pesado em tempo real e pesquisa instantânea de texto.
Pensando em escalar além do cluster do Postgres e adicionar outro armazenamento de dados como Redis ou Elasticsearch? Antes de adotar uma infraestrutura mais complexa, pare por um minuto e pense novamente. É bem possível obter mais proveito de um banco de dados existente do Postgres. Pode ser dimensionado para cargas pesadas e oferece recursos poderosos que não são óbvios à primeira vista. Por exemplo, é possível ativar o armazenamento em cache na memória, pesquisa de texto, indexação especializada e armazenamento de valores-chave.
Depois de ler este artigo, liste os recursos que deseja no seu repositório de dados e verifique se o Postgres será adequado para eles. É poderoso o suficiente para a maioria dos aplicativos.
Por que adicionar um outro repositório de dados nem sempre é uma boa ideia
Como Fred Brooks colocou em The Mythical Man-Month: "O programador, como o poeta, trabalha apenas um pouco afastado do material de pensamento puro. [Eles] constroem castelos no ar, do ar, criando pelo esforço da imaginação".
Adicionar mais peças a esses castelos e se perder no design é infinitamente fascinante; no entanto, no mundo real, construir mais castelos no ar pode atrapalhar. O mesmo vale para o hype mais recente nos armazenamentos de dados. Existem várias vantagens em escolher a tecnologia chata:
- Se alguém novo ingressar na sua equipe, eles podem facilmente entender seus diferentes repositórios de dados?
- Quando algum membro da equipe volta um ano depois, eles podem entender rapidamente como o sistema funciona?
- Se precisar alterar seu sistema ou adicionar recursos, quantas peças precisará mover?
- Considerou os custos de manutenção, segurança e atualizações?
- Considera os modos desconhecido e de falha ao executar seu novo armazenamento de dados na produção em escala?
Embora possa ser gerenciado por um design cuidadoso, a adição de vários datastores aumenta a complexidade. Antes de explorar a adição de repositórios de dados adicionais, vale a pena investigar quais recursos adicionais os repositórios de dados existentes podem oferecer.
Recursos menos conhecidos, mas poderosos, do Postgres
Muitas pessoas não sabem que o Postgres oferece muito mais do que apenas um banco de dados SQL. Se já possui o Postgres na sua lista de aplicações, por que adicionar mais peças quando o Postgres pode fazer o trabalho?
Postgres também utiliza cache
Há um equívoco de que o Postgres lê e grava do disco em todas as consultas, especialmente quando os usuários o comparam com armazenamentos de dados puramente na memória, como o Redis.
Na verdade, o Postgres possui um sistema de cache lindamente projetado com páginas, contagens de uso e logs de transações. A maioria das suas consultas não precisará acessar o disco, especialmente se elas se referirem aos mesmos dados repetidamente, como muitas consultas costumam fazer.
O parâmetro de configuração shared_buffer no arquivo de configuração do Postgres determina quanta memória será usada para armazenar dados em cache. Normalmente, ele deve ser definido entre 25% e 40% da memória total. Isso ocorre porque o Postgres também usa o cache do sistema operacional para sua operação. Com mais memória, a maioria das consultas recorrentes referentes ao mesmo conjunto de dados não precisará acessar o disco. Aqui está como pode definir este parâmetro na CLI do Postgres:
ALTER SYSTEM SET shared_buffer TO = <value>
Serviços de banco de dados gerenciados como o Heroku oferecem vários planos em que a RAM (e, portanto, o cache) é um grande diferencial. A versão gratuita de hobby não oferece recursos dedicados, como RAM. Faça upgrade quando estiver pronto para cargas de produção, para que possa usar melhor o cache.
Também pode usar algumas das ferramentas de cache mais avançadas. Por exemplo, verifique a view pg_buffercache para ver o que está ocupando o cache de buffer compartilhado da sua instância. Outra ferramenta a ser usada é a função pg_prewarm, que vem como parte da instalação básica. Esta função permite que os DBAs carreguem dados da tabela no cache do sistema operacional ou no cache do buffer do Postgres. O processo pode ser manual ou automatizado. Se conhece a natureza de suas consultas ao banco de dados, isso pode melhorar muito o desempenho do aplicativo.
Para os mais corajosos, consulte este artigo para obter uma descrição detalhada do cache do Postgres.
Text searching
Elasticsearch is excellent, but many use cases can get along just fine with Postgres for text searching. Postgres has a special data type, tsvector, and a set of functions, like to_tsvector and to_tsquery, to search quickly through text. tsvector represents a document optimized for text search by sorting terms and normalizing variants. Here is an example of the to_tsquery function:
Pesquisa de texto
O Elasticsearch é excelente, mas muitos casos de uso podem se dar muito bem com o Postgres para pesquisa de texto. O Postgres possui um tipo de dados especial, tsvector, e um conjunto de funções, como to_tsvector e to_tsquery, para pesquisar rapidamente o texto. O tsvector representa um documento otimizado para pesquisa de texto, ordenando termos e normalizando variantes. Aqui está um exemplo da função to_tsquery:
SELECT to_tsquery('english', 'The & Boys & Girls');
to_tsquery
---------------
'boy' & 'girl'
Pode classificar seus resultados por relevância, dependendo de quantas vezes e quais campos sua consulta apareceu nos resultados. Por exemplo, pode tornar o título mais relevante que o corpo. Verifique a documentação do Postgres para obter detalhes.
Funções no Postgres
O Postgres fornece um poderoso conjunto de funções que executam no servidor disponíveis em várias linguagens de programação.
Tente pré-processar o máximo de dados possíveis no servidor Postgres com as funções que executam no servidor. Dessa forma pode-se reduzir a latência resultante da passagem excessiva de dados entre os servidores de aplicativos e o banco de dados. Essa abordagem é particularmente útil para agregações e uniões grandes.
O melhor de tudo é que sua equipe de desenvolvimento pode usar o conjunto de habilidades existente para escrever o código do Postgres. Além do padrão PL/pgSQL (linguagem procedural nativa do Postgres), as funções e os gatilhos do Postgres podem ser escritos em PL/Python, PL/Perl, PL/V8 (extensão JavaScript para Postgres) e PL/R.
Aqui está um exemplo de criação de uma função PL/Python para verificar o comprimento das strings:
CREATE FUNCTION longer_string_length (string1 string, string2 string)
RETURNS integer
AS $$
a=len(string1)
b-len(string2)
if a > b:
return a
return b
$$ LANGUAGE plpythonu;
O Postgres oferece extensões poderosas
As extensões para Postgres são similares aos plug-ins em muitos aplicativos. O uso adequado das extensões do Postgres também pode significar que não é preciso trabalhar com outros armazenamentos de dados para obter funcionalidades extras. Existem muitas extensões disponíveis e listadas no site principal do Postgres.
Dados geoespaciais
O PostGIS é uma extensão especializada para o Postgres usada para manipulação de dados geoespaciais e execução de consultas de localização no SQL. É amplamente popular entre os desenvolvedores de aplicativos GIS que usam o Postgres. Um ótimo guia para iniciantes do PostGIS pode ser encontrado aqui.
O trecho de código a seguir mostra como estamos adicionando a extensão PostGIS ao banco de dados atual. No sistema operacional, executamos estes comandos para instalar o pacote (supondo que esteja usando o sistema operacional Ubuntu):
$ sudo add-apt-repository ppa:ubuntugis/ppa
$ sudo apt-get update
$ sudo apt-get install postgis
Depois disso, efetue login na sua instância do Postgres e instale a extensão:
CREATE EXTENSION postgis;
CREATE EXTENSION postgis_topology;
Se quiser verificar quais extensões existem no banco de dados atual, execute este comando:
SELECT * FROM pg_available_extensions;
Tipo de dados de Chave-Valor
A extensão hstore do Postgres permite armazenar e pesquisar pares simples de chave-valor. Este tutorial fornece uma excelente visão geral de como trabalhar com o tipo de dados hstore.
Tipos de dados Semi-Estruturados
Existem dois tipos de dados nativos para armazenar dados semi-estruturados no Postgres: JSON e XML. O tipo de dados JSON pode hospedar o JSON nativo e seu formato binário (JSONB). Podendo melhorar significativamente o desempenho da consulta quando ela é pesquisada. Como podem ver a seguir, é possível converter cadeias JSON em objetos JSON nativos:
SELECT '{"product1": ["blue", "green"], "tags": {"price": 10, "discounted": false}}'::json;
json
---------------------------------------------------------------------
{"product1": ["blue", "green"], "tags": {"price": 10, "discounted": false}}
Dicas para escalar o Postgres
Se estiver pensando em desativar o Postgres por motivos de desempenho, primeiro veja até onde pode chegar com as otimizações que ele oferece. Aqui, assumiremos que fez o básico, como a criação de índices apropriados. O Postgres oferece muitos recursos avançados e, embora as alterações sejam pequenas, elas podem fazer uma grande diferença, especialmente se isso impedir que complique sua infraestrutura.
Não exagere no índice
Evite índices desnecessários. Use índices de várias colunas com moderação. Muitos índices ocupam memória extra que ofusca melhores usos do cache do Postgres, o que é crucial para o desempenho.
O uso de uma ferramenta como EXPLAIN ANALYZE pode surpreendê-lo com a frequência com que o planejador de consultas realmente escolhe scans sequenciais de tabela. Considerando que muitos dos dados da sua tabela já estarão armazenados em cache, muitas vezes esses índices elaborados nem sequer serão utilizados.
Dito isto, se possuir consultas lentas, a primeira e mais óbvia solução é verificar se está faltando um índice na tabela. Os índices são vitais, mas deve usá-los corretamente.
Índices parciais economizam espaço
Um índice parcial pode economizar espaço, especificando quais valores são indexados. Por exemplo, caso desejar fazer o pedido até a data de inscrição de um usuário, mas se preocupa apenas com os usuários que se inscreveram:
CREATE INDEX user_signup_date ON users(signup_date) WHERE is_signed_up;
Compreendendo os tipos de índice do Postgres
Escolher o índice certo para seus dados pode melhorar o desempenho. Aqui estão alguns tipos de índice comuns e quando deve usar cada um.
Os índices B-tree são árvores binárias usadas para classificar os dados com eficiência. Eles são utilizados por padrão se executar o comando INDEX. Na maioria das vezes, um índice B-tree é suficiente. À medida que o dimensiona, as inconsistências podem ser um problema maior; portanto, use a extensão amcheck periodicamente.
Um índice de intervalo de bloco (BRIN) pode ser usado quando sua tabela já está naturalmente classificada por uma coluna e precisar classificá-la por essa coluna. Por exemplo, uma tabela de log que foi gravada sequencialmente, a configuração de um índice BRIN na coluna de timestamp permite que o servidor saiba que os dados já estão classificados.
Um índice de filtro bloom é perfeito para consultas com várias colunas em tabelas grandes, nas quais só precisa testar a igualdade. Ele usa uma estrutura matemática especial chamada filtro de bloom que se baseia na probabilidade e usa significativamente menos espaço.
CREATE INDEX i ON t USING bloom(col1, col2, col3);
SELECT * from t WHERE col1 = 5 AND col2 = 9 AND col3 = ‘x’;
Use a GIN or GiST index for efficient indexes based on composite values like text, arrays, and JSON.
Use um índice GIN ou GiST para índices eficientes com base em valores compostos como texto, matrizes e JSON.
Quando precisa de outro armazenamento de dados?
Existem casos legítimos para adicionar outro armazenamento de dados além do Postgres.
Tipos de dados especiais
Alguns armazenamentos de dados fornecem tipos de dados que simplesmente não consegue acessar no Postgres. Por exemplo, as funções de lista vinculada, bitmaps e HyperLogLog no Redis não estão disponíveis no Postgres.
Em uma inicialização anterior, tivemos que implementar um limite de frequência, que é um contador para usuários únicos em um site com base nos dados da sessão (como cookies). Pode haver milhões ou dezenas de milhões de usuários visitando um site. Limite de frequência significa que só mostra seu anúncio a cada usuário uma vez por dia.
O Redis possui um tipo de dados HyperLogLog perfeito para um limite de frequência. Ele aproxima a associação do conjunto com uma taxa de erro muito pequena, em troca do tempo O(1) e com uma pegada de memória muito pequena. PFADD adiciona um elemento a um conjunto HyperLogLog. Retorna 1 se o seu elemento ainda não estiver no conjunto e 0 se ele estiver no conjunto.
PFADD user_ids uid1
(integer) 1
PFADD user_ids uid2
(integer) 1
PFADD user_ids uid1
(integer) 0
Processamento pesado em tempo real
Se estiver em uma situação com muitos eventos de pub-sub, empregos e dezenas de processadores para coordenar, pode ser necessário uma solução mais especializada como o Apache Kafka. Os engenheiros do LinkedIn originalmente desenvolveram o Kafka para lidar com novos eventos do usuário, como cliques, convites e mensagens, e permitir que diferentes processadores lidem com a passagem de mensagens e jobs para processar os dados.
Pesquisa instantânea de texto
Se tiver um aplicativo em tempo real sob carga pesada, com mais de dez pesquisas em andamento ao mesmo tempo, e precisar de recursos como o preenchimento automático, poderá se beneficiar mais de uma solução de texto especializada como o Elasticsearch.
Conclusão
Redis, Elasticsearch e Kafka são poderosos, mas às vezes adicioná-los faz mais mal do que bem. Pode-se obter os recursos necessários com o Postgres aproveitando os recursos menos conhecidos que foram abordados aqui. Isto garante que aproveite ao máximo o Postgres e poder economizar tempo e ajudar a evitar complexidade e riscos adicionais.
Para economizar ainda mais tempo e dores de cabeça, considere usar um serviço gerenciado como o Heroku Postgres. A expansão é uma simples questão de adicionar réplicas de seguidores, a alta disponibilidade pode ser ativada com um único clique e o Heroku o realizá. Se realmente precisar expandir para além do Postgres, os outros repositórios de dados que mencionamos acima, como Redis, Apache Kafka e Elasticsearch, poderão ser facilmente provisionados no Heroku. Vá em frente e construa seus castelos no ar - mas ancore-os em uma base confiável, para que possa sonhar com um produto melhor aliado a uma bela experiência do cliente.
Para obter mais informações sobre o Postgres, ouça cargas de trabalho do banco de dados em nuvem com Jon Daniel no Software Engineering Daily.
Sobre o autor
Jason Skowronski é consultor técnico e proprietário do Dev Spotlight. Ele se concentra na criação de ótimos conteúdos para desenvolvedores e engenheiros de DevOps. Ele iniciou sua carreira como desenvolvedor de software na Amazon, depois ingressou na Loggly até sua aquisição pela SolarWinds. Ele agora trabalha como consultor de empresas líderes como Heroku e Rollbar para ajudar seus clientes a se manterem atualizados com as melhores práticas e as mais recentes inovações.