Como determinar o ponto ideal entre o tamanho do pool e as conexões com o banco de dados no PostgreSQL


14

Estamos com problemas para manipular o tráfego durante o horário de pico para nosso servidor de banco de dados. Estamos tentando melhorar o hardware (veja esta pergunta sobre esse lado ), mas também queremos trabalhar na configuração de pool e no ajuste do servidor.

A aplicação em que estamos trabalhando é um jogo multiplayer baseado em turnos para smartphones, onde o back-end consiste em Rails com unicórnio e PostgreSQL 9.1 como banco de dados. Atualmente, temos 600.000 usuários registrados e, como o estado do jogo é armazenado no banco de dados, vários milhares de gravações são feitas a cada dois segundos. Analisamos os arquivos de log do PostgreSQL usando o PgBadger e, durante as horas críticas, recebemos muitas

FATAL: remaining connection slots are reserved for non-replication superuser connections

A solução ingênua para combater esse problema seria aumentar o max_connections (que atualmente é 100) no postgresql.conf . Eu li http://wiki.postgresql.org/wiki/Number_Of_Database_Connections que indica que isso pode não ser a coisa certa a se fazer. No artigo mencionado, refere-se a encontrar o ponto ideal entre max_connections e tamanho da piscina .

O que pode ser feito para encontrar esse ponto ideal? Existem boas ferramentas para medir o desempenho de E / S para diferentes valores de max_connections e tamanho do pool ?

Nossa configuração atual é de 4 servidores de jogos, cada um com 16 trabalhadores unicórnios e um tamanho de pool de 5.

Aqui estão as configurações do postgres não padrão que estamos usando:

version                      | PostgreSQL 9.1.5 on x86_64-unknown-linux-gnu,compiled by gcc (Ubuntu/Linaro 4.6.3-1ubuntu5) 4.6.3, 64-bit
checkpoint_completion_target | 0.9
checkpoint_segments          | 60
checkpoint_timeout           | 6min
client_encoding              | UTF8
effective_cache_size         | 2GB
lc_collate                   | en_US.UTF-8
lc_ctype                     | en_US.UTF-8
log_destination              | csvlog
log_directory                | pg_log
log_filename                 | postgresql-%Y-%m-%d_%H%M%S.log
log_line_prefix              | %t
log_min_duration_statement   | 200ms
log_rotation_age             | 1d
log_rotation_size            | 10MB
logging_collector            | on
max_connections              | 100
max_stack_depth              | 2MB
server_encoding              | UTF8
shared_buffers               | 1GB
ssl                          | on
TimeZone                     | localtime
wal_buffers                  | 16MB
work_mem                     | 8MB

Você é a pessoa que estava perguntando sobre isso na lista de discussão nas últimas semanas? Nesse caso, adicionarei links de volta a essa discussão. Além disso: qual é o hardware e a configuração do servidor de banco de dados ? wiki.postgresql.org/wiki/Slow_Query_Questions . Inclua configurações não padrão: wiki.postgresql.org/wiki/Server_Configuration . Você leu wiki.postgresql.org/wiki/Tuning_Your_PostgreSQL_Server ? Você trabalha em lote em transações maiores sempre que possível? Você usa uma camada de cache e, em caso afirmativo, o que? Você está usando synchronous_commit = offou a commit_delay?
Craig Ringer

Então você tem um total de 20 conexões com o servidor PostgreSQL? 5 por servidor de jogo? Com esses 5 truques de cada servidor de jogo sendo compartilhados entre 16 trabalhadores unicórnios?
Craig Ringer

Oh, você está registrando consultas lentas? Se sim, quais são seus pontos quentes? INSERTS simples ? Como é o seu esquema - ele é particionado? Qual é o explain analyzede algumas consultas de amostra? Qual a frequência dos seus postos de controle e quanto tempo eles demoram? (consulte as opções de log do ponto de verificação). E sério, qual é a sua versão do PostgreSQL ? (Update: Parece que você listar seu hardware aqui: dba.stackexchange.com/questions/28061/... )
Craig Ringer

