PostgreSQL
 sql >> Base de Dados >  >> RDS >> PostgreSQL

Ajustando as operações de entrada/saída (E/S) para PostgreSQL


O PostgreSQL é um dos bancos de dados de código aberto mais populares do mundo e tem implementações bem-sucedidas em vários ambientes de missão crítica em vários domínios, usando aplicativos OLTP de última geração em tempo real que realizam milhões e bilhões de transações por dia. O PostgreSQL I/O é bastante confiável, estável e tem alto desempenho em praticamente qualquer hardware, inclusive na nuvem.

Para garantir que os bancos de dados funcionem na escala esperada com tempos de resposta esperados, há necessidade de alguma engenharia de desempenho. Bem, a obtenção de um bom desempenho do banco de dados depende de vários fatores. O desempenho do banco de dados pode ficar ruim por vários motivos, como dimensionamento de infraestrutura, estratégia de manutenção de banco de dados ineficiente, código SQL ruim ou processos de banco de dados mal configurados que não utilizam todos os recursos disponíveis - CPU, memória, largura de banda de rede e E/S de disco.

O que pode causar a degradação do desempenho do banco de dados?

  • Consultas mal escritas com junções, lógica etc. incorretas que consomem muita CPU e memória
  • Consultas realizando verificações de tabela completa em tabelas grandes devido à indexação imprópria
  • Má manutenção do banco de dados sem estatísticas adequadas
  • Planejamento de capacidade ineficiente resultando em infraestrutura inadequadamente dimensionada
  • Projeto lógico e físico inadequado
  • Nenhum pool de conexões em vigor, o que faz com que os aplicativos façam um grande número de conexões de maneira incontrolável

Portanto, há muitas áreas em potencial que podem causar problemas de desempenho. Uma das áreas significativas que gostaria de focar neste blog é como ajustar o desempenho de E/S (entrada/saída) do PostgreSQL. Ajustar as operações de entrada/saída do PostgreSQL é essencial, especialmente em um ambiente altamente transacional como OLTP ou em um ambiente de data warehousing com análise de dados complexos em conjuntos de dados de grande porte.

Na maioria das vezes, os problemas de desempenho do banco de dados são causados ​​principalmente devido à alta E/S. Isso significa que os processos de banco de dados estão gastando mais tempo gravando ou lendo do disco. Qualquer operação de dados em tempo real é limitada por E/S, é imperativo garantir que o banco de dados seja ajustado por E/S. Neste blog, focarei nos problemas comuns de E/S que os bancos de dados PostgreSQL podem encontrar em ambientes de produção em tempo real.

Ajustando a E/S do PostgreSQL


Ajustar a E/S do PostgreSQL é fundamental para construir uma arquitetura de banco de dados escalável e de alto desempenho. Vejamos vários fatores que afetam o desempenho de E/S:
  • Indexação
  • Particionamento
  • Pontos de verificação
  • VACUUM, ANALYZE (com FILLFACTOR)
  • Outros problemas de E/S
  • E/S do PostgreSQL na nuvem
  • Ferramentas

Indexação


A indexação é uma das principais técnicas de ajuste que desempenha um papel fundamental na melhoria do desempenho de E/S do banco de dados. Isso se aplica a qualquer banco de dados realmente. O PostgreSQL suporta vários tipos de índice que podem acelerar bastante as operações de leitura, proporcionando maior escalabilidade para os aplicativos. Embora a criação de índices seja bastante simples e direta, é essencial que os DBAs e desenvolvedores tenham o conhecimento de que tipo de índice escolher e em quais colunas. Este último é baseado em vários fatores como complexidade da consulta, tipo de dados, cardinalidade dos dados, volume de gravações, tamanho dos dados, arquitetura do disco, infraestrutura (nuvem pública, nuvem privada ou local), etc.

Embora a indexação possa melhorar drasticamente o desempenho de leitura de consulta, ela também pode diminuir a velocidade das gravações que atingem as colunas indexadas. Vamos ver um exemplo:

Impacto dos índices nas operações READ


Uma tabela chamada emp com cerca de 1 milhão de linhas.

LEIA o desempenho sem um índice

postgres=# select * from emp where eid=10;

 eid | ename    | peid | did  |    doj
-----+---------------+--------+------+------------
  10 | emp        |          |   1   | 2018-06-06
(1 row)
 
Time: 70.020 ms => took about 70+ milli-seconds to respond with on row

LEIA o desempenho com um índice


