2 pontos por GN⁺ 2023-07-16 | 1 comentários | Compartilhar no WhatsApp
  • O OrioleDB, um novo mecanismo de armazenamento para PostgreSQL, elimina o processo de VACUUM, que consome muitos recursos, e resolve o problema de bloat em tabelas
  • O PostgreSQL tradicional exige vacuum manual e autovacuum devido à sua arquitetura MVCC, e ambos os métodos consomem recursos significativos do sistema
  • O OrioleDB processa alterações de dados com eficiência e consolida dados fragmentados por meio de undo logs em nível de linha e de bloco e mesclagem automática de páginas
  • Em um benchmark sintético, ao atualizar apenas um único índice, mesclar automaticamente páginas esparsas e aplicar WAL em nível de linha, alcançou TPS 5 vezes maior e economia de recursos
  • Ao resolver o antigo desafio do VACUUM, reduz a carga de manutenção e oferece melhorias de desempenho e experiência do usuário no PostgreSQL

História e limitações do VACUUM no PostgreSQL

  • O processo de VACUUM é um artefato histórico originado do conceito de infinite time-travel do projeto Berkley Postgres, conceito que depois foi abandonado pela comunidade
    • No entanto, isso levou à implementação de um sistema MVCC (Multi-Version Concurrency Control) vulnerável a bloat em tabelas
  • O MVCC é vantajoso para o processamento de transações concorrentes, mas introduziu a necessidade de vacuuming manual para limpar dados antigos e desnecessários
    • O vacuuming manual é uma tarefa intensiva em trabalho e uma possível fonte de ineficiência do sistema
  • Depois, foi introduzido o autovacuum automatizado para reduzir a carga de trabalho manual
    • Foi um grande avanço, mas não uma solução perfeita; mesmo sendo automático, ainda consome recursos significativos do sistema
    • Isso é citado como um dos motivos pelos quais a Uber migrou do PostgreSQL para o MySQL e como uma das 10 reclamações de Richard Branson sobre o PostgreSQL
  • A introdução de atualizações Heap-Only Tuples (HOT) e do microvacuum reduziu a necessidade de vacuum em tabelas inteiras
    • Ainda assim, o VACUUM continuou sendo uma operação intensiva em recursos, e as tabelas permaneceram vulneráveis a bloat
    • Isso foi mencionado como a parte do PostgreSQL mais odiada pela equipe da OtterTune
  • Apesar dessas limitações, muitas organizações e desenvolvedores continuam usando PostgreSQL por sua robustez, extensibilidade e comunidade forte
    • A OtterTune reconheceu o problema, mas decidiu continuar usando PostgreSQL

Principais recursos do OrioleDB

  • O OrioleDB é um novo mecanismo PostgreSQL desenvolvido com o objetivo principal de proteger tabelas contra bloat e eliminar a necessidade de manutenção periódica como o VACUUM
  • Ele faz isso com undo logs em nível de linha e de bloco e mesclagem automática de páginas
    • Undo logs em nível de linha e de bloco oferecem controle mais granular, permitindo processar alterações de dados com eficiência
    • O recurso de mesclagem automática de páginas consolida continuamente dados fragmentados em segundo plano
  • Como cada técnica funciona
    • O undo log em nível de linha permite atualizações in-place
    • O undo log em nível de bloco remove do armazenamento principal tuplas que foram excluídas, mas ainda são visíveis para algumas transações, liberando espaço para novas tuplas
    • A mesclagem automática de páginas esparsas protege tabelas e índices contra bloat mesmo após muitas exclusões
  • Como resultado, há menos intervenção manual, menor consumo de recursos e menor vulnerabilidade das tabelas a bloat

