O Postmaster usa gravações excessivas de CPU e disco

9

usando o PostgreSQL 9.1.2

Estou vendo uso excessivo da CPU e grandes quantidades de gravações no disco a partir de tarefas do postmaster. Isso acontece mesmo enquanto meu aplicativo não faz quase nada (10s de inserções por MINUTE). No entanto, há um número razoável de conexões abertas.

Eu tenho tentado determinar o que no meu aplicativo está causando isso. Sou bem novato no postgresql e ainda não cheguei a lugar algum. Ativei algumas opções de log no meu arquivo de configuração e observei as conexões na tabela pg_stat_activity, mas todas estão ociosas. No entanto, cada conexão consome ~ 50% da CPU e grava ~ 15M / s no disco (não está lendo nada).

Basicamente, estou usando o postgresql.conf com muito poucos ajustes. Agradeço qualquer conselho ou dicas sobre o que posso fazer para rastrear isso.

Aqui está uma amostra do que top / iotop está me mostrando:

Cpu(s): 18.9%us, 14.4%sy,  0.0%ni, 53.4%id, 11.8%wa,  0.0%hi,  1.5%si,  0.0%st
Mem:  32865916k total,  7263720k used, 25602196k free,   575608k buffers
Swap: 16777208k total,        0k used, 16777208k free,  4464212k cached

  PID USER      PR  NI  VIRT  RES  SHR S %CPU %MEM    TIME+  COMMAND                                                                                                                          
17057 postgres  20   0  236m  33m  13m R 45.0  0.1  73:48.78 postmaster                                                                                                                       
17188 postgres  20   0  219m  15m  11m R 42.3  0.0  61:45.57 postmaster                                                                                                                       
17963 postgres  20   0  219m  16m  11m R 42.3  0.1  27:15.01 postmaster                                                                                                                       
17084 postgres  20   0  219m  15m  11m S 41.7  0.0  63:13.64 postmaster                                                                                                                       
17964 postgres  20   0  219m  17m  12m R 41.7  0.1  27:23.28 postmaster                                                                                                                       
18688 postgres  20   0  219m  15m  11m R 41.3  0.0  63:46.81 postmaster                                                                                                                       
17088 postgres  20   0  226m  24m  12m R 41.0  0.1  64:39.63 postmaster                                                                                                                       
24767 postgres  20   0  219m  17m  12m R 41.0  0.1  24:39.24 postmaster                                                                                                                       
18660 postgres  20   0  219m  14m 9.9m S 40.7  0.0  60:51.52 postmaster                                                                                                                       
18664 postgres  20   0  218m  15m  11m S 40.7  0.0  61:39.61 postmaster                                                                                                                       
17962 postgres  20   0  222m  19m  11m S 40.3  0.1  11:48.79 postmaster                                                                                                                       
18671 postgres  20   0  219m  14m   9m S 39.4  0.0  60:53.21 postmaster                                                                                                                       
26168 postgres  20   0  219m  15m  10m S 38.4  0.0  59:04.55 postmaster  


Total DISK READ: 0.00 B/s | Total DISK WRITE: 195.97 M/s
  TID  PRIO  USER     DISK READ  DISK WRITE  SWAPIN     IO>    COMMAND                                                                                                                        
17962 be/4 postgres    0.00 B/s   14.83 M/s  0.00 %  0.25 % postgres: aggw aggw [local] idle
17084 be/4 postgres    0.00 B/s   15.53 M/s  0.00 %  0.24 % postgres: aggw aggw [local] idle
17963 be/4 postgres    0.00 B/s   15.00 M/s  0.00 %  0.24 % postgres: aggw aggw [local] idle
17188 be/4 postgres    0.00 B/s   14.80 M/s  0.00 %  0.24 % postgres: aggw aggw [local] idle
17964 be/4 postgres    0.00 B/s   15.50 M/s  0.00 %  0.24 % postgres: aggw aggw [local] idle
18664 be/4 postgres    0.00 B/s   15.13 M/s  0.00 %  0.23 % postgres: aggw aggw [local] idle
17088 be/4 postgres    0.00 B/s   14.71 M/s  0.00 %  0.13 % postgres: aggw aggw [local] idle
18688 be/4 postgres    0.00 B/s   14.72 M/s  0.00 %  0.00 % postgres: aggw aggw [local] idle
24767 be/4 postgres    0.00 B/s   14.93 M/s  0.00 %  0.00 % postgres: aggw aggw [local] idle
18671 be/4 postgres    0.00 B/s   16.14 M/s  0.00 %  0.00 % postgres: aggw aggw [local] idle
17057 be/4 postgres    0.00 B/s   13.58 M/s  0.00 %  0.00 % postgres: aggw aggw [local] idle
26168 be/4 postgres    0.00 B/s   15.50 M/s  0.00 %  0.00 % postgres: aggw aggw [local] idle
18660 be/4 postgres    0.00 B/s   15.85 M/s  0.00 %  0.00 % postgres: aggw aggw [local] idle