Vamos colocar um índice na coluna eid e ver a diferença
postgres=# create index indx001 on emp ( eid );
CREATE INDEX

postgres=# select * from emp where eid=10;

 eid | ename  | peid | did |    doj
------+-------------+-------+------+------------
  10 | emp      |          |   1   | 2018-06-06
(1 row)
 
Time: 0.454 ms =>  0.4+ milli-seconds!!! thats a huge difference - isn’t it?

Portanto, a indexação é importante.

Impacto dos índices nas operações WRITE


Os índices diminuem o desempenho das gravações. Embora os índices tenham impacto em todos os tipos de operações de gravação, vejamos algumas análises sobre o impacto dos índices nos INSERTs

Inserindo 1 milhão de linhas em uma tabela sem índices

postgres=# do $$
postgres$# declare
postgres$# i integer;
postgres$# begin
postgres$# for i in 1..1000000 loop
postgres$# insert into emp values (i,'emp',null,1,current_date);
postgres$# end loop;
postgres$# end $$;
DO

Time: 4818.470 ms (00:04.818) => Takes about 4.8 seconds

Inserindo o mesmo 1 milhão de linhas com um índice


Vamos criar um índice primeiro
postgres=# create index indx001 on emp ( eid );
CREATE INDEX

postgres=# do $$
postgres$# declare
postgres$# i integer;
postgres$# begin
postgres$# for i in 1..1000000 loop
postgres$# insert into emp values (i,'emp',null,1,current_date);
postgres$# end loop;
postgres$# end $$;
DO

Time: 7825.494 ms (00:07.825) =>  Takes about 7.8 seconds

Assim, como podemos observar, o tempo de INSERT aumentou 80% com apenas um índice e pode demorar muito mais para terminar quando há vários índices. Pode ficar ainda pior quando há índices baseados em funções. É com isso que os DBAs têm que conviver! Os índices aumentarão o desempenho de gravação. No entanto, existem maneiras de resolver esse problema, que depende da arquitetura do disco. Se o servidor de banco de dados estiver usando vários sistemas de arquivos em disco, os índices e tabelas poderão ser colocados em vários espaços de tabela localizados em vários sistemas de arquivos em disco. Desta forma, um melhor desempenho de E/S pode ser alcançado.

DICAS de gerenciamento de índice

  • Entenda a necessidade de índices. A indexação inteligente é fundamental.
  • Evite criar vários índices e, definitivamente, nenhum índice desnecessário, isso pode realmente prejudicar o desempenho de gravação.
  • Monitore o uso de índices e elimine quaisquer índices não utilizados.
  • Quando as colunas indexadas estão sujeitas a alterações de dados, os índices também ficam inchados. Portanto, reorganize os índices regularmente.

Particionamento


Uma estratégia de particionamento eficaz pode reduzir muito os problemas de desempenho de E/S. Tabelas grandes podem ser particionadas com base na lógica de negócios. O PostgreSQL suporta particionamento de tabelas. Embora não suporte totalmente todos os recursos no momento, só pode ajudar com alguns dos casos de uso em tempo real. No PostgreSQL, as tabelas filhas particionadas são completamente individuais para a tabela mestre, o que é um gargalo. Por exemplo, restrições criadas na tabela mestre não podem ser herdadas automaticamente para as tabelas filhas.

No entanto, do ponto de vista do balanceamento de E/S, o particionamento pode realmente ajudar. Todas as partições filhas podem ser divididas em vários espaços de tabela e sistemas de arquivos de disco. As consultas com um intervalo de datas na cláusula “where” que atingem a tabela, particionadas com base no intervalo de datas, podem se beneficiar do particionamento apenas verificando uma ou duas partições em vez da tabela completa.

Ponto de verificação


Os pontos de verificação definem o estado consistente do banco de dados. Eles são críticos e é importante que os pontos de verificação ocorram regularmente o suficiente para garantir que as alterações de dados sejam salvas permanentemente em disco e que o banco de dados esteja em estado consistente o tempo todo. Dito isto, a configuração inadequada de pontos de verificação pode levar a problemas de desempenho de E/S. Os DBAs devem ser meticulosos na configuração de pontos de verificação para garantir que não haja picos de E/S e isso também depende de quão bons são os discos e quão bem o layout dos arquivos de dados é arquitetado.

Qual ​​ponto de verificação faz?


