AskOverflow.Dev

AskOverflow.Dev Logo AskOverflow.Dev Logo

AskOverflow.Dev Navigation

  • Início
  • system&network
  • Ubuntu
  • Unix
  • DBA
  • Computer
  • Coding
  • LangChain

Mobile menu

Close
  • Início
  • system&network
    • Recentes
    • Highest score
    • tags
  • Ubuntu
    • Recentes
    • Highest score
    • tags
  • Unix
    • Recentes
    • tags
  • DBA
    • Recentes
    • tags
  • Computer
    • Recentes
    • tags
  • Coding
    • Recentes
    • tags
Início / dba / Perguntas / 345840
Accepted
Leon
Leon
Asked: 2025-03-23 18:27:01 +0800 CST2025-03-23 18:27:01 +0800 CST 2025-03-23 18:27:01 +0800 CST

Por que todos os trabalhadores do Postgresql estão esperando por um único processo?

  • 772

Estamos usando o PostgreSQL-13 como nosso servidor principal e encontramos um gargalo de desempenho.

O hardware inclui 2 CPUs (AMD EPYC9754 com 128 núcleos e 256 threads cada), 128 GB de memória, hardware RAID0 inclui 2 * 4T SSD (Samsung990Pro).

Acho que o servidor PG não consegue usar todo o potencial do hardware.

Antes de fazer esta pergunta aqui, eu fiz as seguintes coisas:

  1. Verifique minha consulta SQL (usando exatamente a chave primária, sem varredura de sequência);
  2. Confirmar se meu programa roda corretamente (embora eu tenha escrito a mesma lógica em Python e C++, ambos rodam lentamente);
  3. Configurar meu servidor PG para usar o HugePage (configurei 80 GB de memória HugePage no total e permiti que o servidor PG use 64 GB shared_buffers);
  4. Aumentar os limites de memória de cada trabalhador PG( work_mem, temp_buffers,...);
  5. Aumentar o número de trabalhadores paralelos( max_worker_processes, max_parallel_workers_per_gather, max_parallel_workers,...);
  6. Ligar force_parallel_mode;
  7. Diminua o custo de io e o custo da CPU cfg( random_page_cost=1.01, cpu_tuple_cost=0.0025, cpu_index_tuple_cost=0.001,...);
  8. Maximizado default_statistics_targetpara 1000;
  9. Desabilitar replicações;
  10. 32 ou 64 processos de inicialização se conectam paralelamente ao servidor e consultam diferentes linhas de uma mesma tabela com diferentes chaves primárias.
  11. Todas as consultas são somente leitura e NÃO há operações de inserção/atualização/DDL durante os testes;

O que estou esperando:

  1. O servidor PG usa pelo menos 50% dos recursos de CPU/memória;
  2. Não há nenhum processo único bloqueando outras consultas;
  3. O rendimento total basicamente aumenta linearmente conforme a quantidade de recursos que aloquei ao servidor PG (talvez eu seja ingênuo?);

Meus testes:

  1. A definição da tabela:

    CREATE TABLE IF NOT EXISTS ob_lots(
        t_stamp INT8 NOT NULL,
        trd_sec INT4 NOT NULL,
        o_level INT2 NOT NULL,
        i_olots INT4 NOT NULL,
        f_olots FLOAT4 NULL,
    CONSTRAINT prk_ob_lots PRIMARY KEY( t_stamp, o_level ) );
    
  2. A pergunta:

    SELECT f_olots, t_stamp, trd_sec FROM ob_lots
    WHERE t_stamp BETWEEN $1 AND $2
    ORDER BY t_stamp DESC, o_level DESC
    LIMIT 4096;
    
  3. Programa de teste: Inicie muitas instâncias do meu programa que consultam aleatoriamente linhas da tabela acima paralelamente com o SQL de consulta acima. Quando o número de clientes estava aumentando de 2 para 4, ou de 4 para 8, ou de 8 para 16, observamos que o rendimento total quase dobrou todas as vezes. Mas de 16,32 ou mais, o rendimento total nunca mudou.

  4. Explicação SQL:

    Gather  (cost=1000.28..1002.41 rows=1 width=18) (actual time=6.840..9.232 rows=0 loops=1)
    Workers Planned: 1
    Workers Launched: 1
    Single Copy: true
    Buffers: shared hit=8
    ->  Limit  (cost=0.28..2.31 rows=1 width=18) (actual time=0.033..0.033 rows=0 loops=1)
            Buffers: shared hit=8
            ->  Index Scan Backward using prk_ob_lots_sc5555 on ob_lots_sc5555  (cost=0.28..2.31 rows=1 width=18) (actual time=0.031..0.031 rows=0 loops=1)
                Index Cond: ((t_stamp >= 123) AND (t_stamp <= 456))
                Buffers: shared hit=8
    Planning:
    Buffers: shared hit=109
    Planning Time: 0.759 ms
    Execution Time: 9.274 ms
    

