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

Um Guia para Pgpool para PostgreSQL:Parte Um


O Pgpool é menos atual hoje do que costumava ser há 10 anos, quando era a parte padrão de uma configuração de produção do PostgreSQL. Muitas vezes, quando alguém estava falando sobre o cluster do PostgreSQL, eles estavam se referindo ao postgreSQL por trás do pgpool e não à própria instância do PostgreSQL (que é o termo correto). O Pgpool é reconhecido entre os jogadores mais influentes do Postgres:comunidade postgresql, prompt de comando, 2ndquadrant, EDB, citusdata, postgrespro (ordenado por idade, não por influência). Percebo que o nível de reconhecimento em meus links é muito diferente - só quero enfatizar o impacto geral do pgpool no mundo postgres. Alguns dos “vendedores” postgres atuais mais conhecidos foram encontrados depois que o pgpool já era famoso. Então, o que o torna tão famoso?

Apenas a lista dos recursos oferecidos mais procurados faz com que pareça ótimo:
  • replicação nativa
  • pool de conexões
  • balanceamento de carga para escalabilidade de leitura
  • alta disponibilidade (watchdog com IP virtual, recuperação online e failover)

Bem, vamos fazer uma caixa de areia e jogar. Minha configuração de amostra é o modo master slave. Eu diria que é o mais popular hoje, porque você normalmente usa replicação de streaming junto com balanceamento de carga. O modo de replicação é pouco usado atualmente. A maioria dos DBAs ignora isso em favor da replicação de streaming e do pglogical e, anteriormente, do slony.

O modo de replicação tem muitas configurações interessantes e funcionalidades certamente interessantes. Mas a maioria dos DBAs tem configuração master/multi slave quando chegam ao pgpool. Portanto, eles estão procurando por failover automático e balanceador de carga, e o pgpool o oferece pronto para uso para ambientes mestre/multi-escravo existentes. Sem falar que a partir do Postgres 9.4, a replicação de streaming funciona sem grandes bugs e a partir de 10 índices de hash a replicação é suportada, então quase não há nada que impeça você de usá-la. Também a replicação de streaming é assíncrona por padrão (configurável para sincronização síncrona e até mesmo não "linear" configurações complicadas, enquanto a replicação pgpool nativa é síncrona (o que significa mudanças de dados mais lentas) sem opção de escolha. Também se aplicam limitações adicionais. O próprio manual do Pgpool sugere a preferência quando possível, replicação de streaming sobre o pgpool nativo). E então esta é a minha escolha aqui.

Ah, mas primeiro precisamos instalá-lo - certo?

Instalação (de versão superior no Ubuntu).

Primeiro, verifique a versão do Ubuntu com lsb_release -a. Para mim repo é:
[email protected]:~# sudo add-apt-repository 'deb http://apt.postgresql.org/pub/repos/apt/ xenial-pgdg main'
wget --quiet -O - https://www.postgresql.org/media/keys/ACCC4CF8.asc | \
>   sudo apt-key add -
OK
[email protected]:~# sudo apt-get update

Por último a própria instalação:
sudo apt-get install pgpool2=3.7.2-1.pgdg16.04+1

Configuração:

Eu uso a configuração padrão do modo recomendado:
zcat /usr/share/doc/pgpool2/examples/pgpool.conf.sample-stream.gz > /etc/pgpool2/pgpool.conf

Iniciando:

Se você perdeu a configuração, verá:
2018-03-22 13:52:53.284 GMT [13866] FATAL:  role "nobody" does not exist

Ah verdade - meu mal, mas facilmente corrigível (realizável cegamente com um forro se você quiser o mesmo usuário para todas as verificações de integridade e recuperação):
[email protected]:~# sed -i s/'nobody'/'pgpool'/g /etc/pgpool2/pgpool.conf

E antes de prosseguirmos, vamos criar o banco de dados pgpool e o usuário pgpool em todos os clusters (no meu sandbox eles são master, failover e slave, então preciso executá-lo apenas no master):
t=# create database pgpool;
CREATE DATABASE
t=# create user pgpool;
CREATE ROLE