Em termos simples, os pontos de verificação garantirão:
  • Todos os dados confirmados são gravados nos arquivos de dados no disco.
  • arquivos de obstrução são atualizados com status de confirmação.
  • Os arquivos de log de transações no diretório pg_xlog (agora pg_wal) são reciclados.

Isso explica como os pontos de verificação de E/S são intensivos. Existem parâmetros no postgresql.conf que podem ser configurados/ajustados para controlar o comportamento do checkpoint e esses parâmetros são max_wal_size, min_wal_size, checkpoint_timeout e checkpoint_completion_target. Esses parâmetros decidirão com que frequência os pontos de verificação devem ocorrer e em quanto tempo os pontos de verificação devem ser concluídos.

Como entender qual configuração é melhor para pontos de verificação? Como ajustá-los?

Aqui estão algumas dicas:
  • Avalie o TPS do banco de dados. Avalie o volume total de transações que ocorrem no banco de dados em um dia útil e também identifique em que momento o maior número de transações atinge o banco de dados.
  • Discutir com desenvolvedores de aplicativos e outras equipes técnicas regularmente para entender as estatísticas de taxa de transação do banco de dados, bem como o crescimento futuro de transações.
  • Isso também pode ser feito no banco de dados:

    • Monitore o banco de dados e avalie o número de transações que ocorrem durante o dia. Isso pode ser feito consultando tabelas pgcatalog como pg_stat_user_tables.

    • Avalie o número de arquivos de arquivo wal gerados por dia

    • Monitore para entender o desempenho dos pontos de verificação ativando o parâmetro log_checkpoints
      2018-06-06 15:03:16.446 IST [2111] LOG:  checkpoint starting: xlog
      2018-06-06 15:03:22.734 IST [2111] LOG:  checkpoint complete: wrote 12112 buffers (73.9%); 0 WAL file(s) added, 0 removed, 25 recycled; write=6.058 s, sync=0.218 s, total=6.287 s; sync files=4, longest=0.178 s, average=0.054 s; distance=409706 kB, estimate=412479 kB

    • Entenda se a configuração do ponto de verificação atual é boa o suficiente para o banco de dados. Configure o parâmetro checkpoint_warning (configurado por padrão para 30 segundos) para ver os avisos abaixo nos arquivos de log postgres.
      2018-06-06 15:02:42.295 IST [2111] LOG:  checkpoints are occurring too frequently (11 seconds apart)
      2018-06-06 15:02:42.295 IST [2111] HINT:  Consider increasing the configuration parameter "max_wal_size".

O que significa o aviso acima?


Os pontos de verificação geralmente ocorrem sempre que max_wal_size (1 GB por padrão, o que significa 64 arquivos WAL) de arquivos de log são preenchidos ou quando checkpoint_timeout (a cada 5 minutos a cada padrão) é atingido. O aviso acima significa que o max_wal_size configurado não é adequado e os pontos de verificação estão ocorrendo a cada 11 segundos, o que significa que 64 arquivos WAL no diretório PG_WAL estão sendo preenchidos em apenas 11 segundos, o que é muito frequente. Em outras palavras, se houver transações menos frequentes, os pontos de verificação ocorrerão a cada 5 minutos. Portanto, como a dica sugere, aumente o parâmetro max_wal_size para um valor maior, o parâmetro max_min_size pode ser aumentado para o mesmo ou menor que o anterior.

Outro parâmetro crítico a ser considerado da perspectiva de desempenho de E/S é checkpoint_completion_target, que é configurado por padrão para 0,5.

checkpoint_completion_target =0,5 x checkpoint_timeout =2,5 minutos

Isso significa que os pontos de verificação têm 2,5 minutos para sincronizar os blocos sujos com o disco. 2,5 minutos são suficientes? Isso precisa ser avaliado. Se o número de blocos sujos a serem gravados for muito alto, 2,5 minutos podem parecer muito, muito agressivos e é quando um pico de E/S pode ser observado. A configuração do parâmetro completion_target deve ser feita com base nos valores max_wal_size e checkpoint_timeout. Se esses parâmetros forem aumentados para um valor mais alto, considere aumentar checkpoint_completion_target adequadamente.

VACUAR, ANALISAR (com FILLFACTOR)


VACUUM é um dos recursos mais poderosos do PostgreSQL. Ele pode ser usado para remover bloats (espaço fragmentado) dentro de tabelas e índices e é gerado por transações. O banco de dados deve ser submetido a VACUUMing regularmente para garantir uma manutenção saudável e melhor desempenho. Novamente, não VACUUMing o banco de dados regularmente pode levar a sérios problemas de desempenho. ANALYZE deve ser executado junto com VACUUM (VACUUM ANALYZE) para garantir estatísticas atualizadas para o planejador de consultas.

