PostgreSQL
 sql >> база данни >  >> RDS >> PostgreSQL

Ръководство за Pgpool за PostgreSQL:Част втора

Това е втората част от блога „Ръководство за Pgpool за PostgreSQL“. Първата част, обхващаща балансирането на натоварването, обединяването на сесиите, кеша на паметта и инсталацията, може да бъде намерена тук.

Много потребители търсят pgpool специално за функции с висока достъпност и той има какво да предложи. В мрежата има няколко доста инструкции за pgpool HA (например по-дълга и по-къса), така че няма да има смисъл да ги повтаряте. Нито искаме да предоставим още един сляп набор от конфигурационни стойности. Вместо това предлагам да играете срещу правилата и да опитате да го направите по грешен начин, така че ще видим интересно поведение. Една от най-очакваните функции (поне е в горната част на страницата) е способността да се разпознае използваемостта на „мъртъв“ бивш главен и да се използва повторно с pg_rewind. Това може да спести часове на връщане на новия режим на готовност с големи данни (тъй като пропускаме rsync или pg_basebackup, които ефективно копират ВСИЧКИ файлове от новия главен файл). Строго погледнато, pg_rewind е предназначен за планирано преминаване на отказ (по време на надстройка или мигриране към нов хардуер). Но видяхме кога това е много полезно при непланирано, но все пак грациозно изключване и автоматизирано превключване при отказ - например ClusterControl го използва, когато извършва автоматично превключване при отказ на подчинени устройства за репликация. Да предположим, че имаме случая:имаме нужда от (всякакъв) master, за да бъде достъпен колкото е възможно повече. Ако по някаква причина (мрежова повреда, превишаване на максималния брой връзки или всякаква друга „провал“, която забранява стартирането на нови сесии) вече не можем да използваме главен за RW операции, имаме конфигуриран клъстер за отказване с подчинени устройства, които могат да приемат връзки. След това можем да повишим един от робите и да се провалим към него.

Първо да приемем, че имаме три възела:

  • 10.1.10.124:5400 с /pg/10/m (pgpool се върти и тук)
  • 10.1.10.147:5401 с /pg/10/m2
  • 10.1.10.124:5402 с /pg/10/s2

Това на практика са същите възли като в част първа, но възелът за преодоляване на отказ е преместен на друг хост и $PGDATA. Направих го, за да се уверя, че не съм допуснал печатна грешка или не съм забравил някой допълнителен цитат в отдалечената ssh команда. Също така информацията за отстраняване на грешки ще изглежда по-проста, защото ip адресите са различни. Накрая не бях сигурен, че ще мога да накарам този неподдържан случай на използване да работи, така че трябва да го видя със собствените си очи.

Отказ при отказ

Първо задаваме failover_command и стартираме pgpool reload и се опитваме да преминем към отказ. Тук и по-нататък ще отразя малко информация към /tmp/d на сървъра на pgpool, за да мога да tail -f /tmp/d, за да видя потока.