Benchmark

  • O benchmark sintético foi configurado com um script de inicialização que cria 1 tabela e 5 índices
    • Criação da tabela test com chave primária id e colunas value1~value4(float8), ts(timestamp)
    • Criação de índices em value1, value2, value3, value4 e ts, respectivamente
  • O script pgbench usa um formato de upsert que faz uma atualização esparsa de um índice em caso de conflito
    • Executa INSERT com um id aleatório no intervalo de 1 a 10.000.000; em caso de conflito, atualiza apenas ts
    • Essa atualização esparsa causa bloat de índice em tabelas PostgreSQL heap comuns
  • Vantagens do design do OrioleDB mostradas por esse benchmark
    • Graças ao undo log e às atualizações in-place, o OrioleDB atualiza apenas o único índice cujo valor mudou, enquanto o mecanismo heap do PostgreSQL, ao atualizar um único campo indexado, invalida o HOT e faz todos os índices serem atualizados
    • A mesclagem automática de páginas protege índices esparsos contra bloat, e páginas esparsas são mescladas automaticamente
    • O WAL em nível de linha ocupa muito menos espaço que o WAL em nível de bloco, gerando redução de IOPS ao registrar WAL
  • Números entregues pelo OrioleDB como resultado das melhorias acumuladas
    • TPS 5 vezes maior por transação
    • Carga de CPU 2,3 vezes menor por transação
    • IOPS 22 vezes menor por transação
    • Sem bloat em tabelas e índices

Importância do OrioleDB

  • Com a introdução do OrioleDB, a comunidade PostgreSQL entra em uma nova era em que o VACUUM se torna coisa do passado
  • Ele apresenta uma solução para um dos problemas mais antigos do PostgreSQL, oferecendo aos usuários maior eficiência e menor carga de manutenção