A VACUUM ANALYZE pode ser realizada de duas formas:manual, automática ou ambas. Em um ambiente de produção em tempo real, geralmente são ambos. O VACUUM automático é habilitado pelo parâmetro “autovacuum” que por padrão está configurado para “on”. Com o autovacuum habilitado, o PostgreSQL inicia automaticamente o VACUUMing das tabelas periodicamente. As tabelas candidatas que precisam de vácuo são coletadas por processos de autovacuum com base em vários limites definidos por vários parâmetros de autovacuum*, esses parâmetros podem ser ajustados / ajustados para garantir que os inchaços das tabelas sejam limpos periodicamente. Vejamos alguns parâmetros e seu uso -

Parâmetros de vácuo automático

autovacuum=on Este parâmetro é usado para habilitar/desabilitar o autovacuum. O padrão é "ativado".
log_autovacuum_min_duration =-1 Registra a duração do processo de autovacuum. Isso é importante para entender por quanto tempo o processo de autovacuum foi executado.
autovacuum_max_workers =3 Número de processos de autovacuum necessários. Isso depende de quão agressivas são as transações de banco de dados e quantas CPUs você pode oferecer para processos de autovacuum.
autovacuum_naptime =1 min Tempo de descanso de autovacuum entre execuções de autovacuum.

Parâmetros que definem o limite para o início do processo de Autovacuum


O(s) trabalho(s) de vácuo automático é(ão) iniciado(s) quando um determinado limite é atingido. Abaixo estão os parâmetros que podem ser usados ​​para definir um determinado limite, com base no qual o processo de autovacuum será iniciado.
autovacuum_vacuum_threshold =50 A tabela será limpa quando no mínimo 50 linhas forem atualizadas/excluídas em uma tabela.
autovacuum_analyze_threshold =50 A tabela será analisada quando no mínimo 50 linhas forem atualizadas/excluídas em uma tabela.
autovacuum_vacuum_scale_factor =0,2 A tabela será limpa quando no mínimo 20% das linhas forem atualizadas/excluídas em uma tabela.
autovacuum_analyze_scale_factor =0,1 A tabela será limpa quando no mínimo 10% das linhas forem atualizadas/excluídas em uma tabela.

Os parâmetros acima do limite podem ser modificados com base no comportamento do banco de dados. Os DBAs precisarão analisar e identificar as tabelas quentes e garantir que essas tabelas sejam limpas com a maior frequência possível para garantir um bom desempenho. Chegar a um determinado valor para esses parâmetros pode ser um desafio em um ambiente de alta transação, em que as alterações de dados acontecem a cada segundo. Muitas vezes percebi que os processos de autovacuum demoram bastante para serem concluídos, acabando por consumir muitos recursos nos sistemas de produção.

Sugiro não depender completamente do processo de autovacuum, a melhor maneira é agendar um trabalho noturno de VACUUM ANALYZE para que a carga do autovacuum seja reduzida. Para começar, considere manualmente VACUUMing grandes tabelas com uma alta taxa de transação.

VÁCUO COMPLETO


VACUUM FULL ajuda a recuperar o espaço inchado nas tabelas e índices. Este utilitário não pode ser usado quando o banco de dados está online, pois bloqueia a tabela. As tabelas devem ser submetidas a VACUUM FULL somente quando os aplicativos forem encerrados. Os índices também serão reorganizados junto com as tabelas durante o VACUUM FULL.

Vamos dar uma olhada no impacto do VACUUM ANALYZE

Inchaços:como identificar inchaços? Quando os inchaços são gerados?


Aqui estão alguns testes:

Eu tenho uma tabela de tamanho 1 GB com 10 milhões de linhas.
postgres=# select pg_relation_size('pgbench_accounts')/1024/1024/1024;

 ?column? 
----------------
        1

postgres=# select count(*) From pgbench_accounts ;
  count   
-----------------
 10000000

Vejamos o impacto dos bloats em uma consulta simples:select * from pgbench_accounts;

Abaixo está o plano de explicação para a consulta:
postgres=# explain analyze select * from pgbench_accounts;

