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

Impulsionando o desempenho do PostgreSQL com HAProxy

O desempenho do banco de dados é uma preocupação muito importante ao manter seu cluster de banco de dados, especialmente à medida que ele cresce ao longo do tempo. Isso é especialmente verdadeiro se seu aplicativo começou com baixo tráfego e depois cresceu para cargas de trabalho de leitura e gravação moderadas ou pesadas.

O que deve ser lembrado é que não há uma configuração perfeita na qual você possa confiar por muito tempo, pois certas cargas de trabalho podem mudar com o tempo.

Com o ClusterControl, a criação ou implantação de um novo cluster de banco de dados PostgreSQL executa uma análise básica, como verificar os recursos de hardware, aplicar o ajuste automático e definir os valores para os parâmetros ajustáveis ​​selecionados. À medida que o PostgreSQL evolui, muitas ferramentas também foram desenvolvidas para suportar diferentes configurações, especialmente para balanceamento de carga.

Neste blog, veremos a importância do HAProxy e como ele pode ajudar a impulsionar o desempenho. É uma ferramenta antiga, mas um poderoso proxy e/ou balanceador de carga que suporta não apenas servidores de banco de dados, mas também protocolos específicos de aplicativos de rede. O HAProxy pode operar via camada quatro e camada sete, respectivamente, dependendo do tipo de configuração com base na configuração.

Ajuste de desempenho do PostgreSQL

Um dos principais fatores para impulsionar o desempenho do PostgreSQL começa com o ajuste de parâmetro básico de initdb para valores de parâmetro de tempo de execução. Isso deve ser capaz de lidar com a carga de trabalho desejada de acordo com seus requisitos específicos. Antes de começarmos a usar o recurso HAProxy para PostgreSQL, seu servidor de banco de dados precisa estar estável e ajustado para as variáveis ​​desejadas. Vamos dar uma lista de áreas para o PostgreSQL sobre quais são as coisas que podem afetar o desempenho do seu servidor de banco de dados.

Ajuste para gerenciamento de memória viável

O PostgreSQL é eficiente e pode ser executado com eficiência em apenas 256 MB de memória. A memória não é cara, mas a maioria dos conjuntos de dados tem menos de 4 Gib. Se você tiver pelo menos 4Gib, seu conjunto de dados ativo pode permanecer no cache de arquivo e/ou shared_buffer.

Ajustar seu PostgreSQL para gerenciamento de memória é uma das coisas mais primárias e básicas que você precisa configurar. Configurá-lo adequadamente pode impactar no aumento do desempenho do seu servidor de banco de dados. Embora isso dependa de que tipo de mesas você está jogando. Consultas inválidas e definições de tabela insatisfatórias também podem levar a um desempenho insatisfatório. Com índices adequados definidos para suas tabelas e com consultas referenciando índices, as chances podem chegar a 80% - 100% das consultas podem ser recuperadas da sua memória. Isso especialmente se o buffer de índice tiver o valor certo para carregar seu índice definido em suas tabelas. Vejamos os parâmetros que são comumente definidos para melhoria de desempenho.

  • shared_buffers - O PostgreSQL dimensiona seu espaço de memória principal com shared_buffers. O cache de trabalho de todas as tuplas quentes (e entradas de índice) no PostgreSQL. Este parâmetro define a quantidade de memória que o servidor de banco de dados usa para buffers de memória compartilhada. É um cache pré-alocado (buffers). Para sistemas baseados em Linux, é ideal definir o parâmetro do kernel kernel.shmmax que pode ser definido persistentemente através do arquivo de configuração do kernel /etc/sysctl.conf.
  • temp_buffers - Define o número máximo de buffers temporários usados ​​para cada sessão. Esses são buffers de sessão locais usados ​​apenas para acessar tabelas temporárias. Uma sessão atribuirá os buffers temporários conforme necessário até o limite fornecido por temp_buffers.
  • work_mem - A memória de trabalho disponível para operações de trabalho (classificações) antes da troca do PostgreSQL. Não defina globalmente (postgresql.conf). Use por transação, pois isso pode ser ruim por consulta, por conexão ou por classificação. O uso de EXPLAIN ANALYZE é recomendado para ver se você está transbordando ou não.
  • maintenance_work_mem - Especifica a quantidade de memória a ser usada para operações de manutenção (VACUUM, CREATE INDEX e ALTER TABLE … ADD FOREIGN KEY…)

Ajuste para gerenciamento de disco viável

