PostgreSQL
 sql >> Baza danych >  >> RDS >> PostgreSQL

Przewodnik po Pgpool dla PostgreSQL:część druga

To jest druga część bloga „A Guide to Pgpool for PostgreSQL”. Pierwsza część obejmująca równoważenie obciążenia, łączenie sesji, pamięć podręczną i instalację można znaleźć tutaj.

Wielu użytkowników patrzy na pgpool specjalnie z myślą o funkcjach wysokiej dostępności i ma on wiele do zaoferowania. W sieci jest sporo instrukcji dotyczących pgpool HA (np. dłuższa i krótsza), więc nie ma sensu ich powtarzać. Nie chcemy też dostarczać kolejnego ślepego zestawu wartości konfiguracyjnych. Zamiast tego sugeruję grać wbrew regułom i robić to w niewłaściwy sposób, dzięki czemu zobaczymy ciekawe zachowanie. Jedną z najbardziej oczekiwanych funkcji (przynajmniej znajduje się na górze strony) jest możliwość rozpoznania użyteczności „martwego” ex mastera i ponownego użycia go z pg_rewind. Może to zaoszczędzić godziny przywracania nowego trybu gotowości z dużymi danymi (ponieważ pomijamy rsync lub pg_basebackup, które skutecznie kopiują WSZYSTKIE pliki z nowego wzorca). Ściśle mówiąc, pg_rewind jest przeznaczony do planowanego przełączania awaryjnego (podczas aktualizacji lub migracji na nowy sprzęt). Ale widzieliśmy, kiedy bardzo pomaga w niezaplanowanym, ale jeszcze wdzięcznym zamykaniu i automatycznym przełączaniu awaryjnym — na przykład ClusterControl wykorzystuje go podczas automatycznego przełączania awaryjnego jednostek podrzędnych replikacji. Załóżmy, że tak jest:potrzebujemy (dowolnego) mistrza, aby był jak najbardziej dostępny. Jeśli z jakiegoś powodu (awaria sieci, przekroczenie maksymalnej liczby połączeń lub jakakolwiek inna „awaria”, która uniemożliwia rozpoczęcie nowych sesji) nie możemy już używać mastera do operacji RW, mamy skonfigurowany klaster pracy awaryjnej z urządzeniami slave, które mogą akceptować połączenia. Możemy wtedy awansować jednego z niewolników i przejść do niego.

Najpierw załóżmy, że mamy trzy węzły:

  • 10.1.10.124:5400 z /pg/10/m (pgpool też się tu kręci)
  • 10.1.10.147:5401 z /pg/10/m2
  • 10.1.10.124:5402 z /pg/10/s2

W rzeczywistości są to te same węzły, co w części pierwszej, ale węzeł awaryjny jest przenoszony na inny host i $PGDATA. Zrobiłem to, aby upewnić się, że nie popełniłem literówki lub nie zapomniałem dodatkowego cytatu w zdalnym poleceniu ssh. Również informacje debugowania będą wyglądać na prostsze, ponieważ adresy IP są różne. W końcu nie byłem pewien, czy uda mi się uruchomić ten nieobsługiwany przypadek użycia, więc muszę to zobaczyć na własne oczy.

Przełączanie awaryjne

Najpierw ustawiamy polecenie failover_command i uruchamiamy pgpool reload i próbujemy przełączyć się w tryb failover. Tu i dalej, wyślę jakieś informacje do /tmp/d na serwerze pgpool, więc mogę tail -f /tmp/d zobaczyć przepływ.

[email protected]:~$ grep failover_command /etc/pgpool2/pgpool.conf
failover_command = 'bash /pg/10/fo.sh %D %H %R'

[email protected]:~$ cat /pg/10/fo.sh
rem_cmd="pg_ctl -D $3 promote"
cmd="ssh -T [email protected]$2 $rem_cmd"
echo "$(date) $cmd" >>/tmp/d
$cmd &>>/tmp/d

NB:Czy masz ustawioną ścieżkę $PATH w .bashrc na zdalnym hoście?..

Zatrzymajmy mistrza (wiem, że nie tak dzieje się katastrofa, spodziewasz się, że przynajmniej jakaś wielka małpa lub czerwony świecący robot rozwali serwer ogromnym młotem, albo przynajmniej nudne dyski twarde, by umrzeć, ale używam tego pełnego wdzięku wariant do demonstracji możliwego użycia pg_rewind, więc tutaj przełączenie awaryjne będzie wynikiem błędu ludzkiego lub awarii sieci pół sekundy w ciągu health_check_period), więc:

/usr/lib/postgresql/10/bin/pg_ctl -D /pg/10/m stop
2018-04-18 13:53:55.469 IST [27433]  LOG:  received fast shutdown request
waiting for server to shut down....2018-04-18 13:53:55.478 IST [27433]  LOG:  aborting any active transactions
2018-04-18 13:53:55.479 IST [28855] postgres t FATAL:  terminating connection due to administrator command
2018-04-18 13:53:55.483 IST [27433]  LOG:  worker process: logical replication launcher (PID 27440) exited with exit code 1
2018-04-18 13:53:55.484 IST [27435]  LOG:  shutting down
2018-04-18 13:53:55.521 IST [27433]  LOG:  database system is shut down
 done
server stopped

Teraz sprawdzam wyjście polecenia failover:

[email protected]:~$ cat /tmp/d
Wed Apr 18 13:54:05 IST 2018 ssh -T [email protected]
pg_ctl -D /pg/10/f promote
waiting for server to promote.... done
server promoted

I sprawdzenie po chwili:

t=# select nid,port,st, role from dblink('host=localhost port=5433','show pool_nodes') as t (nid int,hostname text,port int,st text,lb_weight float,role text,cnt int,cur_node text,del int);
 nid | port |  st  |  role
-----+------+------+---------
   0 | 5400 | down | standby
   1 | 5401 | up   | primary
   2 | 5402 | up   | standby
(3 rows)

Widzimy również w dziennikach klastra ex-failover:

2018-04-13 14:26:20.823 IST [20713]  LOG:  received promote request
2018-04-13 14:26:20.823 IST [20713]  LOG:  redo done at 0/951EC20
2018-04-13 14:26:20.823 IST [20713]  LOG:  last completed transaction was at log time 2018-04-13 10:41:54.355274+01
2018-04-13 14:26:20.872 IST [20713]  LOG:  selected new timeline ID: 2
2018-04-13 14:26:20.966 IST [20713]  LOG:  archive recovery complete
2018-04-13 14:26:20.998 IST [20712]  LOG:  database system is ready to accept connections

Sprawdzanie replikacji:

[email protected]:~$ psql -p 5401 t -c "select now() into test"
SELECT 1
[email protected]:~$ psql -p 5402 t -c "select * from test"
              now
-------------------------------
 2018-04-13 14:33:19.569245+01
(1 row)

Slave /pg/10/s2:5402 przełączył się na nową oś czasu dzięki recovery_target_timeline =najnowszy w recovery.conf, więc jesteśmy dobrzy. Nie musimy dostosowywać pliku recovery.conf, aby wskazywał nowy master, ponieważ wskazuje on na adres IP i port pgpool i pozostają one takie same bez względu na to, kto pełni rolę głównego mastera.

Sprawdzanie równoważenia obciążenia:

[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

Ładny. Aplikacje za pgpool zauważą drugą awarię i będą nadal działać.

Ponowne wykorzystanie byłego mistrza

Teraz możemy przełączyć byłego mastera w tryb gotowości do przełączania awaryjnego i przywrócić go (bez dodawania nowego węzła do pgpool, ponieważ już tam istnieje). Jeśli nie masz włączonej funkcji wal_log_hints lub sum kontrolnych danych (pełna różnica między tymi opcjami jest tutaj), musisz ponownie utworzyć klaster na byłym wzorcu, aby podążać za nową osią czasu:

[email protected]:~$ rm -fr /pg/10/m
[email protected]:~$ pg_basebackup -h localhost -p 5401 -D /pg/10/m/

Ale nie spiesz się, aby uruchomić powyższe stwierdzenia! Jeśli zadbałeś o wal_log_hints (wymaga ponownego uruchomienia), możesz spróbować użyć pg_rewind, aby znacznie szybciej przełączyć byłego mastera na nowy slave.

Więc ATM mamy byłego mistrza w trybie offline, nowego mistrza z rozpoczętą kolejną osią czasu. Jeśli były mistrz był offline z powodu tymczasowej awarii sieci i wraca, musimy go najpierw wyłączyć. W powyższym przypadku wiemy, że jest wyłączony, więc możemy po prostu spróbować przewinąć:

[email protected]:~$ pg_rewind -D /pg/10/m2 --source-server="port=5401 host=10.1.10.147"
servers diverged at WAL location 0/40605C0 on timeline 2
rewinding from last common checkpoint at 0/4060550 on timeline 2
Done!

I znowu:

[email protected]:~$ pg_ctl -D /pg/10/m2 start
server started
...blah blah 
[email protected]:~$ 2018-04-16 12:08:50.303 IST [24699]  LOG:  started streaming WAL from primary at 0/B000000 on timeline 2

t=# select nid,port,st,role from dblink('host=localhost port=5433','show pool_nodes') as t (nid int,hostname text,port int,st text,lb_weight float,role text,cnt int,cur_node text,del int);
 nid | port |  st  |  role
-----+------+------+---------
   0 | 5400 | down | standby
   1 | 5401 | up   | primary
   2 | 5402 | up   | standby
(3 rows)

Ops. Och! Pomimo faktu, że klaster na porcie 5400 jest w trybie online i podąża za nową osią czasu, musimy powiedzieć pgpool, aby go rozpoznał:

[email protected]:~$ pcp_attach_node -w -h 127.0.0.1 -U vao -n 0
 pcp_attach_node  -- Command Successful

Teraz wszystkie trzy działają (a pgpool o tym wie) i są zsynchronizowane:

[email protected]:~$ sql="select ts.i::timestamp(0), current_setting('data_directory'),case when pg_is_in_recovery() then 'recovering' else 'mastering' end stream from ts order by ts desc"
[email protected]:~$ psql -h 10.1.10.147 -p 5401 t -c "$sql";
          i          | current_setting |  stream
---------------------+-----------------+-----------
 2018-04-30 14:34:36 | /pg/10/m2       | mastering
(1 row)

[email protected]:~$ psql -h 10.1.10.124 -p 5402 t -c "$sql";
          i          | current_setting |   stream
---------------------+-----------------+------------
 2018-04-30 14:34:36 | /pg/10/s2       | recovering
(1 row)

[email protected]:~$ psql -h 10.1.10.124 -p 5400 t -c "$sql";
          i          | current_setting |   stream
---------------------+-----------------+------------
 2018-04-30 14:34:36 | /pg/10/m        | recovering
(1 row)

Teraz spróbuję użyć recovery_1st_stage_command do ponownego użycia byłego mistrza:

[email protected]:~# grep 1st /etc/pgpool2/pgpool.conf
recovery_1st_stage_command = 'or_1st.sh'

Ale recovery_1st_stage_command nie oferuje potrzebnych argumentów dla pg_rewind, które widzę, jeśli dodam do recovery_1st_stage_command:

echo "online recovery started on $(hostname) $(date --iso-8601) $0 $1 $2 $3 $4"; exit 1;

Wynik:

online recovery started on u2 2018-04-30 /pg/10/m2/or_1st.sh /pg/10/m2 10.1.10.124 /pg/10/m 5401

Cóż - użycie pg_rewind jest tylko na liście rzeczy do zrobienia - czego się spodziewałem?.. Więc muszę zrobić trochę małpiego hacka, aby uzyskać główny adres IP i port (pamiętaj, że będzie się zmieniał po awarii).

Pobierz oficjalny dokument już dziś Zarządzanie i automatyzacja PostgreSQL za pomocą ClusterControlDowiedz się, co musisz wiedzieć, aby wdrażać, monitorować, zarządzać i skalować PostgreSQLPobierz oficjalny dokument

Małpa hack

Więc mam coś takiego w recovery_1st_stage_command:

[email protected]:~# cat /pg/10/or_1st.sh
pgpool_host=10.1.10.124
pgpool_port=5433
echo "online recovery started on $(hostname) $(date --iso-8601) $0 $1 $2 $3 $4" | ssh -T $pgpool_host "cat >> /tmp/d"
master_port=$(psql -XAt -h $pgpool_host -p $pgpool_port t -c "select port from dblink('host=$pgpool_host port=$pgpool_port','show pool_nodes') as t (nid int,hostname text,port int,st text,lb_weight float,role text,cnt int,cur_node text,del int) where role='primary'")
master_host=$(psql -XAt -h $pgpool_host -p $pgpool_port t -c "select hostname from dblink('host=$pgpool_host port=$pgpool_port','show pool_nodes') as t (nid int,hostname text,port int,st text,lb_weight float,role text,cnt int,cur_node text,del int) where role='primary'")
failover_host=$(psql -XAt -h $pgpool_host -p $pgpool_port t -c "select hostname from dblink('host=$pgpool_host port=$pgpool_port','show pool_nodes') as t (nid int,hostname text,port int,st text,lb_weight float,role text,cnt int,cur_node text,del int) where role!='primary' order by port limit 1")
src='"port=$master_port host=$master_host"'
rem_cmd="'pg_rewind -D $3 --source-server=\"port=$master_port host=$master_host\"'"
cmd="ssh -T $failover_host $rem_cmd"
echo $cmd | ssh -T $pgpool_host "cat >> /tmp/d"
$cmd

tmp=/tmp/rec_file_tmp
cat > $tmp <<EOF
standby_mode          = 'on'
primary_conninfo      = 'host=$master_host port=$master_port user=postgres'
trigger_file = '/tmp/tg_file'
recovery_target_timeline  = latest
EOF

scp $tmp $failover_host:$3/recovery.conf

rem_cmd="pg_ctl -D $3 start"
cmd="ssh -T $failover_host $rem_cmd"
echo $cmd | ssh -T $pgpool_host "cat >> /tmp/d"
$cmd
echo "OR finished $(date --iso-8601)" | ssh -T $pgpool_host "cat >> /tmp/d"
exit 0;

Co za bałagan! Cóż – jeśli zdecydujesz się skorzystać z nieistniejącej funkcji – przygotuj się – będzie źle wyglądała, działała gorzej i na stałe będziesz się wstydził tego, co zrobiłeś. Więc krok po kroku:

  • Potrzebuję adresu IP i portu pgpool, aby zdalnie się z nim połączyć, zarówno w celu zapytania „show pool_nodes”, jak i rejestrowania kroków oraz wykonywania poleceń.
  • Przesyłam trochę informacji o dbg do /tmp/d przez ssh, ponieważ polecenie zostanie wykonane po stronie mastera, co zmieni się po awarii
  • Mogę użyć wyniku „show pool_nodes”, aby uzyskać informacje o uruchomionym połączeniu głównym, po prostu filtrując za pomocą klauzuli WHERE
  • Będę potrzebował podwójnych cudzysłowów w argumencie dla pg_rewind, który będzie musiał uruchomić się przez ssh, więc po prostu podzielę polecenie dla czytelności, a następnie powtórzę i uruchomię
  • Przygotowuję plik recovery.conf na podstawie danych wyjściowych z „show pool_nodes” (pisząc go zadaję sobie pytanie – dlaczego zamiast tego nie użyłem adresu IP i portu pgpool?..
  • Uruchamianie nowego urządzenia podrzędnego awaryjnego (wiem, że powinienem użyć drugiego kroku – po prostu pominąłem, aby uniknąć ponownego uzyskania wszystkich adresów IP i portów)

Teraz co pozostało - próba wykorzystania tego bałaganu w pcp:

[email protected]:~# pcp_recovery_node -h 127.0.0.1 -U vao -n 0 -w
pcp_recovery_node -- Command Successful
[email protected]:~# psql -h localhost -p 5433 t -c"select nid,port,st,role from dblink('host=10.1.10.124 port=5433','show pool_nodes') as t (nid int,hostname text,port int,st text,lb_weight float,role text,cnt int,cur_node text,del int)"
 nid | port | st |  role
-----+------+----+---------
   0 | 5400 | up | standby
   1 | 5401 | up | primary
   2 | 5402 | up | standby
(3 rows)

Sprawdzanie /tmp/d na serwerze pgpool:

[email protected]:~# cat /tmp/d
Tue May  1 11:37:59 IST 2018 ssh -T [email protected] /usr/lib/postgresql/10/bin/pg_ctl -D /pg/10/m2 promote
waiting for server to promote.... done
server promoted
online recovery started on u2 2018-05-01 /pg/10/m2/or_1st.sh /pg/10/m2
ssh -T 10.1.10.124 'pg_rewind -D --source-server="port=5401 host=10.1.10.147"'
ssh -T 10.1.10.124 pg_ctl -D start
OR finished 2018-05-01

Teraz oczywiście chcemy przewrócić go ponownie, aby sprawdzić, czy działa na dowolnym hoście:

[email protected]:~$ ssh -T 10.1.10.147 pg_ctl -D /pg/10/m2 stop             waiting for server to shut down.... done
server stopped
[email protected]:~$ psql -h localhost -p 5433 t -c"select nid,port,st,role from dblink('host=10.1.10.124 port=5433','show pool_nodes') as t (nid int,hostname text,port int,st text,lb_weight float,role text,cnt int,cur_node text,del int)"
 nid | port |  st  |  role
-----+------+------+---------
   0 | 5400 | up   | primary
   1 | 5401 | down | standby
   2 | 5402 | up   | standby
(3 rows)

[email protected]:~# pcp_recovery_node -h 127.0.0.1 -U vao -n 1 -w

[email protected]:~$ psql -h localhost -p 5433 t -c"select nid,port,st,role from dblink('host=10.1.10.124 port=5433','show pool_nodes') as t (nid int,hostname text,port int,st text,lb_weight float,role text,cnt int,cur_node text,del int)"
 nid | port | st |  role
-----+------+----+---------
   0 | 5400 | up | primary
   1 | 5401 | up | standby
   2 | 5402 | up | standby
(3 rows)

Log wygląda podobnie - zmienił się tylko adres IP i porty:

 Tue May  1 11:44:01 IST 2018 ssh -T [email protected] /usr/lib/postgresql/10/bin/pg_ctl -D /pg/10/m promote
waiting for server to promote.... done
server promoted
online recovery started on u 2018-05-01 /pg/10/m/or_1st.sh /pg/10/m 10.1.10.147 /pg/10/m2 5400
ssh -T 10.1.10.147 'pg_rewind -D /pg/10/m2 --source-server="port=5400 host=10.1.10.124"'
ssh -T 10.1.10.147 pg_ctl -D /pg/10/m2 start
online recovery started on u 2018-05-01 /pg/10/m/or_1st.sh /pg/10/m
ssh -T 10.1.10.147 'pg_rewind -D --source-server="port=5400 host=10.1.10.124"'
ssh -T 10.1.10.147 pg_ctl -D start
OR finished 2018-05-01

W tej piaskownicy master przeniósł się do 5401 po przełączeniu awaryjnym, a po pewnym czasie życia w tym miejscu powrócił do 5400. Użycie pg_rewind powinno przyspieszyć działanie. Wcześniej przerażającą częścią automatycznego przełączania awaryjnego było - jeśli naprawdę zepsułeś konfigurację i nie przewidziałeś jakiejś siły wyższej, możesz natknąć się na automatyczne przełączanie awaryjne do następnego urządzenia podrzędnego, a następnie do następnego, aż nie będzie już wolnego urządzenia podrzędnego. A potem po prostu kończysz z kilkoma mistrzami z podzielonymi mózgami i bez zapasowego zapasu. Słabym pocieszeniem w takim scenariuszu jest posiadanie jeszcze większej liczby niewolników do przełączania awaryjnego, ale bez pg_rewind nie miałbyś nawet tego. „Tradycyjny” rsync lub pg_basebackup kopiuje WSZYSTKIE $PGDATA, aby utworzyć rezerwę i nie może ponownie użyć „niezbyt innego” ex master.

Kończąc ten eksperyment, chciałbym jeszcze raz podkreślić - nie jest to rozwiązanie odpowiednie do wklejania kopii w ciemno. Użycie pg_rewind nie jest zalecane dla pg_pool. Nie można z niego korzystać w żadnym bankomacie. Chciałem dodać trochę świeżego powietrza do konfiguracji pgpool HA, aby nuby takie jak ja mogły bliżej przyjrzeć się, jak to działa. Aby koryfeusz uśmiechnął się z naiwistycznego podejścia i może zobaczył to naszymi - nubeskimi oczami.


  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Różnica między znacznikami czasu z/bez strefy czasowej w PostgreSQL

  2. Łączenie PostgreSQL 9.2.1 z Hibernate

  3. W mojej bazie danych PostgreSQL brakuje miejsca na dysku

  4. Wypełnianie pola Many2many (odoo 8)

  5. Migracja z DB2 do PostgreSQL — co powinieneś wiedzieć