Finalmente - começando:
[email protected]:~$ /usr/sbin/service pgpool2 start
[email protected]:~$ /usr/sbin/service pgpool2 status
pgpool2.service - pgpool-II
   Loaded: loaded (/lib/systemd/system/pgpool2.service; enabled; vendor preset: enabled)
   Active: active (running) since Mon 2018-04-09 10:25:16 IST; 4h 14min ago
     Docs: man:pgpool(8)
  Process: 19231 ExecReload=/bin/kill -HUP $MAINPID (code=exited, status=0/SUCCESS)
 Main PID: 8770 (pgpool)
    Tasks: 10
   Memory: 5.5M
      CPU: 18.250s
   CGroup: /system.slice/pgpool2.service
           ├─ 7658 pgpool: wait for connection reques
           ├─ 7659 pgpool: wait for connection reques
           ├─ 7660 pgpool: wait for connection reques
           ├─ 8770 /usr/sbin/pgpool -n
           ├─ 8887 pgpool: PCP: wait for connection reques
           ├─ 8889 pgpool: health check process(0
           ├─ 8890 pgpool: health check process(1
           ├─ 8891 pgpool: health check process(2
           ├─19915 pgpool: postgres t ::1(58766) idl
           └─23730 pgpool: worker proces

Ótimo - para que possamos prosseguir para o primeiro recurso - vamos verificar o balanceamento de carga. Ele tem alguns requisitos para ser usado, suporta dicas (por exemplo, balancear na mesma sessão), tem funções de lista negra e branca, tem lista de preferências de redirecionamento baseada em expressões regulares. É sofisticado. Infelizmente, passar por cima de toda essa funcionalidade estaria fora do escopo deste blog, portanto, verificaremos as demonstrações mais simples:

Primeiro, algo bem simples mostrará qual nó é usado para selecionar (na minha configuração, master gira em 5400, slave em 5402 e failover em 5401, enquanto o próprio pgpool está em 5433, pois tenho outro cluster em execução e não queria interferir com isso):
[email protected]:~$ psql -h localhost -p 5433 t -c "select current_setting('port') from ts limit 1"
 current_setting
-----------------
 5400
(1 row)

Então em loop:
[email protected]:~$ (for i in $(seq 1 99); do psql -h localhost -p 5433 t -c "select current_setting('port') from ts limit 1" -XAt; done) | sort| uniq -c
      9 5400
     30 5401
     60 5402

Excelente. Ele definitivamente equilibra a carga entre os nós, mas parece não equilibrar igualmente - talvez seja tão inteligente que saiba o peso de cada instrução? Vamos verificar a distribuição com os resultados esperados:
t=# show pool_nodes;
 node_id | hostname  | port | status | lb_weight |  role   | select_cnt | load_balance_node | replication_delay
---------+-----------+------+--------+-----------+---------+------------+-------------------+-------------------
 0       | localhost | 5400 | up     | 0.125000  | primary | 122        | false             | 0
 1       | localhost | 5401 | up     | 0.312500  | standby | 169        | false             | 0
 2       | localhost | 5402 | up     | 0.562500  | standby | 299        | true              | 0
(3 rows)

Não - o pgpool não analisa o peso das declarações - era um DBA com as configurações dela novamente! As configurações (consulte o atributo lb_weight) são reconciliadas com os destinos de destino de consulta reais. Você pode alterá-lo facilmente (como fizemos aqui) alterando a configuração correspondente, por exemplo:
[email protected]:~$ grep weight /etc/pgpool2/pgpool.conf
backend_weight0 =0.2
backend_weight1 = 0.5
backend_weight2 = 0.9
[email protected]:~# sed -i s/'backend_weight2 = 0.9'/'backend_weight2 = 0.2'/ /etc/pgpool2/pgpool.conf
[email protected]:~# grep backend_weight2 /etc/pgpool2/pgpool.conf
backend_weight2 = 0.2
[email protected]:~# pgpool reload
[email protected]:~$ (for i in $(seq 1 9); do psql -h localhost -p 5433 t -c "select current_setting('port') from ts limit 1" -XAt; done) | sort| uniq -c
      6 5401
      3 5402
Baixe o whitepaper hoje PostgreSQL Management &Automation with ClusterControlSaiba o que você precisa saber para implantar, monitorar, gerenciar e dimensionar o PostgreSQLBaixe o whitepaper
Excelente! O próximo grande recurso oferecido é o pool de conexões. Com o 3.5, o “problema do rebanho trovejante” é resolvido pela serialização de chamadas accept(), acelerando bastante o tempo de “conexão do cliente”. E, no entanto, esse recurso é bastante simples. Ele não oferece vários níveis de pooling ou vários pools configurados para o mesmo banco de dados (o pgpool permite que você escolha onde executar seleções com database_redirect_preference_list de balanceamento de carga), ou outros recursos flexíveis oferecidos pelo pgBouncer.

Demonstração tão curta:
t=# select pid,usename,backend_type, state, left(query,33) from pg_stat_activity where usename='vao' and pid <> pg_backend_pid();
 pid  | usename |  backend_type  | state |     left
------+---------+----------------+-------+--------------
 8911 | vao     | client backend | idle  |  DISCARD ALL
 8901 | vao     | client backend | idle  |  DISCARD ALL
 7828 | vao     | client backend | idle  |  DISCARD ALL
 8966 | vao     | client backend | idle  |  DISCARD ALL
(4 rows)
Hm - did I set up this little number of children?
t=# pgpool show num_init_children;
 num_init_children
-------------------
 4
(1 row)

Ah, é verdade, eu mudei eles abaixo do padrão 32, então a saída não levaria várias páginas. Pois então, vamos tentar ultrapassar o número de sessões (abaixo eu abro sessões postgres assíncronas em loop, então as 6 sessões seriam requisitadas mais ou menos ao mesmo tempo):
[email protected]:~$ for i in $(seq 1 6); do (psql -h localhost -p 5433 t -U vao -c "select pg_backend_pid(), pg_sleep(1), current_setting('port'), clock_timestamp()" &);  done
[email protected]:~$  pg_backend_pid | pg_sleep | current_setting |        clock_timestamp
----------------+----------+-----------------+-------------------------------
           8904 |          | 5402            | 2018-04-10 12:46:55.626206+01
(1 row)

 pg_backend_pid | pg_sleep | current_setting |        clock_timestamp
----------------+----------+-----------------+-------------------------------
           9391 |          | 5401            | 2018-04-10 12:46:55.630175+01
(1 row)

 pg_backend_pid | pg_sleep | current_setting |       clock_timestamp
----------------+----------+-----------------+------------------------------
           8911 |          | 5400            | 2018-04-10 12:46:55.64933+01
(1 row)

 pg_backend_pid | pg_sleep | current_setting |        clock_timestamp
----------------+----------+-----------------+-------------------------------
           8904 |          | 5402            | 2018-04-10 12:46:56.629555+01
(1 row)

 pg_backend_pid | pg_sleep | current_setting |        clock_timestamp
----------------+----------+-----------------+-------------------------------
           9392 |          | 5402            | 2018-04-10 12:46:56.633092+01
(1 row)

 pg_backend_pid | pg_sleep | current_setting |       clock_timestamp
----------------+----------+-----------------+------------------------------
           8910 |          | 5402            | 2018-04-10 12:46:56.65543+01
(1 row)

Ele permite que as sessões cheguem a três - esperado, já que uma é tomada pela sessão acima (selecionando em pg_stat_activity) então 4-1=3. Assim que o pg_sleep termina sua segunda soneca e a sessão é encerrada pelo postgres, a próxima é liberada. Então, depois que as três primeiras terminam, as próximas três entram em cena. O que acontece com o resto? Eles são enfileirados até que o próximo slot de conexão seja liberado. Em seguida, o processo descrito ao lado de serialize_accept acontece e o cliente é conectado.

Huh? Apenas pool de sessão no modo de sessão? É tudo?.. Não, aqui entra o cache! Olhar.:
postgres=# /*NO LOAD BALANCE*/ select 1;
 ?column?
----------
        1
(1 row)

Verificando a pg_stat_activity:
postgres=# select pid, datname, state, left(query,33),state_change::time(0), now()::time(0) from pg_stat_activity where usename='vao' and query not like '%DISCARD%';
  pid  | datname  | state |               left                | state_change |   now
-------+----------+-------+-----------------------------------+--------------+----------
 15506 | postgres | idle  | /*NO LOAD BALANCE*/ select 1, now | 13:35:44     | 13:37:19
(1 row)

Em seguida, execute a primeira instrução novamente e observe state_change não mudando, o que significa que você nem chega ao banco de dados para obter um resultado conhecido! Claro que se você colocar alguma função mutável, os resultados não serão armazenados em cache. Experimente com:
postgres=# /*NO LOAD BALANCE*/ select 1, now();
 ?column? |             now
----------+------------------------------
        1 | 2018-04-10 13:35:44.41823+01
(1 row)

Você descobrirá que state_change muda assim como o resultado.

Último ponto aqui - por que /*NO LOAD BALANCE*/ ?.. para ter certeza de que verificamos pg_stat_activity no mestre e executamos a consulta no mestre também. Da mesma forma, você pode usar a dica /*NO QUERY CACHE*/ para evitar obter um resultado em cache.

Já muito para uma breve revisão? Mas nem tocamos na parte do HA! E muitos usuários procuram o pgpool especificamente para esse recurso. Bem, este não é o fim da história, este é o fim da primeira parte. A segunda parte está chegando, onde abordaremos brevemente o HA e algumas outras dicas sobre o uso do pgpool...