Vários parâmetros de tempo de execução para definir aqui. Vamos listar quais são:

  • temp_file_limit - Especifica a quantidade máxima de espaço em disco que uma sessão pode usar para arquivos temporários, como arquivos temporários de classificação e hash, ou o arquivo de armazenamento para um cursor retido. Uma transação que tentar exceder esse limite será cancelada.
  • fsync - Se o fsync estiver habilitado, o PostgreSQL tentará garantir que as atualizações sejam fisicamente gravadas no disco. Isso garante que o cluster de banco de dados possa ser recuperado para um estado consistente após uma falha do sistema operacional ou do hardware. Embora a desativação do fsync geralmente melhore o desempenho, ela pode causar perda de dados em caso de falha de energia ou falha do sistema. Portanto, só é aconselhável desativar o fsync se você puder recriar facilmente todo o seu banco de dados a partir de dados externos
  • synchronous_commit - Usado para impor que a confirmação aguardará que o WAL seja gravado no disco antes de retornar um status de sucesso ao cliente. Essa variável tem trade-offs entre desempenho e confiabilidade. Se você precisar de mais desempenho, desative isso, o que significa que quando o servidor trava, há tendência de encontrar perda de dados. Caso contrário, se a confiabilidade for importante, defina-o como ativado. Isso significa que haverá um intervalo de tempo entre o status de sucesso e uma gravação garantida no disco, o que pode afetar o desempenho.
  • checkpoint_timeout, checkpoint_completion_target - O PostgreSQL grava as alterações no WAL, o que é uma operação cara. Se estiver gravando alterações com frequência no WAL, isso pode afetar negativamente o desempenho. Então, como funciona, o processo de ponto de verificação libera os dados nos arquivos de dados. Essa atividade é feita quando o CHECKPOINT ocorre e pode causar uma grande quantidade de IO. Todo esse processo envolve operações caras de leitura/gravação de disco. Embora você (usuário administrador) sempre possa emitir CHECKPOINT sempre que parecer necessário ou automatizá-lo definindo os valores desejados para esses parâmetros. O parâmetro checkpoint_timeout é usado para definir o tempo entre os pontos de verificação WAL. Definir isso muito baixo diminui o tempo de recuperação de falhas, pois mais dados são gravados no disco, mas também prejudica o desempenho, pois cada ponto de verificação acaba consumindo recursos valiosos do sistema. O checkpoint_completion_target é a fração de tempo entre os pontos de verificação para conclusão do ponto de verificação. Uma alta frequência de pontos de verificação pode afetar o desempenho. Para pontos de verificação suaves, checkpoint_timeout deve ser um valor baixo. Caso contrário, o sistema operacional acumulará todas as páginas sujas até que a proporção seja atendida e, em seguida, faça um grande flush.

Ajustando outros parâmetros para desempenho

Existem certos parâmetros que fornecem impulso e impulsionam o desempenho no PostgreSQL. Vamos listar quais são estes abaixo:

  • wal_buffers - O PostgreSQL grava seu registro WAL (write ahead log) nos buffers e, em seguida, esses buffers são liberados para o disco. O tamanho padrão do buffer, definido por wal_buffers, é de 16 MB, mas se você tiver muitas conexões simultâneas, um valor mais alto pode proporcionar um desempenho melhor.
  • effective_cache_size - O Effective_cache_size fornece uma estimativa da memória disponível para armazenamento em cache de disco. É apenas uma diretriz, não a memória alocada exata ou o tamanho do cache. Ele não aloca memória real, mas informa ao otimizador a quantidade de cache disponível no kernel. Se o valor for definido muito baixo, o planejador de consultas pode decidir não usar alguns índices, mesmo que sejam úteis. Portanto, definir um valor alto é sempre benéfico.
  • default_statistics_target - O PostgreSQL coleta estatísticas de cada uma das tabelas em seu banco de dados para decidir como as consultas serão executadas nelas. Por padrão, ele não coleta muitas informações, e se você não estiver obtendo bons planos de execução, deverá aumentar esse valor e depois executar ANALYZE no banco de dados novamente (ou aguardar o AUTOVACUUM).

Eficiência de consulta do PostgreSQL 