Atualização : Muitas das gravações de arquivos parecem estar em alguns arquivos temporários (?) No diretório $ PG_DATA / base /. Meu entendimento da estrutura do arquivo aqui é que cada tabela é basicamente armazenada como um arquivo cujo nome é o OID da tabela. No entanto, existem vários arquivos nomeados tnn_nnnnnnne são esses arquivos que parecem ser gravados (talvez sobrescritos) constantemente. Para que são esses arquivos? Existem ~ 4700 dos arquivos e todos têm 8K de tamanho:

-rw-------. 1 postgres postgres     8192 Jul  3 23:08 t12_1430975
-rw-------. 1 postgres postgres     8192 Jul  3 23:08 t16_1432736
-rw-------. 1 postgres postgres     8192 Jul  3 23:08 t28_1439066
-rw-------. 1 postgres postgres     8192 Jul  3 23:08 t24_1436243
-rw-------. 1 postgres postgres     8192 Jul  3 23:08 t24_1436210
-rw-------. 1 postgres postgres     8192 Jul  3 23:08 t19_1393372
-rw-------. 1 postgres postgres     8192 Jul  3 23:08 t28_1439051
-rw-------. 1 postgres postgres     8192 Jul  3 23:08 t8_1430334

Atualização : A execução do rastreio nos processos do postmaster mostra basicamente muitas coisas de E / S de arquivos:

open("base/16388/t24_1435947_fsm", O_RDWR) = -1 ENOENT (No such file or directory)
open("base/16388/t24_1435947_vm", O_RDWR) = -1 ENOENT (No such file or directory)
open("base/16388/t24_1435947", O_RDWR)  = 9
lseek(9, 0, SEEK_END)                   = 8192
ftruncate(9, 0)                         = 0
lseek(9, 0, SEEK_END)                   = 0
open("base/16388/t24_1435941", O_RDWR)  = 18
lseek(18, 0, SEEK_END)                  = 0
write(9, "\0\0\0\0\0\0\0\0\1\0\0\0000\0\360\37\360\37\4 \0\0\0\0b1\5\0\2\0\0\0"..., 8192) = 8192
lseek(18, 0, SEEK_END)                  = 0
close(9)                                = 0
open("base/16388/t24_1435947", O_RDWR)  = 9
lseek(9, 0, SEEK_END)                   = 8192
close(18)                               = 0
close(9)                                = 0
open("base/16388/t24_1435944_fsm", O_RDWR) = -1 ENOENT (No such file or directory)
open("base/16388/t24_1435944_vm", O_RDWR) = -1 ENOENT (No such file or directory)
open("base/16388/t24_1435944", O_RDWR)  = 9
lseek(9, 0, SEEK_END)                   = 0
close(9)                                = 0

Atualização : Portanto, esse problema parece ter tudo a ver com tabelas temporárias. Alteramos nossa configuração para que as tabelas temporárias sejam tabelas 'regulares', e toda a atividade do disco tenha desaparecido, e o desempenho esteja de volta ao que eu esperava. Agora, essa alteração foi apenas um teste rápido e sujo: se realmente vamos mudar para usar tabelas regulares, temos problemas com simultaneidade e limpeza. As mesas temporárias são realmente tão más ou estamos abusando delas?

Atualização : Um pouco mais de experiência. Estou usando um middleware de replicação baseado em instruções desenvolvido internamente . É bastante maduro e tem sido usado em vários projetos ao longo de vários anos, mas usando o MySQL. Trabalhamos apenas com o PostgreSQL nos últimos dois anos. Basicamente, estávamos usando as tabelas temporárias como parte do mecanismo de replicação. Sempre que uma nova conexão é estabelecida, criamos uma tabela temporária para cada tabela no banco de dados. Com 10 a 20 conexões (de longa duração) e ~ 50 tabelas, isso pode resultar em muitas tabelas temporárias. Todas as tabelas temporárias foram criadas com:

CREATE TEMPORARY TABLE... ON COMMIT DELETE ROWS;

A semântica das tabelas temporárias se encaixa muito bem com o nosso esquema de replicação e simplificou muito do código que tínhamos que usar no MySQL, mas parece que a implementação não foi boa também. Com base nas pesquisas que fiz, não acho que tabelas temporárias foram realmente destinadas à função para a qual as usamos.

Eu não sou o especialista interno (nem de perto) sobre esse assunto, apenas um usuário, por isso minha explicação pode não ser 100% precisa, mas acho que é bem próxima.