As seguintes coisas me parecem estranhas:

  1. Há um processo PG que usa quase 100% de um único núcleo de CPU, e os outros usam muito menos;
  2. NÃO há io, NENHUMA troca durante o teste, e muitos recursos de memória/CPU/io estão livres/ociosos. Algo parece que todos os outros trabalhadores estão esperando pelo processo PG mestre (imagino que um use 100% da CPU), e resulta em um gargalo;
  3. O banco de dados de teste usou cerca de 4 GB de espaço em disco, pequeno o suficiente para ser mantido inteiramente na memória pelo PG. De fato, como observamos, não há nenhuma operação de io;

O que está fazendo? Por que todos os trabalhadores estão esperando por um único processo?

Esta é a parte principal da minha configuração PG (eu apenas listo as linhas que alterei):

max_connections = 2048

buffers compartilhados = 64 GB

huge_pages = ligado

temp_buffers = 256 MB

max_prepared_transactions = 256

work_mem = 256 MB

manutenção_trabalho_mem = 16 GB

memória_de_trabalho_de_vácuo_automático = -1

tipo_de_memória_compartilhada_dinâmica = posix

simultaneidade_io_efetiva = 1000

manutenção_io_concorrência = 1000

max_worker_processes = 256

max_parallel_maintenance_workers = 256

max_parallel_workers_per_gather = 256

parallel_leader_participation = ligado

max_parallel_workers = 256

fsync = desligado

synchronous_commit = desligado

full_page_writes = desativado

wal_compression = ativado

wal_buffers = -1

atraso_do_escritor_wal = 10000ms

wal_writer_flush_after = 1 GB

atraso_de_commit = 100000

commit_siblings = 128

tempo_limite_do_ponto_de_verificação = 1d

max_wal_size = 128 GB

tamanho_min_wal = 32 GB

meta_de_conclusão_do_ponto_de_verificação = 1.0

checkpoint_flush_after = 0

aviso_do_ponto_de_verificação = 0

max_wal_senders = 0

custo_da_página_seq = 1,0

custo_da_página_aleatória = 1,01

custo_tupla_da_cpu = 0,0025

custo_da_tupla_do_índice_da_cpu = 0,001

custo_operador_cpu = 0,00125

tamanho_do_cache_efetivo = 64 GB

meta_estatística_padrão = 1000

force_parallel_mode = ativado

autovacuum = ligado

E as saídas de tope iotop:

topo - 16:38:16 acima 4:09, 2 usuários, média de carga: 14,16, 9,14, 3,97

Número: 1581 no total, 2 em execução, 1573 dormindo, 0 parado, 6 zumbis

%Cpu(s): 3,5 us, 4,3 sy, 0,0 ni, 92,1 id, 0,0 wa, 0,0 hi, 0,1 si, 0,0 st

GiB Mem: 125,6 total, 34,6 grátis, 82,9 usado, 9,1 buff/cache

GiB Swap: 1,0 total, 1,0 grátis, 0,0 usado. 42,6 disponível Mem

进程号 USER PR NI VIRT RES SHR SWAP %CPU %MEM TIME+ COMMAND

31159 leon 20 0 4654,2m 105,1m 12,5m 0,0m S 152,7 0,1 7:09,93 carga

3186 postgres 0 -20 66,7g 18,6m 16,2m 0,0m R 99,5 0,0 5:03.16 postgres #é o mestre?

3192 postgres 0 -20 80,4m 6,8m 3,6m 0,0m S 8,2 0,0 0:24,97 postgres

32218 postgres 0 -20 66,7g 13,5m 9,9m 0,0m S 5,8 0,0 0:12,90 postgres

31217 postgres 0 -20 66,7g 13,4m 9,9m 0,0m S 5,3 0,0 0:12,74 postgres

31234 postgres 0 -20 66,7g 13,5m 9,9m 0,0m S 5,3 0,0 0:12,74 postgres

(muitos muitos processos postgres...)

Total de LEITURA DE DISCO: 0,00 B/s | Total de GRAVAÇÃO DE DISCO: 0,00 B/s