O PostgreSQL tem um recurso muito poderoso para otimizar consultas. Com o otimizador de consulta genética integrado (conhecido como GEQO). Ele usa um algoritmo genético que é um método de otimização heurística por meio de busca aleatória. Isso é aplicado ao realizar a otimização usando JOINs, o que fornece uma otimização de desempenho muito boa. Cada candidato no plano de junção é representado por uma sequência na qual unir as relações de base. Ele executa aleatoriamente um relacionamento genético simplesmente gerando alguma sequência de junção possível, mas aleatoriamente.

Para cada sequência de junção considerada, o código do planejador padrão é invocado para estimar o custo de realizar a consulta usando essa sequência de junção. Assim, para cada uma das sequências JOIN, todas têm seus planos de varredura de relação determinados inicialmente. Em seguida, o plano de consulta irá computar o plano mais viável e com melhor desempenho, ou seja, com menor custo estimado e considerado como “mais adequado” do que aqueles com maior custo.

Dado que ele possui um poderoso recurso integrado ao PostgreSQL e os parâmetros configurados de acordo com os requisitos desejados, ele não anula a viabilidade quando se trata de desempenho se a carga for lançada apenas para um nó primário. O balanceamento de carga com HAProxy ajuda a impulsionar ainda mais o desempenho do PostgreSQL.

Melhorando o desempenho do PostgreSQL com divisão de leitura e gravação 

Você pode ter um ótimo desempenho lidando com o nó do servidor PostgreSQL, mas pode não ser capaz de prever que tipo de carga de trabalho você pode ter, especialmente quando o tráfego é alto e a demanda sai do limite. Equilibrar a carga entre um primário e um secundário fornece um aumento de desempenho em seu aplicativo e/ou clientes que se conectam ao cluster de banco de dados PostgreSQL. Como isso pode ser feito, não é mais uma questão, pois é uma configuração muito comum para uma alta disponibilidade e redundância quando se trata de distribuir a carga e evitar que o nó primário fique atolado devido ao processamento de alta carga.

Configurar com HAProxy é fácil. No entanto, é mais eficiente, mais rápido e viável com o ClusterControl. Então, usaremos o ClusterControl para configurar isso para nós.

Configurando o PostgreSQL com HAProxy

Para fazer isso, basta instalar e configurar o HAProxy sobre os clusters do PostgreSQL. O HAProxy possui um recurso de suporte ao PostgreSQL através da opção pgsql-check mas seu suporte é uma implementação muito simples para determinar se um nó está ativo ou não. Ele não possui verificações para identificar um nó primário e um nó de recuperação. Uma opção é usar o xinetd para o qual dependeremos da comunicação do HAProxy para escutar através do nosso serviço xinetd que verifica a integridade de um nó específico em nosso cluster PostgreSQL.

Em ClusterControl, navegue até Gerenciar → Load Balancer como abaixo,

Em seguida, basta seguir com base na interface do usuário conforme a captura de tela abaixo. Você pode clicar em Mostrar configurações avançadas para ver opções mais avançadas. Seguir a interface do usuário é muito simples. Ver abaixo,

Estou importando apenas HAProxy de nó único sem redundância, mas para fins de este blog, vamos torná-lo mais simples.

Minha amostra de visualização HAProxy é mostrada abaixo,

Como mostrado acima, 192.168.30.20 e 192.168.30.30 são os principais e nós secundários/de recuperação, respectivamente. Considerando que o HAProxy está instalado no nó secundário/recuperação. Idealmente, você pode instalar seu HAProxy em vários nós para ter mais redundância e alta disponibilidade, é melhor isolá-lo em relação aos nós do banco de dados. Se você estiver com o orçamento apertado ou economizando seu uso, poderá optar por instalar seus nós HAProxy, onde seus nós de banco de dados também são instalados.

ClusterControl configura isso automaticamente e também inclui o serviço xinetd para verificação do PostgreSQL. Isso pode ser verificado com netstat como abaixo,

[email protected]:~# netstat -tlv4np|grep haproxy

tcp        0      0 0.0.0.0:5433            0.0.0.0:*               LISTEN      28441/haproxy

tcp        0      0 0.0.0.0:5434            0.0.0.0:*               LISTEN      28441/haproxy

tcp        0      0 0.0.0.0:9600            0.0.0.0:*               LISTEN      28441/haproxy

Enquanto a porta 5433 é leitura-gravação e 5444 é somente leitura.

Para PostgreSQL, verifique o serviço xinetd, ou seja, postgreshk como visto abaixo,

[email protected]:~# cat /etc/xinetd.d/postgreschk

# default: on

# description: postgreschk

service postgreschk