De qualquer forma, para ajustar especificamente o tamanho do pool, as únicas respostas reais são configurar medidas robustas de carga e taxa de transferência do servidor de banco de dados e começar a ajustar para cima e para baixo até encontrar o ponto ideal.
Craig Ringer

@ CraigRinger Não, eu não sou essa pessoa. Mas obrigado pelos backlinks! Eu li o servidor Tuning Your PostgreSQL e segui algumas das dicas mencionadas. Agora incluí as configurações não padrão. Estamos agora olhando para make maiores transações e testessynchronous_commit = off
lorgartzor

Respostas:


14

A resposta curta aqui é "tentativa e erro guiados por métricas de monitoramento e desempenho".

Existem algumas regras gerais que devem ajudá-lo a encontrar a área vaga em que você deve começar, mas elas são muito gerais. As diretrizes gerais "número de CPUs e número de discos independentes" são frequentemente citadas, mas é apenas um ponto de partida incrivelmente grosseiro.

O que você realmente precisa fazer é obter métricas robustas de desempenho para o seu aplicativo. Comece a gravar estatísticas.

Não há muito em termos de ferramentas integradas para isso. Existem coisas como o check_postgresscript nagios , o registro do contador de desempenho do sistema Cacti, o coletor de estatísticas do PostgreSQL, etc ... mas não há muito que ajude tudo. Infelizmente, você terá que fazer isso sozinho. Para o lado do PostgreSQL, consulte o monitoramento no manual do PostgreSQL. Existem algumas opções de terceiros, como o Postgres Enterprise Monitor do EnterpriseDB .

Para as métricas em nível de aplicativo mencionadas aqui, você deseja gravá-las em estruturas de dados compartilhadas ou em um banco de dados externo não durável como o Redis e agregá-las à medida que você as grava ou antes de gravá-las no banco de dados PostgreSQL. Tentar registrar diretamente na página distorcerá suas medidas com a sobrecarga criada pelo registro das medidas e piorará o problema.

A opção mais simples é provavelmente um singleton em cada servidor de aplicativos que você usa para registrar estatísticas do aplicativo. Você provavelmente deseja manter uma atualização constante de mín, máx, n, total e média; Dessa forma, você não precisa armazenar cada ponto de estatística, apenas os agregados. Esse singleton pode gravar suas estatísticas agregadas na página a cada x minutos, uma taxa suficientemente baixa para que o impacto no desempenho seja mínimo.

Começar com:

  • Qual é a latência da solicitação? Em outras palavras, quanto tempo o aplicativo leva para obter uma solicitação do cliente até responder ao cliente. Registre isso agregado por um período de tempo, e não como registros individuais. Agrupe por tipo de solicitação; digamos, por página.

  • Qual é o atraso de acesso ao banco de dados para cada consulta ou tipo de consulta que o aplicativo executa? Quanto tempo leva para solicitar informações ao banco de dados / armazenar informações até que esteja pronto e possa passar para a próxima tarefa? Novamente, agregue essas estatísticas no aplicativo e grave apenas as informações agregadas no banco de dados.

  • Como é o seu rendimento? Em um determinado x minuto, quantas consultas de cada classe principal que seu aplicativo executa são atendidas pelo banco de dados?

  • Para o mesmo intervalo de tempo de x minutos, quantas solicitações de clientes existiam?

  • Amostrando a cada poucos segundos e agregando nas mesmas janelas de x minutos no banco de dados, quantas conexões de banco de dados havia? Quantos deles estavam ociosos? Quantos estavam ativos? Em inserções? Atualizações? Selecione% s? exclui? Quantas transações houve nesse período? Consulte a documentação do coletor de estatísticas

  • Mais uma vez, amostrando e agregando no mesmo intervalo de tempo, como eram as métricas de desempenho do sistema host? Quantas leem e quantas E / S de disco de gravação / segundo? Megabytes por segundo de disco lê e grava? Utilização da CPU? Carga média? Uso de RAM?