QUERY PLAN
------------------------------------------------------------------------------------------------------------------------------------------------
 Seq Scan on pgbench_accounts  (cost=0.00..263935.00 rows=10000000 width=97) 
 (actual time=0.033..1054.257 rows=10000000 loops=1)
 Planning time: 0.255 ms
 Execution time: 1494.448 ms

Agora, vamos atualizar todas as linhas da tabela e ver o impacto da consulta SELECT acima.
postgres=# update pgbench_accounts set abalance=1;
UPDATE 10000000

postgres=# select count(*) From pgbench_accounts ;
  count   
-----------------
 10000000

Abaixo está o EXPLAIN PLAN da execução da query post UPDATE.
postgres=# explain analyze select * from pgbench_accounts;

QUERY PLAN                                                             
----------------------------------------------------------------------------------------------------------------------------------------------------------
 Seq Scan on pgbench_accounts  (cost=0.00..527868.39 rows=19999939 width=97) 
 (actual time=404.474..1520.175 rows=10000000 loops=1)
 Planning time: 0.051 ms
 Execution time: 1958.532 ms

O tamanho da tabela aumentou para 2 GB após o UPDATE
postgres=# select pg_relation_size('pgbench_accounts')/1024/1024/1024;

 ?column? 
-----------------
        2

Se você puder observar e comparar os números de custo do EXPLAIN PLAN anterior, há uma enorme diferença. O custo aumentou em uma grande margem. Mais importante, se você observar com atenção, o número de linhas (pouco mais de 19 milhões) que estão sendo verificadas após o UPDATE é maior, o que é quase duas vezes o número real de linhas existentes (10 milhões). Isso significa que o número de linhas inchadas é de mais de 9 milhões e o tempo real também aumentou e o tempo de execução aumentou de 1,4 segundos para 1,9 segundos.

Então, esse é o impacto de não VACUUMing na TABLE após o UPDATE. Os números EXPLAIN PLAN acima significam precisamente que a mesa está inchada.

Como identificar se a mesa está inchada? Use o módulo de contribuição pgstattuple:
postgres=# select * from pgstattuple('pgbench_accounts');
 table_len  | tuple_count | tuple_len  | tuple_percent | dead_tuple_count | dead_tuple_len | dead_tuple_percent | free_space | free_percent 
------------+-------------+------------+---------------+------------------+----------------+--------------------+------------+--------------
 2685902848 |    10000000 | 1210000000 |         45.05 |          9879891 |     1195466811 |              44.51 |   52096468 |         1.94

O número acima indica que metade da mesa está inchada.

Vamos VACUUM ANALYZE a tabela e veja o impacto agora:
postgres=# VACUUM ANALYZE pgbench_accounts ;
VACUUM

postgres=# explain analyze select * from pgbench_accounts;

QUERY PLAN
-----------------------------------------------------------------------------------------------------------------------------------------------
 Seq Scan on pgbench_accounts  (cost=0.00..428189.05 rows=10032005 width=97) 
 (actual time=400.023..1472.118 rows=10000000 loops=1)
 Planning time: 4.374 ms
 Execution time: 1913.541 ms

Após VACUUM ANALYZE, os números de custo diminuíram. Agora, o número de linhas verificadas está chegando perto de 10 milhões, também o tempo real e o tempo de execução não mudaram muito. Isso porque, embora os inchaços na mesa tenham desaparecido, o tamanho da mesa a ser escaneada permanece o mesmo. Abaixo está a saída pgstattuple post VACUUM ANALYZE.
postgres=# select * from pgstattuple('pgbench_accounts');

 table_len  | tuple_count | tuple_len  | tuple_percent | dead_tuple_count | dead_tuple_len | dead_tuple_percent | free_space | free_percent 
------------+-------------+------------+---------------+------------------+----------------+--------------------+------------+--------------
 2685902848 |    10000000 | 1210000000 |         45.05 |             0 |              0 |                  0 | 1316722516 |        49.02

O número acima indica que todos os inchaços (tuplas mortas) desapareceram.

Vejamos o impacto do VACUUM FULL ANALYZE e vejamos o que acontece:
postgres=# vacuum full analyze pgbench_accounts ;
VACUUM

postgres=# explain analyze select * from pgbench_accounts;

                            QUERY PLAN                                                            
---------------------------------------------------------------------------
 Seq Scan on pgbench_accounts  (cost=0.00..263935.35 rows=10000035 width=97) 
(actual time=0.015..1089.726 rows=10000000 loops=1)
 Planning time: 0.148 ms
 Execution time: 1532.596 ms