{

        flags           = REUSE

        socket_type     = stream

        port            = 9201

        wait            = no

        user            = root

        server          = /usr/local/sbin/postgreschk

        log_on_failure  += USERID

        disable         = no

        #only_from       = 0.0.0.0/0

        only_from       = 0.0.0.0/0

        per_source      = UNLIMITED

}

Os serviços xinetd também dependem de /etc/services para que você possa encontrar a porta designada para mapear.

[email protected]:~# grep postgreschk /etc/services

postgreschk        9201/tcp

Se você precisar alterar a porta do seu postgreschk para qual porta mapear, você também deve alterar este arquivo, além do arquivo de configuração do serviço, e não se esqueça de reiniciar o daemon xinetd.

O serviço postgreschk contém uma referência a um arquivo externo que basicamente verifica se os nós são graváveis, o que significa que é primário ou mestre. Se um nó estiver em recuperação, é uma réplica ou um nó de recuperação.

[email protected]:~# cat /usr/local/sbin/postgreschk

#!/bin/bash

#

# This script checks if a PostgreSQL server is healthy running on localhost. It will

# return:

# "HTTP/1.x 200 OK\r" (if postgres is running smoothly)

# - OR -

# "HTTP/1.x 500 Internal Server Error\r" (else)

#

# The purpose of this script is make haproxy capable of monitoring PostgreSQL properly

#



export PGHOST='localhost'

export PGUSER='s9smysqlchk'

export PGPASSWORD='password'

export PGPORT='7653'

export PGDATABASE='postgres'

export PGCONNECT_TIMEOUT=10



FORCE_FAIL="/dev/shm/proxyoff"



SLAVE_CHECK="SELECT pg_is_in_recovery()"

WRITABLE_CHECK="SHOW transaction_read_only"



return_ok()

{

    echo -e "HTTP/1.1 200 OK\r\n"

    echo -e "Content-Type: text/html\r\n"

    if [ "$1x" == "masterx" ]; then

        echo -e "Content-Length: 56\r\n"

        echo -e "\r\n"

        echo -e "<html><body>PostgreSQL master is running.</body></html>\r\n"

    elif [ "$1x" == "slavex" ]; then

        echo -e "Content-Length: 55\r\n"

        echo -e "\r\n"

        echo -e "<html><body>PostgreSQL slave is running.</body></html>\r\n"

    else

        echo -e "Content-Length: 49\r\n"

        echo -e "\r\n"

        echo -e "<html><body>PostgreSQL is running.</body></html>\r\n"

    fi

    echo -e "\r\n"



    unset PGUSER

    unset PGPASSWORD

    exit 0

}



return_fail()

{

    echo -e "HTTP/1.1 503 Service Unavailable\r\n"

    echo -e "Content-Type: text/html\r\n"

    echo -e "Content-Length: 48\r\n"

    echo -e "\r\n"

    echo -e "<html><body>PostgreSQL is *down*.</body></html>\r\n"

    echo -e "\r\n"



    unset PGUSER

    unset PGPASSWORD

    exit 1

}



if [ -f "$FORCE_FAIL" ]; then

    return_fail;

fi



# check if in recovery mode (that means it is a 'slave')

SLAVE=$(psql -qt -c "$SLAVE_CHECK" 2>/dev/null)

if [ $? -ne 0 ]; then

    return_fail;

elif echo $SLAVE | egrep -i "(t|true|on|1)" 2>/dev/null >/dev/null; then

    return_ok "slave"

fi



# check if writable (then we consider it as a 'master')

READONLY=$(psql -qt -c "$WRITABLE_CHECK" 2>/dev/null)

if [ $? -ne 0 ]; then

    return_fail;

elif echo $READONLY | egrep -i "(f|false|off|0)" 2>/dev/null >/dev/null; then

    return_ok "master"

fi



return_ok "none";

A combinação de usuário/senha deve ser um ROLE válido em seu servidor PostgreSQL. Como estamos instalando via ClusterControl, isso é tratado automaticamente.

Agora que temos uma instalação completa do HAProxy, essa configuração nos permite ter uma divisão de leitura-gravação em que leitura-gravação vão para o nó primário ou gravável, enquanto somente leitura para o primário e o secundário/ nós de recuperação. Essa configuração não significa que já tenha desempenho, ela ainda foi ajustada conforme discutido anteriormente com uma combinação de HAProxy para balanceamento de carga que adiciona mais aumento de desempenho para seu aplicativo e respectivos clientes de banco de dados.