1 comentários

 
GN⁺ 2023-07-16
Opiniões no Hacker News
  • Ainda assim, algumas coisas me incomodam. O processamento em nível de linha cria problemas de alinhamento de escrita e de alinhamento de fsync, e páginas são mais fáceis de alinhar do que linhas de tamanho arbitrário
    O PostgreSQL é muito, talvez extremamente, conservador quanto à segurança dos dados, e isso é alcançado principalmente com fsync nos momentos adequados; o impacto disso se espalha por toda a pilha de I/O, incluindo o firmware dos SSDs, deixando tudo mais lento
    MVCC é muito bom para acesso concorrente, mas a documentação do Oriole não diz sob quais condições de concorrência o gráfico foi produzido
    O título e a introdução do documento do Oriole se concentram em resolver o VACUUM, mas não parecem demonstrar que o gráfico de “onda quadrada” visto no PostgreSQL seja realmente causado, em sua maior parte, pelo VACUUM. Outro benchmark da Percona (https://www.percona.com/blog/evaluating-checkpointing-in-postgresql/) não mostra esse padrão claro de onda quadrada
    Os autores provavelmente estão cientes desses problemas, então poderiam escrever um resumo de como os abordaram

    • O OrioleDB usa WAL em nível de linha, mas ainda usa páginas. O WAL em nível de linha se tornou possível graças a checkpoints copy-on-write, que fornecem uma imagem estruturalmente consistente da B-tree. Para mais detalhes, consulte a documentação de arquitetura
      https://github.com/orioledb/orioledb/blob/main/doc/arch.md
      Como o PostgreSQL é conservador quanto à segurança dos dados, o primeiro objetivo é se tornar uma extensão pura. Para virar parte do PostgreSQL, será preciso passar pelo teste do tempo
      É verdade que faltavam informações de concorrência, e adicionamos ao post do blog o tipo de VM e as informações de concorrência
      O padrão de onda quadrada é, de fato, causado pelos checkpoints. Aqui, a causa da melhoria na verdade não é o VACUUM, mas a forma de modificar apenas os índices relacionados, além do WAL em nível de linha, que reduz o I/O total
  • É legal, mas fico curioso para saber como vocês planejam acompanhar o ciclo de releases do projeto-mãe
    Se vocês fizeram um fork de um grande projeto open source e aplicaram mudanças consideráveis, e não acham que essas mudanças serão aceitas upstream, não sei se isso é uma boa ideia
    É preciso deixar claro se é um brinquedo feito por diversão ou um projeto sério que será mantido daqui para frente
    Se for um projeto sério, é preciso explicitar o plano para que ele não vire software abandonado no futuro, o plano para absorver releases futuros do projeto original, ou então o plano de se separar como um projeto completamente distinto
    Por ser uma extensão, parece que deve ser possível receber mudanças upstream do PostgreSQL, mas, se isso fosse fácil, ela teria virado parte do projeto PostgreSQL desde o início, então não parece tão simples

    • O autor já respondeu nos comentários do post
      “Correto. Mas há um longo caminho pela frente. No momento, o OrioleDB é uma extensão fornecida junto com patches no core do PostgreSQL. O objetivo de médio prazo é transformar o OrioleDB em uma extensão pura, e o objetivo de longo prazo é tornar o OrioleDB parte do core do PostgreSQL”
    • Você não pretende usar isso em produção nos próximos dias, então soa agressivo demais. Você também não manifestou intenção de apoiar financeiramente o projeto e, além disso, como outras pessoas apontaram, essa pergunta já tinha sido respondida
      Da próxima vez, seria melhor não chegar tão forte logo de início
    • Há um link de referência com a resposta já dada :)
      https://news.ycombinator.com/item?id=36742001
    • É um ponto razoável. Como alguém que já sofreu com problemas de VACUUM, fiquei curioso se isso é algo fundamentalmente necessário ou se pode ser corrigido
      Ver um exemplo corrigido certamente ajuda. Para uma empresa que tenha recursos para manter um fork do Postgres, ótimo; caso contrário, é preciso avaliar se a dificuldade de usar esse fork compensa em relação aos ganhos de desempenho
  • Já chega dessa história de que “a Uber migrou do Postgres para o MySQL”. A Uber saiu do Postgres que usava como banco de dados relacional para algo que, na prática, era seu próprio banco de dados não relacional, usando MySQL como armazenamento distribuído de chave-valor, então não é uma situação que se aplique diretamente à maioria dos usuários de Postgres
    De todo modo, esse desenho de MVCC que move dados antigos para logs/segmentos de undo também é usado no Oracle DB, então o funcionamento em si já foi validado
    A dificuldade comum é que ler versões antigas dos dados fica mais lento. É preciso procurá-las no log e, às vezes, os dados podem ser removidos do log antes de a transação terminar, causando o famigerado erro Snapshot Too Old
    Não vi no texto quando as linhas são removidas do log de undo. Se forem removidas quando não forem mais necessárias, parece que seria preciso uma quantidade parecida de trabalho de gerenciamento, e não está claro para mim de onde viria a melhoria. Se for um buffer circular que pode ficar sem espaço, como no Oracle, então transações longas começam a falhar sob alta carga de escrita, o que é bem desagradável

    • Registros de undo são truncados quando não são mais necessários para nenhuma transação
      Depende do que exatamente se quer dizer com “trabalho de gerenciamento”. Se olharmos para o volume de trabalho, registros antigos de undo podem ser removidos em lote de forma muito barata, por exemplo dando unlink em arquivos, e é daí que vem a melhoria. Não é necessário fazer varredura de VACUUM
      Se olharmos para uso de espaço, é verdade que o mesmo número de versões ocupa a mesma quantidade de espaço. Mas manter versões antigas de linhas em um armazenamento separado evita a degradação de longo prazo do armazenamento principal. O OrioleDB também implementa mesclagem automática de páginas esparsas
      O OrioleDB implementa um buffer circular em memória para o log de undo. Se o buffer circular não comportar todos os registros de undo, os registros mais antigos são despejados para o armazenamento. Atualmente não há limite para o tamanho do log de undo, e os registros são mantidos enquanto qualquer transação puder precisar deles, portanto não há erro “Snapshot Too Old”
      Ainda assim, dá para considerar implementar, como opção, um erro no estilo Oracle para permitir limitar o tamanho do undo. Também vale conferir o documento de arquitetura no GitHub
      https://github.com/orioledb/orioledb/blob/main/doc/arch.md
    • O SQL Server também evita VACUUM, talvez de uma forma parecida
      Claro que o MySQL evita VACUUM abrindo mão de bastante coisa em termos de concorrência
  • O título me deixou animado, mas a primeira impressão foi frustrante. O README principal no GitHub[1] parece texto promocional corporativo
    Até agora, o que consegui entender é que o OrioleDB é um novo mecanismo de armazenamento para PostgreSQL, que o PostgreSQL é o banco de dados “mais amado”, que o OrioleDB é uma extensão construída sobre outras extensões e que o OrioleDB abre as portas da nuvem
    Depois da onda de golpes com criptomoedas e Web 3.0, eu teria evitado esse tipo de abordagem ao lançar um projeto para estender e melhorar algo tão importante quanto o PostgreSQL
    [1] https://github.com/orioledb/orioledb

    • Imagino que você esteja se referindo a esta parte: “OrioleDB consists of an extension, building on the innovative table access method framework and other standard Postgres extension interfaces.”
      Acho difícil escrever de forma mais clara que isso. Métodos de acesso a tabelas são um recurso introduzido no PostgreSQL para dar suporte a mecanismos alternativos de armazenamento, como zheap, ou a armazenamentos orientados a colunas
      Mencionar esse fato é importante. Existem muitos forks do PostgreSQL com sistemas alternativos de armazenamento de dados acoplados, enquanto o OrioleDB foi projetado para funcionar como extensão em um PostgreSQL sem fork. Ainda não é assim, mas essa é a direção
      Para quem conhece PostgreSQL, o README parece bem claro
  • O design do Oriole parece exigir índices cientes de transações e remoção de entradas ponto a ponto, e isso tem seu próprio custo
    Por exemplo, algo equivalente ao GiST para índices espaciais parece trabalhoso de manter, pela natureza de não se saber exatamente a localização de cada tupla de índice, e o GIN para indexação de busca em texto completo poderia ficar muito grande por perder capacidade de compressão nas árvores de postings
    Além disso, em um cenário com tabelas organizadas por índice, não consigo imaginar bem como implementar algo equivalente ao BRIN. O BRIN permite excluir rapidamente grandes intervalos da tabela física dos resultados da consulta quando eles não contêm dados de interesse. Seria possível particionar por intervalo de chave primária, mas a densidade de valores da chave primária pode variar muito ao longo do tempo e entre faixas de valores
    Tenho curiosidade sobre como pretendem implementar esses métodos de índice mais complexos, mas muito úteis
    Há também problemas que podem surgir quando regras de ordenação, isto é, collations, mudam. Como o heap e o VACUUM do Postgres não conhecem a ordem de classificação, muitas vezes é possível corrigir danos após uma mudança de collation apagando e reinserindo linhas que ficaram em posições incorretas, e deixando o VACUUM limpar eventualmente as tuplas quebradas
    No Oriole, parece difícil fazer isso porque não daria para localizar por busca pontual a tupla original a ser removida, e corrigir casos conhecidos de corrupção de índice provavelmente exigiria reconstruir o índice inteiro, o que parece aumentar bastante o ônus de manutenção

    • Para uma funcionalidade semelhante ao GiST, estamos pensando em criar uma B-tree sobre alguma curva de preenchimento de espaço. Também planejamos adicionar union keys às páginas internas para tornar a busca nessa árvore mais rápida e simples
      Em uma funcionalidade semelhante ao GIN, a compressão de listas de postings ainda é possível. Uma opção viável é vincular registros de undo à lista de postings inteira, em vez de a um único item da lista de postings
      Como o BRIN usa tabelas organizadas por índice, não parece que será possível criar um análogo direto. Ainda assim, dá para fazer coisas interessantes com union keys nas páginas internas da chave primária
      O problema de collation é real e sério. Antes do GA, todos os índices sensíveis a collation provavelmente terão de ser fixados a uma versão específica de collation da libicu
  • A lógica do texto também é convincente, e os benchmarks parecem sustentar as alegações de desempenho, mas não entendo bem a distinção entre o novo mecanismo de armazenamento proposto — isto é, o OrioleDB — e o próprio PostgreSQL.
    Tirando a motivação comercial e o desejo de lucrar com as inovações abordadas no texto, há algum motivo para comercializar isso como um novo banco de dados chamado OrioleDB, em vez de contribuir essas melhorias upstream?

    • Vejo o OrioleDB como o futuro engine do PostgreSQL e gostaria que ele se tornasse o engine padrão.
      Mas as mudanças do OrioleDB são grandes demais para serem incorporadas gradualmente. Por isso, a comparação está sendo feita entre o OrioleDB e o engine atual do PostgreSQL, incluindo não só o heap, mas também vários subsistemas.
    • A visão de Alexander Korotkov parece se basear em sua experiência como committer do Postgres: como essas mudanças são grandes demais para serem aceitas upstream, ele está seguindo o caminho de um engine separado.
      Para mais detalhes, veja especialmente os slides 9 a 11 em https://www.socallinuxexpo.org/sites/default/files/presentations/solving-postgres-wicked-problems.pdf
    • Essas mudanças são grandes demais para serem integradas ao próprio engine do PostgreSQL. Isso porque elas alteram fundamentalmente a abordagem de MVCC.
  • Se for uma extensão de engine, fico curioso para saber se há impacto ao usá-la junto com outras extensões. Por exemplo, timescaledb[0] funciona sobre tabelas subjacentes.
    Fico me perguntando que efeito algo assim teria:
    create table xyz(...) using orioledb;
    select create_hypertable(xyz, ts);
    [0] https://github.com/timescale/timescaledb

  • Será que o OrioleDB teria interesse em prometer um formato em disco estável, eliminando a necessidade de um procedimento de upgrade entre versões major do Postgres? Parece uma oportunidade para resolver esse problema.

    • O motivo pelo qual é necessário um procedimento de upgrade no PostgreSQL geralmente não é o formato em disco de baixo nível do heap do Postgres ou do método de acesso a tabelas do OrioleDB, mas sim mudanças no catálogo do Postgres.
      Coisas como adicionar novos tipos e suas funções de suporte precisam ser inseridas por algum procedimento de upgrade. Também há outras mudanças de catálogo que alteram o layout de colunas das tabelas de catálogo, e nesse caso também é necessário um procedimento para atualizar os dados armazenados entre versões.
      Sem um procedimento de upgrade, não é possível alterar o catálogo. É por isso que, no PostgreSQL, apenas upgrades de versões minor podem ser feitos só com a substituição dos binários, com rollback seguro e sem problemas.
      Se as atualizações ficassem limitadas apenas a mudanças de API interna, planner e executor, o desenvolvimento ficaria seriamente restringido. Acho difícil que o OrioleDB elimine a necessidade desse procedimento de upgrade.
    • À primeira vista, isso parece inalcançável, a menos que se esteja disposto a abrir mão de bastante desempenho. O formato em disco só muda quando há um bom motivo.
    • Não vejo bem como isso ajudaria. O PostgreSQL já promete, na prática, um formato em disco estável para tabelas e índices, e é por isso que o pg_upgrade funciona.
      A maior parte do trabalho de upgrade de um cluster vem de reescrever as tabelas de catálogo. Além disso, para a maioria das cargas de trabalho, o pg_upgrade é muito rápido, então também não vejo onde estaria o grande ganho.
  • A expressão “redução de 2,3x na sobrecarga de CPU por transação” me incomoda. No Postgres, o uso de CPU oscila de 5% a 65%, enquanto no Oriole fica sempre em 90%
    Previsibilidade é bom, mas elevar a faixa baixa em 85% não é algo bastante preocupante?

    • Em geral, é melhor aproveitar a CPU ao máximo. O Oriole parece ter uma demanda de I/O muito menor, processar muito mais transações e ter se tornado limitado por CPU
      A boa notícia é que isso significa que, ao escalar verticalmente com uma CPU mais forte, dá para obter mais desempenho no Oriole. Já o Postgres não continuaria ganhando desempenho da mesma forma
      Do ponto de vista de um sistema operacional de desktop, talvez dê para usar o tempo ocioso do servidor Postgres para outra coisa, mas em servidores normalmente se quer uma máquina que faça uma coisa só e seja otimizada para isso
    • Pela minha interpretação, isso acontece porque saturaram a CPU até 90% usando o limite de TPS empregado na comparação. Pelo menos neste gráfico, o TPS do Oriole é estável e muito mais alto que o do pg
      Se o TPS for reduzido, a CPU também deve cair proporcionalmente, e aqui parece que a intenção é mostrar até onde ele consegue chegar
    • Se o teto de uso de CPU deixa de ser uma limitação, fica mais fácil reduzir a utilização mantendo desempenho mais ou menos proporcional, então isso não é um problema
      Se você limitar o sistema a 60% de CPU, os números absolutos podem mudar, mas, se no mesmo nível de uso o TPS for 1,8x maior, é vitória de qualquer jeito. Parece um número bem bom, mais do que um truque de marketing
      Se uma CPU de servidor cara custa X dólares por unidade, mas você só consegue usar 60% dela — e, na prática, é só isso mesmo que dá para usar —, é como queimar 0,4X dólar por unidade
      Se você consegue levar a carga de trabalho verticalmente até saturar 90% de uma máquina, em geral é fácil aplicar QoS e técnicas de isolamento para manter uma saturação menor com desempenho proporcional. O inverso não é verdadeiro. Se você só consegue usar 60% da saturação total da máquina e precisa escalar horizontalmente, para passar de 90% será necessário redesenhar, e foi exatamente esse redesenho que aconteceu aqui
    • No mesmo equipamento, o desempenho agora ficou 5 vezes melhor. O TPS é 5 vezes maior. Seria preciso testar de novo com mais hardware, mas, se ele conseguir manter 3 vezes mais desempenho também na faixa baixa, pode ser uma boa alternativa para alguns usuários
      Dizem que, como resultado acumulado das melhorias, o OrioleDB oferece TPS 5 vezes maior, carga de CPU por transação 2,3 vezes menor, IOPS por transação 22 vezes menor e ausência de bloat em tabelas e índices
    • Foi um teste de desempenho, e é bem provável que o objetivo fosse aplicar continuamente, por bastante tempo, a carga máxima que cada engine de banco de dados consegue suportar
      A oscilação da carga de CPU não é o Postgres “escalando”, mas sim entrando periodicamente em gargalos de desempenho. Provavelmente por causa da necessidade de executar VACUUM, algo muito sensível a I/O
      Por isso, em vez de usar I/O para processar consultas, o Postgres usa I/O para tarefas de limpeza, e o TPS e o uso de CPU despencam juntos
      Já o Oriole gerencia uma vazão muito maior de forma bem mais consistente. Se você pisar no acelerador, qual carro preferiria: um que segue estável a 100 mph, ou um que, mesmo com o pedal no fundo, oscila violentamente entre 40 e 70 mph?
  • No texto há um link com um título bem interessante: “10 coisas que Richard Branson odeia no PostgreSQL”. No fim, descobri que quem escreveu aquele blog não foi Richard, e sim Rick Branson

    • Rick é apelido de Richard
    • “Richard Branson” não é um identificador único. Talvez todos nós devêssemos usar UUIDs
    • Essa parte também me chamou a atenção. Fiquei pensando por que eu deveria me importar com o que o CEO da Virgin pensa sobre bancos de dados
      Ah, não era ele