Se você observar, os números do tempo real e do tempo de execução são semelhantes aos números antes de UPDATE. Além disso, o tamanho da tabela agora diminuiu de 2 GB para 1 GB.
postgres=# select pg_relation_size('pgbench_accounts')/1024/1024/1024;

 ?column? 
-----------------
        1

Esse é o impacto do VACUUM FULL.

FILFATOR


FILLFACTOR é um atributo muito importante que pode fazer uma diferença real na estratégia de manutenção do banco de dados em nível de tabela e índice. Este valor indica a quantidade de espaço a ser utilizada pelos INSERTs dentro de um bloco de dados. O valor padrão de FILLFACTOR é 100%, o que significa que os INSERTs podem utilizar todo o espaço disponível em um bloco de dados. Isso também significa que não há espaço disponível para UPDATEs. Esse valor pode ser reduzido para um determinado valor para tabelas altamente atualizadas.

Este parâmetro pode ser configurado para cada tabela e um índice. Se FILLFACTOR estiver configurado para o valor ideal, você poderá ver uma diferença real no desempenho do VACUUM e no desempenho da consulta também. Em suma, os valores ideais de FILLFACTOR garantem que um número desnecessário de blocos não seja alocado.

Vejamos o mesmo exemplo acima -

A tabela tem um milhão de linhas
postgres=# select count(*) From pgbench_accounts ;
  count   
-----------------
 10000000

Antes de atualizar o tamanho da tabela é de 1 GB
postgres=# select pg_relation_size('pgbench_accounts')/1024/1024/1024;

?column? 
--------
   1

postgres=# update pgbench_accounts set abalance=1;
UPDATE 10000000

Após a atualização, o tamanho da tabela aumentou para 2 GB após o UPDATE
postgres=# select pg_relation_size('pgbench_accounts')/1024/1024/1024;

?column? 
---------
    2

Isso significa que o número de blocos alocados para a tabela aumentou em 100%. Se o FILLFACTOR foi configurado, o tamanho da tabela pode não ter aumentado por essa margem.

Como saber qual valor configurar para FILLFACTOR?


Tudo depende de quais colunas estão sendo atualizadas e do tamanho das colunas atualizadas. Em geral, seria bom avaliar o valor FILLFACTOR testando-o em bancos de dados UAT. Se as colunas que estão sendo atualizadas forem, digamos, 10% de toda a tabela, considere configurar o fator de preenchimento para 90% ou 80%.

Observação importante:
Se você alterar o valor de FILLFACTOR para a tabela existente com os dados, será necessário fazer um VACUUM FULL ou uma reorganização da tabela para garantir que o valor de FILLFACTOR esteja em vigor para os dados existentes.

DICAS DE ASPIRAÇÃO

  • Como dito acima, considere executar o trabalho VACUUM ANALYZE manualmente todas as noites nas tabelas muito usadas, mesmo quando o autovacuum estiver ativado.
  • Considere executar VACUUM ANALYZE em tabelas após INSERT em massa. Isso é importante, pois muitos acreditam que VACUUMing pode não ser necessário após INSERTs.
  • Monitore para garantir que as tabelas altamente ativas sejam VACUUMed regularmente consultando a tabela pg_stat_user_tables.
  • Use o módulo contrib pg_stattuple para identificar o tamanho do espaço inchado dentro dos segmentos da tabela.
  • O utilitário VACUUM FULL não pode ser usado em sistemas de banco de dados de produção. Considere usar ferramentas como pg_reorg ou pg_repack, que ajudarão a reorganizar tabelas e índices online sem bloqueios.
  • Certifique-se de que o processo AUTOVACUUM seja executado por mais tempo durante o horário comercial (tráfego intenso).
  • Ative o parâmetro log_autovacuum_min_duration para registrar os tempos e a duração dos processos AUTOVACUUM.
  • É importante garantir que FILLFACTOR esteja configurado para um valor ideal em tabelas e índices de alta transação.
Baixe o whitepaper hoje PostgreSQL Management &Automation with ClusterControlSaiba o que você precisa saber para implantar, monitorar, gerenciar e dimensionar o PostgreSQLBaixe o whitepaper

Outros problemas de E/S

Classificação de disco


