PostgreSQL е страхотен проект и се развива с невероятна скорост. Ще се съсредоточим върху развитието на възможностите за отказоустойчивост в PostgreSQL във всичките му версии с поредица от публикации в блога. Това е четвъртата публикация от поредицата и ще говорим за синхронния комит и неговото въздействие върху отказоустойчивостта и надеждността на PostgreSQL.
Ако искате да наблюдавате напредъка на еволюцията от самото начало, моля, проверете първите три публикации в блога от поредицата по-долу. Всяка публикация е независима, така че всъщност не е нужно да четете една, за да разберете друга.
- Еволюция на отказоустойчивостта в PostgreSQL
- Еволюция на отказоустойчивостта в PostgreSQL:Фаза на репликация
- Еволюция на отказоустойчивостта в PostgreSQL:Пътуване във времето
Синхронно записване
По подразбиране PostgreSQL прилага асинхронна репликация, при която данните се предават поточно, когато е удобно за сървъра. Това може да означава загуба на данни в случай на отказ. Възможно е да поискате от Postgres да изисква един (или повече) режим на готовност, за да потвърди репликацията на данните преди извършване, това се нарича синхронна репликация (синхронно записване ) .
При синхронна репликация забавянето на репликацията директно влияе върху изминалото време на транзакциите на главния. При асинхронна репликация главният може да продължи с пълна скорост.
Синхронната репликация гарантира, че данните се записват в поне два възела преди потребителят или приложението да бъде казано, че транзакцията е извършена.
Потребителят може да избере режима на извършване на всяка транзакция , така че е възможно едновременно да се изпълняват както синхронни, така и асинхронни транзакции за извършване.
Това позволява гъвкави компромиси между производителност и сигурност в трайността на транзакциите.
Конфигуриране на синхронно записване
За да настроим синхронна репликация в Postgres, трябва да конфигурираме synchronous_commit
параметър в postgresql.conf.
Параметърът указва дали транзакция commit ще изчака WAL записите да бъдат записани на диска, преди командата да върне успешно индикация към клиента. Валидни стойности са включени , remote_apply , отдалечено_запис , локален и изключено . Ще обсъдим как работят нещата по отношение на синхронната репликация, когато настроим synchronous_commit
параметър с всяка от дефинираните стойности.
Нека започнем с документацията на Postgres (9.6):
Тук разбираме концепцията за синхронен комит, както описахме в уводната част на публикацията, вие сте свободни да настроите синхронна репликация, но ако не го направите, винаги има риск от загуба на данни. Но без риск от създаване на несъответствие в базата данни, за разлика от изключването на fsync off
– обаче това е тема за друг пост. И накрая, стигаме до заключението, че ако трябва да не губим никакви данни между закъсненията на репликацията и искаме да сме сигурни, че данните са записани в поне два възела, преди потребителят/приложението да бъде информирано, че транзакцията е извършила , трябва да приемем загубата на някаква производителност.
Нека видим как работят различните настройки за различно ниво на синхронизация. Преди да започнем, нека поговорим как се обработва комитът от PostgreSQL репликация. Клиентът изпълнява заявки на главния възел, промените се записват в регистър на транзакциите (WAL) и се копират по мрежата в WAL на възела в режим на готовност. След това процесът на възстановяване на възела в режим на готовност чете промените от WAL и ги прилага към файловете с данни точно както по време на възстановяване при срив. Ако режимът на готовност е вгорещ режим в режим, клиентите могат да издават заявки само за четене на възела, докато това се случва. За повече подробности относно това как работи репликацията, можете да разгледате публикацията в блога за репликация в тази серия.
Фиг.1 Как работи репликацията
synchronous_commit =изключено
Когато зададем sychronous_commit = off,
COMMIT
не чака записът на транзакцията да бъде изхвърлен на диска. Това е подчертано на Фиг.2 по-долу.
Фиг.2 synchronous_commit =off
synchronous_commit =local
Когато зададем synchronous_commit = local,
COMMIT
изчаква, докато записът на транзакцията се изчисти на локалния диск. Това е подчертано на Фиг.3 по-долу.
Фиг.3 synchronous_commit =local
synchronous_commit =включено (по подразбиране)
Когато зададем synchronous_commit = on,
COMMIT
ще изчака, докато сървърът(ите), посочени от synchronous_standby_names
потвърдете, че записът на транзакцията е безопасно записан на диска. Това е подчертано на Фиг.4 по-долу.
Забележка: Когато synchronous_standby_names
е празен, тази настройка се държи по същия начин като synchronous_commit = local
.
Фиг.4 synchronous_commit =on
synchronous_commit =remote_write
Когато зададем synchronous_commit = remote_write,
COMMIT
ще изчака, докато сървърът(ите), посочени от synchronous_standby_names
потвърдете записа на записа на транзакцията в операционната система, но не е непременно достигнал до диска. Това е подчертано на фиг.5 по-долу.
Фиг.5 synchronous_commit =remote_write
synchronous_commit =remote_apply
Когато зададем synchronous_commit = remote_apply,
COMMIT
ще изчака, докато сървърът(ите), посочени от synchronous_standby_names
потвърдете, че записът на транзакцията е приложен към базата данни. Това е подчертано на Фиг.6 по-долу.
Фиг.6 synchronous_commit =remote_apply
Сега нека разгледаме sychronous_standby_names
параметър в подробности, който е посочен по-горе при настройка на synchronous_commit
като on
, remote_apply
или remote_write
.
synchronous_standby_names =‘име на готовност [, …]’
Синхронният комит ще изчака отговор от един от режимите на готовност, изброени в реда на приоритета. Това означава, че ако първият режим на готовност е свързан и стрийминг, синхронният комит винаги ще чака отговор от него, дори ако вторият режим на готовност вече е отговорил. Специалната стойност на *
може да се използва като stanby_name
което ще съответства на всеки свързан режим на готовност.
synchronous_standby_names =‘брой (име на готовност [, …])’
Синхронният комит ще изчака отговор от поне num
брой режими на готовност, изброени по приоритет. Прилагат се същите правила като по-горе. Така че, например настройка на synchronous_standby_names = '2 (*)'
ще накара синхронния комит да изчака отговор от всеки 2 резервни сървъра.
synchronous_standby_names е празен
Ако този параметър е празен, както е показано, той променя поведението на настройката synchronous_commit
до on
, remote_write
или remote_apply
да се държи същото като local
(т.е. COMMIT
ще изчака само прочистване на локален диск).
Заключение
В тази публикация в блога обсъдихме синхронната репликация и описахме различни нива на защита, които са налични в Postgres. Ще продължим с логическата репликация в следващата публикация в блога.
Препратки
Специални благодарности на моя колега Petr Jelinek, че ми даде идеята за илюстрации.
Документация на PostgreSQL
Готварска книга за администриране на PostgreSQL 9 – второ издание