[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:Имате ли зададен $PATH в .bashrc на отдалечен хост?..

Нека спрем господаря (знам, че не се случва бедствието, очаквате поне някаква огромна маймуна или червен блестящ робот да разбие сървъра с огромен чук или поне скучните твърди дискове да умрат, но аз използвам този грациозен вариант за демонстрация на възможното използване на pg_rewind, така че тук преминаването при отказ ще бъде резултат от човешка грешка или мрежова повреда половин секунда през периода на Health_check_period), така че:

/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

Сега проверяваме изхода на командата за преодоляване на срив:

[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

И проверка след известно време:

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)

Също така виждаме в регистрационните файлове на клъстер за преодоляване на отказ:

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

Проверка на репликация:

[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 премина към нова времева линия благодарение на recovery_target_timeline =последно в recovery.conf, така че сме добре. Не е необходимо да коригираме recovery.conf, за да сочи към новия главен файл, защото той сочи към pgpool ip и порт и те остават същите, независимо кой изпълнява основната роля на главен.

Проверка на балансирането на натоварването:

[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

Хубаво. Приложенията зад pgpool ще забележат второ прекъсване и ще продължат да работят.

Повторно използване на бившия главен

Сега можем да превърнем ex-master в режим на готовност при отказ и да го върнем обратно (без да добавяме нов възел към pgpool, тъй като той вече съществува там). Ако нямате активиран wal_log_hints или контролни суми за данни (изчерпателна разлика между тези опции е тук), трябва да пресъздадете клъстер на ex-master, за да следвате нова времева линия:

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

Но не бързайте да изпълнявате изявленията по-горе! Ако сте се погрижили за wal_log_hints (изисква рестартиране), можете да опитате да използвате pg_rewind за много по-бързо превключване на бившия главен към нов подчинен.

И така банкомат имаме бившият главен офлайн, нов главен със следващата времева линия стартира. Ако бившият главен е бил офлайн поради временна повреда в мрежата и се върне, първо трябва да го изключим. В случая по-горе знаем, че е надолу, така че можем просто да опитаме да превъртим назад:

[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!

И отново:

[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. Дух! Въпреки факта, че клъстерът на порт 5400 е онлайн и следва нова времева линия, трябва да кажем на pgpool да го разпознае:

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

Сега и трите са готови (и pgpool го знае) и са в синхрон:

[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)

Сега ще опитам да използвам recovery_1st_stage_command за повторно използване на ex-master:

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

Но recovery_1st_stage_command не предлага необходимите аргументи за pg_rewind, които мога да видя, ако добавя към recovery_1st_stage_command:

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

Резултатът:

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

Е – използването на pg_rewind е само в списъка със задачи – какво очаквах?.. Така че трябва да направя някакъв маймунски хак, за да получа главен IP адрес и порт (не забравяйте, че ще продължи да се променя след отказ).

Изтеглете Бялата книга днес Управление и автоматизация на PostgreSQL с ClusterControl Научете какво трябва да знаете, за да внедрите, наблюдавате, управлявате и мащабирате PostgreSQLD Изтеглете Бялата книга

Маймунски хак

Така че имам нещо подобно в 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;

Сега каква бъркотия! Е - ако решите да използвате несъществуваща функция - подгответе се - тя ще изглежда зле, ще работи по-зле и ще се срамувате постоянно от това, което сте направили. Така че стъпка по стъпка:

  • Имам нужда от pgpool IP и порт, за да се свържа отдалечено с него, както за заявка за „show pool_nodes“, така и за регистриране на стъпки и за изпълнение на команди.
  • Изпращам малко информация за dbg към /tmp/d през ssh, защото командата ще бъде изпълнена от страна на главната, която ще се промени след неуспешно преминаване.
  • Мога да използвам резултата от „show pool_nodes“, за да получа информацията за текущата основна връзка, просто филтриране с клауза WHERE
  • Ще имам нужда от двойни кавички в аргумент за pg_rewind, който ще трябва да работи през ssh, така че просто разделям командата за четливост, след това я повтарям и изпълнявам
  • Подготовка recovery.conf въз основа на изхода от “show pool_nodes” (при писането му се питам – защо не използвах вместо това IP и порт на pgpool?..
  • Стартиране на нов подчинен при отказ (знам, че трябва да използвам 2-ра стъпка – просто пропуснах, за да избегнем повторното получаване на всички IP адреси и портове)

Сега какво остава - опитвам се да използвам тази бъркотия в 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)

Проверка на /tmp/d на 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

Сега очевидно искаме да го превъртим отново, за да видим дали работи на някой хост:

[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)

Дневникът изглежда подобно - само IP и портовете са променени:

 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

В тази пясъчна среда главният се премести на 5401 при отказ и след като живее там известно време се премести обратно към 5400. Използването на pg_rewind трябва да го направи възможно най-бързо. Преди това страшната част от автоматичното превключване на отказ беше - ако наистина сте объркали конфигурацията и не сте предвидили някаква форсмажорна сила, бихте могли да се сблъскате с автоматично превключване към следващия подчинен и следващия и следващия, докато не остане свободен подчинен. И след това просто се оказвате с няколко раздвоени майстори и без резервно превключване при отказ. Лоша утеха в такъв сценарий е да имате още повече подчинени на отказ, но без pg_rewind не бихте имали дори това. „Традиционният“ rsync или pg_basebackup копират ВСИЧКИ $PGDATA, за да създадете режим на готовност, и не могат да използват повторно „не твърде различни“ бивши главни.

В заключение на този експеримент бих искал още веднъж да подчертая - това не е решение, подходящо за сляпо копиране. Използването на pg_rewind не се насърчава за pg_pool. Изобщо не е използваем банкомат. Исках да добавя малко свеж въздух към конфигурацията на pgpool HA, за да могат nubes като мен да наблюдават малко по-отблизо как работи. Корифеят да се усмихне на наивистичния подход и може би да го види с нашите - nubes очи.


  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Мигриране от MSSQL към PostgreSQL – какво трябва да знаете

  2. „O“ в ORDBMS:Наследяване от PostgreSQL

  3. Размер на таблицата на дяловете в PostgreSQL 9.0

  4. Как да получите номер на ред в PostgreSQL

  5. Връзката е отказана (PGError) (postgresql и rails)