As consultas que executam a classificação são outra ocorrência comum em bancos de dados de produção em tempo real e a maioria delas não pode ser evitada. Consultas usando cláusulas como GROUP BY, ORDER BY, DISTINCT, CREATE INDEX, VACUUM FULL etc. executam a classificação e a classificação pode ocorrer no disco. A classificação ocorre na memória se a seleção e a classificação forem feitas com base em colunas indexadas. É aqui que os índices compostos desempenham um papel fundamental. Os índices são armazenados em cache de forma agressiva na memória. Caso contrário, se houver a necessidade de classificar os dados no disco, o desempenho diminuirá drasticamente.

Para garantir que a classificação ocorra na memória, o parâmetro work_mem pode ser usado. Este parâmetro pode ser configurado para um valor tal que toda a ordenação possa ser feita na memória. A principal vantagem deste parâmetro é que, além de configurá-lo em postgresql.conf, ele também pode ser configurado em nível de sessão, nível de usuário ou nível de banco de dados. Quanto deve ser o valor work_mem? Como saber quais consultas estão realizando a classificação de disco? Como monitorar consultas que executam a classificação de disco em um banco de dados de produção em tempo real?

A resposta é - configure o parâmetro log_temp_files para um determinado valor. O valor está em bytes, um valor de 0 registra todos os arquivos temporários (junto com seus tamanhos) gerados no disco devido à classificação do disco. Uma vez configurado o parâmetro, você poderá ver as seguintes mensagens nos arquivos de log
2018-06-07 22:48:02.358 IST [4219] LOG:  temporary file: path "base/pgsql_tmp/pgsql_tmp4219.0", size 200425472
2018-06-07 22:48:02.358 IST [4219] STATEMENT:  create index bid_idx on pgbench_accounts(bid);
2018-06-07 22:48:02.366 IST [4219] LOG:  duration: 6421.705 ms  statement: create index bid_idx on pgbench_accounts(bid);

A mensagem acima significa que a consulta CREATE INDEX estava executando a classificação de disco e gerou um arquivo de tamanho 200425472 bytes que é 191+ MB. Isso significa precisamente que o parâmetro work_mem deve ser configurado para 191+ MB ou mais para que essa consulta específica execute a classificação de memória.

Bem, para as consultas do aplicativo, o parâmetro work_mem só pode ser configurado no nível do usuário. Antes de fazer isso, tome cuidado com o número de conexões que o usuário está fazendo com o banco de dados e o número de consultas de classificação que estão sendo executadas por esse usuário. Porque o PostgreSQL tenta alocar work_mem para cada processo (realizando ordenação) em cada conexão, o que poderia potencialmente esgotar a memória no servidor de banco de dados.

Layout do sistema de arquivos do banco de dados


Projetar um layout de sistema de arquivos de banco de dados eficiente e que conduza ao desempenho é importante do ponto de vista do desempenho e da escalabilidade. É importante ressaltar que isso não depende do tamanho do banco de dados. Em geral, a percepção é que bancos de dados de grande porte precisarão de arquitetura de disco de alto desempenho, o que NÃO é verdade. Mesmo que o tamanho do banco de dados seja de 50 GB, você pode precisar de uma boa arquitetura de disco. E isso pode não ser possível sem incorrer em custos extras.

Aqui estão algumas dicas para o mesmo:
  • Certifique-se de que o banco de dados tenha vários espaços de tabela, com tabelas e índices agrupados com base nas taxas de transação.
  • O tablespace deve ser colocado em vários sistemas de arquivos de disco para E/S balanceada. Isso também garantirá que várias CPUs entrem em ação para realizar transações em vários discos.
  • Considere colocar o diretório pg_xlog ou pg_wal em um disco separado em um banco de dados de alta transação.
  • Certifique-se de que os parâmetros *_cost sejam configurados com base na infraestrutura
  • Use iostat, mpstat e outras ferramentas de monitoramento de E/S para entender as estatísticas de E/S em todos os discos e arquitetar/gerenciar os objetos de banco de dados de acordo.

PostgreSQL na nuvem


A infraestrutura é fundamental para um bom desempenho do banco de dados. As estratégias de engenharia de desempenho diferem com base na infraestrutura e no ambiente. Cuidados especiais devem ser tomados para bancos de dados PostgreSQL hospedados na nuvem. O benchmarking de desempenho para bancos de dados hospedados em servidores barebone físicos em um data center local pode ser totalmente diferente dos bancos de dados hospedados na nuvem pública.