Wolfcastle
fonte
3
Seu entendimento está um pouco desatualizado. Se você olhar para a documentação oficial , verá que "... para relações temporárias, o nome do arquivo tem o formato tBBB_FFF, onde BBB é o ID de back-end do back-end que criou o arquivo , e FFF é o número do código do arquivo. ... "
Milen A. Radev
Uau, esse é um subsistema de E / S de disco com bom desempenho. O que strace diz sobre o que os trabalhadores estão realmente fazendo?
Womble
@ MilenA.Radev, então parece que eu posso estar fazendo algo estranho / excessivo com tabelas temporárias. Isto é interessante. Eu tenho muitos gatilhos no lugar que usam tabelas temporárias. Vou olhar mais de perto para eles.
Wolfcastle
@ womble, atualizei a questão com a saída do strace.
Wolfcastle
Você está realmente enfrentando um problema de desempenho?
precisa saber é o seguinte

Respostas:

1

Sua configuração do PostgreSQL está muito diferente. Isso foi suspeito em sua postagem inicial,

 Cpu(s): 18.9%us, 14.4%sy,  0.0%ni, 53.4%id, 11.8%wa,  0.0%hi,  1.5%si,  0.0%st
 Mem:  32865916k total,  7263720k used, 25602196k free,   575608k buffers
 Swap: 16777208k total,        0k used, 16777208k free,  4464212k cached

Dos 32 GB no servidor, ~ 25 GB são gratuitos, exceto ~ 575 MB de buffer.

No seu arquivo postgresql.conf,

 shared_buffers = 32MB                   # min 128kB                               
 #temp_buffers = 8MB                     # min 800kB
 #max_prepared_transactions = 0          # zero disables the feature
 ...
 #work_mem = 1MB                         # min 64kB
 #maintenance_work_mem = 16MB            # min 1MB
 #max_stack_depth = 2MB   

Estou assumindo que este é um banco de dados dedicado. Nesse caso, altere-o para os seguintes parâmetros e recarregue / reinicie,

 shared_buffers = 16GB                   # min 128kB                               
 temp_buffers = 128MB                     # min 800kB
 #max_prepared_transactions = 0          # zero disables the feature
 ...
 work_mem = 8MB                         # min 64kB
 maintenance_work_mem = 64MB            # min 1MB
 max_stack_depth = 4MB   

Deixe-me saber como isso altera seu desempenho e pode ajustá-lo ainda mais, conforme necessário.

No que diz respeito às tabelas não registradas, se suas tabelas temporárias contiverem dados temporários efêmeros e, como você mencionou, são criados na sessão, é melhor usar tabelas não registradas.

Você pode truncar suas tabelas após a sessão, se isso for aceitável.

Mais informações aqui - http://michael.otacoo.com/postgresql-2/unlogged-table-performance-in-postgresql-9-1/

Não sei por que você precisa de tabelas temporárias para replicação. Você não pode usar a replicação de streaming do PostgreSQL?

Chida
fonte
0

Usar tabelas temporárias e ter conexões de longa data (provavelmente o pool de conexões está envolvido) pode ser um fardo se o servidor não estiver preparado para isso. Um parâmetro do PostgreSQL com o temp_buffersqual você pode tentar jogar é o que controla a RAM alocada para tabelas temporárias. Esses buffers temporários são alocados por conexão e o valor padrão (8 MB) provavelmente é muito baixo para o seu site.

Talvez você também precise alterar um pouco o comportamento do aplicativo cliente, dependendo de como você usa suas tabelas temporárias. Há uma pergunta semelhante com uma boa resposta no Stack Overflow .

Tonin
fonte
Vou ter que perguntar ao meu especialista interno se tentamos ajustar o valor de temp_buffers ou não (tentamos várias coisas diferentes). A pergunta que você aponta não se aplica, pois não estamos usando tabelas temporárias dessa maneira. Atualizei a pergunta com mais alguns detalhes.
Wolfcastle
Obrigado pela atualização da pergunta e pelo arquivo postgresql.conf, é isso que precisamos tentar melhorar nessa situação. Concordo com a resposta @Chida, que está alinhada com o que sugeri wrt temp_buffers. Você também pode nos dizer qual é o tamanho do banco de dados que você está tentando replicar? Quantas tabelas, tamanho médio por tabela e tamanho total do banco de dados?
Tonin
0

Você poderia postar seu arquivo postgresql.conf? Seu postgresql parece estar significativamente otimizado.

Você também pode postar:

  • Se você estiver usando tabelas não registradas para suas tabelas temporárias?

  • Quantos discos e em que configuração RAID?

Chida
fonte
Coloquei o arquivo postgresql.conf aqui . Eu acredito que você não pode criar uma tabela que seja temporária e desobstruída. Existem 6 1 TB discos de um RAID 1 + 0 (total de armazenamento de 3 TB)
Wolfcastle