Agora você pode começar a aprender sobre o desempenho do seu aplicativo correlacionando os dados, criando gráficos, etc. Você começará a ver padrões, a encontrar gargalos.

Você pode aprender que o seu sistema está em cerviz-garrafa INSERTe UPDATEé em altas taxas de transação, apesar de bastante baixo / S de disco em megabytes por segundo. Isso sugere que você precisa melhorar o desempenho da liberação do disco com um controlador RAID de cache de write-back suportado por bateria ou alguns SSDs protegidos por energia de alta qualidade. Você também pode usar synchronous_commit = offse não houver problema em perder algumas transações na falha do servidor e / ou a commit_delay, para retirar parte da carga de sincronização.

Quando você faz um gráfico de suas transações por segundo com base no número de conexões simultâneas e corrige a taxa de solicitações variável que o aplicativo está vendo, poderá ter uma idéia melhor de onde está o ponto ideal da taxa de transferência.

Se você não possui armazenamento de liberação rápida (BBU RAID ou SSDs rápidos e duráveis), não desejará mais do que um número bastante pequeno de conexões de gravação ativa, talvez no máximo o dobro do número de discos que você possui, provavelmente menos dependendo da organização do RAID , desempenho do disco etc. Nesse caso, nem vale a pena tentativa e erro; basta atualizar seu subsistema de armazenamento para um com liberações rápidas de disco .

Procure pg_test_fsyncuma ferramenta que ajude a determinar se isso pode ser um problema para você. A maioria dos pacotes do PostgreSQL instala essa ferramenta como parte do contrib, portanto você não precisa compilá-la. Se você receber menos do que um par de milhares de ops / segundo em pg_test_fsyncque você urgentemente precisa atualizar o seu sistema de armazenamento. Meu laptop equipado com SSD recebe de 5000 a 7000. Minha estação de trabalho trabalhando com uma matriz RAID 10 de 4 discos de 7200 rpm SATA e write-through (sem cache de gravação) recebe cerca de 80 operações / segundo f_datasync, até 20 operações / segundo fsync(); é centenas de vezes mais lento . Compare: laptop com ssd vs estação de trabalho com gravação (sem gravação em cache) RAID 10. O SSD deste laptop é barato e eu não confio necessariamente nele para liberar seu cache de gravação em caso de perda de energia; Eu mantenho bons backups e não os utilizo para dados importantes. Os SSDs de boa qualidade têm o mesmo desempenho, se não melhor, e são duráveis ​​para gravação.

No caso de sua inscrição, recomendo fortemente que você analise:

  • Um bom subsistema de armazenamento com descargas rápidas. Não posso enfatizar isso o suficiente. SSDs de boa qualidade com proteção contra falhas de energia e / ou um controlador RAID com cache de write-back protegido por energia.
  • Usando UNLOGGEDtabelas para dados que você pode perder. Agregue-o periodicamente em tabelas registradas. Por exemplo, mantenha os jogos em andamento em tabelas não registradas e escreva as pontuações em tabelas duráveis ​​comuns.
  • Usando um commit_delay(menos útil com armazenamento de descarga rápida - dica)
  • Desativando synchronous_committransações que você pode perder (menos útil com armazenamento de descarga rápida - dica de dica)
  • Tabelas de particionamento, especialmente tabelas em que os dados "expiram" e são limpos. Em vez de excluir de uma tabela particionada, descarte uma partição.
  • Índices parciais
  • Reduzindo o número de índices que você cria. Todo índice tem um custo de gravação.
  • Trabalho em lote para transações maiores
  • Usando réplicas de espera ativa somente leitura para remover a carga de leitura do banco de dados principal
  • O uso de uma camada de armazenamento em cache, como memcached ou redis, para dados que mudam com menos frequência ou podem ficar obsoletos. Você pode usar LISTENe NOTIFYexecutar a invalidação de cache usando gatilhos nas tabelas do PostgreSQL.

Em caso de dúvida: http://www.postgresql.org/support/professional_support/

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.