Em geral, as instâncias de nuvem podem ser um pouco mais lentas e os benchmarks diferem por uma margem considerável, especialmente em termos de E/S. Sempre execute verificações de latência de E/S antes de escolher/criar uma instância de nuvem. Para minha surpresa, aprendi que o desempenho das instâncias de nuvem também pode variar dependendo das regiões, mesmo que sejam do mesmo provedor de nuvem. Para explicar melhor, uma instância de nuvem com as mesmas especificações criadas em duas regiões diferentes pode fornecer resultados de desempenho diferentes.

Carregamento de dados em massa


As operações offline de carregamento de dados em massa são bastante comuns no mundo do banco de dados. Eles podem gerar uma carga de E/S significativa, o que, por sua vez, diminui o desempenho da carga de dados. Enfrentei esses desafios em minha experiência como DBA. Muitas vezes, o carregamento de dados fica terrivelmente lento e precisa ser ajustado. Aqui estão algumas dicas. Lembre-se de que eles se aplicam apenas a operações de carregamento de dados offline e não podem ser considerados para carregamento de dados no banco de dados de produção ao vivo.
  • Como a maioria das operações de carregamento de dados é realizada fora do horário comercial, verifique se os seguintes parâmetros estão configurados durante o carregamento de dados -
    • Configure valores relacionados ao ponto de verificação grandes o suficiente para que os pontos de verificação não causem problemas de desempenho.
    • Desativar full_page_write
    • Desativar o arquivamento do wal
    • Configure o parâmetro synchronous_commit como "off"
    • Remova restrições e índices para as tabelas sujeitas ao carregamento de dados (restrições e índices podem ser recriados após o carregamento de dados com um valor work_mem maior)
    • Se você estiver fazendo o carregamento de dados de um arquivo CSV, um Maintenance_work_mem maior pode gerar bons resultados.
    • Embora haja um benefício significativo de desempenho, NÃO desative o parâmetro fsync, pois isso pode causar corrupção de dados.

DICAS para análise de desempenho da nuvem

  • Realize testes completos de latência de E/S usando o pgbench. Na minha experiência, tive resultados de desempenho bastante comuns ao fazer verificações de latência de disco como parte da avaliação do TPS. Houve problemas com o desempenho do cache em algumas instâncias de nuvem pública. Isso ajudará a escolher as especificações apropriadas para a instância de nuvem escolhida para os bancos de dados.
  • As instâncias de nuvem podem ter um desempenho diferente de região para região. Uma instância de nuvem com determinadas especificações em uma região pode fornecer resultados de desempenho diferentes em comparação com uma instância de nuvem com as mesmas especificações em outra região. Meus testes pgbench executados em várias instâncias de nuvem (todas as mesmas especificações com o mesmo fornecedor de nuvem) em diferentes regiões me deram resultados diferentes em algumas delas. Isso é importante especialmente quando você está migrando para a nuvem.
  • O desempenho da consulta na nuvem pode precisar de uma abordagem de ajuste diferente. Os DBAs precisarão usar parâmetros *_cost para garantir a geração de planos de execução de consulta saudáveis.

Ferramentas para monitorar o desempenho do PostgreSQL


Existem várias ferramentas para monitorar o desempenho do PostgreSQL. Deixe-me destacar alguns deles.
  • pg_top é uma GRANDE ferramenta para monitorar dinamicamente o banco de dados PostgreSQL. Eu recomendo esta ferramenta para DBAs por vários motivos. Esta ferramenta tem inúmeras vantagens, deixe-me listá-las:
    • pg_top tool uses textual interface and is similar to Unix “top” utility.
    • Will clearly list out the processes and the hardware resources utilized. What excites me with this tool is that it will clearly tell you if a particular process is currently on DISK or CPU - in my view that’s excellent. DBAs can clearly pick the process running for longer time on the disk.
    • You can check the EXPLAIN PLAN of the top SQLs dynamically or instantly
    • You can also find out what Tables or Indexes are being scanned instantly
  • Nagios is a popular monitoring tool for PostgreSQL which has both open-source and commercial versions. Open source version should suffice for monitoring. Custom Perl scripts can be built and plugged into Nagios module.
  • Pgbadger is a popular tool which can be used to analyze PostgreSQL log files and generate performance reports. This report can be used to analyze the performance of checkpoints, disk sorting.
  • Zabbix is another popular tool used for PostgreSQL monitoring.

ClusterControl is an up-and-coming management platform for PostgreSQL. Apart from monitoring, it also has functionality to deploy replication setups with load balancers, automatic failover, backup management, among others.