LEITURA DE DISCO atual: 0,00 B/s | GRAVAÇÃO DE DISCO atual: 0,00 B/s

TID  PRIO  USER     DISK READ DISK WRITE>    COMMAND

  1 be/4 root        0.00 B/s    0.00 B/s init

  2 be/4 root        0.00 B/s    0.00 B/s [kthreadd]

  3 be/0 root        0.00 B/s    0.00 B/s [rcu_gp]

  4 be/0 root        0.00 B/s    0.00 B/s [rcu_par_gp]

  5 be/0 root        0.00 B/s    0.00 B/s [slub_flushwq]
postgresql
  • 1 1 respostas
  • 82 Views

1 respostas

  • Voted
  1. Best Answer
    Laurenz Albe
    2025-03-24T20:27:26+08:002025-03-24T20:27:26+08:00

    Acho que você está sofrendo de um equívoco. Uma única consulta como essa nunca manterá uma máquina forte ocupada. Um núcleo de CPU está processando e os outros apenas aguardam. Distribuir a carga de trabalho em vários núcleos tornaria o processamento mais lento devido à sobrecarga do paralelismo.

    Você pode ver isso no seu plano de execução:

    • Todo o trabalho real é feito na varredura de índice reverso, que leva 0,03 milissegundos.

    • A consulta leva apenas 9 milissegundos porque você ativou force_parallel_mode(o que você nunca deve fazer — esse parâmetro é interessante apenas para desenvolvimento PostgreSQL e testes de regressão). Iniciar os processos adicionais, criar segmentos de memória compartilhada para trocar dados e outras sobrecargas consumiam todo esse tempo.

    Se você quiser processamento paralelo com instruções curtas no PostgreSQL, você tem que abrir várias sessões de banco de dados e executar instruções em cada uma delas. Efetivamente, você tem que paralelizar em sua aplicação.

    Para carregamento em massa para PostgreSQL, considere usar COPYem vez de INSERT. Se precisar usar INSERT, use instruções preparadas.

    A maioria das alterações de parâmetros são inúteis ou prejudiciais:

    • max_connections = 2048

      São muitos. Não exceda seu número de núcleos. Não sobrecarregue sua máquina.

    • buffers compartilhados = 64 GB

      Isso não ajudará no carregamento de dados.

    • huge_pages = ligado

      Essa está boa.

    • temp_buffers = 256 MB

      Inútil, a menos que você esteja usando tabelas temporárias.

    • max_prepared_transactions = 256

      Essa é uma configuração maligna e pode derrubar seu banco de dados. Não habilite transações preparadas, a menos que seja absolutamente necessário.

    • work_mem = 256 MB

      Ok, mas não faz sentido com pequenas declarações.

    • manutenção_trabalho_mem = 16 GB

      Tudo bem se você tiver RAM suficiente.

    • simultaneidade_io_efetiva = 1000

      Provavelmente muito alto.

    • manutenção_io_concorrência = 1000

      Provavelmente muito alto.

    • max_worker_processes = 256

      Não faz sentido se suas declarações forem pequenas.

    • max_parallel_maintenance_workers = 256

      Alto demais.

    • max_parallel_workers_per_gather = 256

      Alto demais.

    • max_parallel_workers = 256

      Provavelmente muito alto.

    • fsync = desligado

      Isso causará corrupção de dados. Não faça isso.

    • synchronous_commit = desligado

      Isso é aceitável, mas só é necessário se você tiver transações pequenas, o que é um antipadrão para carregamento em massa.

    • full_page_writes = desativado

      Isso causará corrupção de dados. Não faça isso.

    • wal_compression = ativado

      Isso é bom, mas só é útil se a quantidade de WAL gravado for um problema maior do que a utilização da CPU.

    • atraso_do_escritor_wal = 10000ms

      Sem sentido.

    • wal_writer_flush_after = 1 GB

      Não fará diferença.

    • atraso_de_commit = 100000

      Isso tornará suas transações muito lentas. Não faça isso.

    • commit_siblings = 128

      Isso é completamente ridículo.

    • tempo_limite_do_ponto_de_verificação = 1d

      Aumentar esse parâmetro pode até ser uma boa ideia, mas um dia é demais.

    • max_wal_size = 128 GB

      Essa é realmente uma configuração útil.

    • tamanho_min_wal = 32 GB

      Sem sentido.

    • meta_de_conclusão_do_ponto_de_verificação = 1.0

      Provavelmente inútil, pode ser prejudicial se atrasar o próximo ponto de verificação.

    • checkpoint_flush_after = 0

      Isso prejudicará o desempenho. Não faça isso.

    • aviso_do_ponto_de_verificação = 0

      Sem sentido.

    • max_wal_senders = 0

      Sem sentido.

    • custo_da_página_aleatória = 1,01

      Bom se você tiver SSDs ou similares.

    • custo_tupla_da_cpu = 0,0025

      Não mexa com isso.

    • custo_da_tupla_do_índice_da_cpu = 0,001

      Não mexa com isso.

    • custo_operador_cpu = 0,00125

      Não mexa com isso.

    • tamanho_do_cache_efetivo = 64 GB

      Bom!

    • meta_estatística_padrão = 1000

      Isso prejudicará o desempenho.

    • force_parallel_mode = ativado

      Isso prejudicará o desempenho.

    • 2

relate perguntas

  • Posso ativar o PITR depois que o banco de dados foi usado

  • Práticas recomendadas para executar a replicação atrasada do deslocamento de tempo

  • Os procedimentos armazenados impedem a injeção de SQL?

  • Sequências Biológicas do UniProt no PostgreSQL

  • Qual é a diferença entre a replicação do PostgreSQL 9.0 e o Slony-I?

Sidebar

Stats

  • Perguntas 205573
  • respostas 270741
  • best respostas 135370
  • utilizador 68524
  • Highest score
  • respostas
  • Marko Smith

    conectar ao servidor PostgreSQL: FATAL: nenhuma entrada pg_hba.conf para o host

    • 12 respostas
  • Marko Smith

    Como fazer a saída do sqlplus aparecer em uma linha?

    • 3 respostas
  • Marko Smith

    Selecione qual tem data máxima ou data mais recente

    • 3 respostas
  • Marko Smith

    Como faço para listar todos os esquemas no PostgreSQL?

    • 4 respostas
  • Marko Smith

    Listar todas as colunas de uma tabela especificada

    • 5 respostas
  • Marko Smith

    Como usar o sqlplus para se conectar a um banco de dados Oracle localizado em outro host sem modificar meu próprio tnsnames.ora

    • 4 respostas
  • Marko Smith

    Como você mysqldump tabela (s) específica (s)?

    • 4 respostas
  • Marko Smith

    Listar os privilégios do banco de dados usando o psql

    • 10 respostas
  • Marko Smith

    Como inserir valores em uma tabela de uma consulta de seleção no PostgreSQL?

    • 4 respostas
  • Marko Smith

    Como faço para listar todos os bancos de dados e tabelas usando o psql?

    • 7 respostas
  • Martin Hope
    Jin conectar ao servidor PostgreSQL: FATAL: nenhuma entrada pg_hba.conf para o host 2014-12-02 02:54:58 +0800 CST
  • Martin Hope
    Stéphane Como faço para listar todos os esquemas no PostgreSQL? 2013-04-16 11:19:16 +0800 CST
  • Martin Hope
    Mike Walsh Por que o log de transações continua crescendo ou fica sem espaço? 2012-12-05 18:11:22 +0800 CST
  • Martin Hope
    Stephane Rolland Listar todas as colunas de uma tabela especificada 2012-08-14 04:44:44 +0800 CST
  • Martin Hope
    haxney O MySQL pode realizar consultas razoavelmente em bilhões de linhas? 2012-07-03 11:36:13 +0800 CST
  • Martin Hope
    qazwsx Como posso monitorar o andamento de uma importação de um arquivo .sql grande? 2012-05-03 08:54:41 +0800 CST
  • Martin Hope
    markdorison Como você mysqldump tabela (s) específica (s)? 2011-12-17 12:39:37 +0800 CST
  • Martin Hope
    Jonas Como posso cronometrar consultas SQL usando psql? 2011-06-04 02:22:54 +0800 CST
  • Martin Hope
    Jonas Como inserir valores em uma tabela de uma consulta de seleção no PostgreSQL? 2011-05-28 00:33:05 +0800 CST
  • Martin Hope
    Jonas Como faço para listar todos os bancos de dados e tabelas usando o psql? 2011-02-18 00:45:49 +0800 CST

Hot tag

sql-server mysql postgresql sql-server-2014 sql-server-2016 oracle sql-server-2008 database-design query-performance sql-server-2017

Explore

  • Início
  • Perguntas
    • Recentes
    • Highest score
  • tag
  • help

Footer

AskOverflow.Dev

About Us

  • About Us
  • Contact Us

Legal Stuff

  • Privacy Policy

Language

  • Pt
  • Server
  • Unix

© 2023 AskOverflow.DEV All Rights Reserve