В този запис в блога ще говорим за логическа репликация в PostgreSQL:случаи на употреба, обща информация за състоянието на тази технология и специален случай на употреба, по-специално за това как да настроите абонат (реплика) възел на основния сървър, за да да функционира като сървър на база данни за тестовата среда и да отговори на предизвикателствата.
Въведение
Логическата репликация, официално въведена в PostgreSQL 10, е най-новата технология за репликация, предлагана от общността на PostgreSQL. Логическата репликация е продължение на наследството на физическата репликация, с която споделя много идеи и код. Логическата репликация работи като физическа репликация, използвайки WAL за записване на логически промени, независимо от версията или конкретната архитектура. За да може да осигури логическа репликация на основното предложение, общността на PostgreSQL е извървяла дълъг път.
Типове репликация и история на репликация на PostgreSQL
Типовете репликация в базите данни могат да бъдат класифицирани по следния начин:
- Физическа (известна още като двоична) репликация
- Ниво на операционна система (vSphere репликация)
- Ниво на файловата система (DRBD)
- Ниво на база данни (базирано на WAL)
- Логическа репликация (ниво на база данни)
- Въз основа на задействане (DBMirror, Slony)
- Межен софтуер (pgpool)
- базирано на WAL (pglogical, логическа репликация)
Пътната карта, която води до днешната логическа репликация, базирана на WAL, беше:
- 2001:DBMirror (базирано на тригер)
- 2004:Slony1 (базирано на тригери), pgpool (междууер)
- 2005:PITR (базиран на WAL) въведен в PostgreSQL 8.0
- 2006:Топъл режим на готовност в PostgreSQL 8.2
- 2010:Репликация на физическо поточно предаване, горещ режим на готовност в PostgreSQL 9.0
- 2011:Синхронно поточно репликация в PostgreSQL 9.1
- 2012:Каскадно стрийминг репликация в PostgreSQL 9.2
- 2013:Фонови работници в PostgreSQL 9.3
- 2014:API за логическо декодиране, слотове за репликация. (Основи за логическа репликация) в PostgreSQL 9.4
- 2015:2ndQuadrant представя pglogical, предшественика или логическа репликация
- 2017:Логическа репликация в ядрото на PostgreSQL 10!
Както можем да видим, много технологии си сътрудничат, за да направят логическата репликация реалност:WAL архивиране, топъл/горещ режим на готовност, физическа репликация на WAL, фонови работници, логическо декодиране. Ако приемем, че читателят е запознат с повечето понятия за физическа репликация, ще говорим за основните компоненти на логическата репликация.
Основни понятия за логическа репликация на PostgreSQL
Някои термини:
- Публикация: Набор от промени от набор от таблици, дефинирани в конкретна база данни на първичен сървър за физическа репликация. Публикация може да обработва всички или някои от:INSERT, DELETE, UPDATE, TRUNCATE.
- Възел на издателя: Сървърът, където се намира публикацията.
- Реплика на идентичност: Начин за идентифициране на реда от страната на абоната за АКТУАЛИЗИРАНЕ и ИЗТРИВАНЕ.
- Абонамент: Връзка към възел на издател и една или повече публикации в него. Абонаментът използва специален слот за репликация на издателя за репликация. Допълнителни слотове за репликация могат да се използват за първоначалната стъпка на синхронизиране.
- Абонатен възел: Сървърът, където се намира абонаментът.
Логическата репликация следва модел за публикуване/абониране. Един или повече абонати могат да се абонират за една или повече публикации на възел на издател. Абонатите могат да публикуват повторно, за да позволят каскадна репликация. Логическата репликация на таблица се състои от два етапа:
- Правете моментна снимка на таблицата на издателя и я копирате на абоната
- Прилагане на всички промени (след моментната снимка) в една и съща последователност
Логическата репликация е транзакционна и гарантира, че редът на промените, прилагани към абоната, остава същият като при издателя. Логическата репликация дава много повече свобода от физическата (двоична) репликация, следователно може да се използва по повече начини:
- Единична база данни или специфична репликация на таблица (няма нужда от репликиране на целия клъстер)
- Задаване на задействания към абоната за конкретна задача (като анонимизиране, което е доста гореща тема след влизането в сила на GDPR)
- Наличието на абонатен възел да събира данни от много възли на издатели, като по този начин позволява централна аналитична обработка
- Репликация между различни версии/архитектури/платформи (нулеви надстройки при престой)
- Използване на абонатния възел като сървър на база данни за среда за тестване/разработка. Защо искаме това, е защото тестването срещу реални данни е най-реалистичният вид тестове.
Предупреждения и ограничения
Има някои неща, които трябва да имаме предвид, когато използваме логическа репликация, някои от тях може да повлияят на някои дизайнерски решения, но други могат да доведат до критични инциденти.
Ограничения
- Поддържат се само DML операции. Без DDL. Схемата трябва да бъде дефинирана предварително
- Последователностите не се репликират
- Големите обекти не се репликират
- Поддържат се само обикновени базови таблици (материализирани изгледи, основни таблици на дялове, чужди таблици не се поддържат)
Предупреждения
Основният проблем, с който рано или късно ще трябва да се сблъскаме, когато използваме логическа репликация, са конфликтите на абоната. Абонатът е нормален сървър за четене/запис, който може да действа като основен при настройка на физическа репликация или дори като издател в настройка на каскадна логическа репликация. Докато записите в абонираните таблици се извършват, може да има конфликти . Конфликт възниква, когато репликираните данни нарушават ограничение върху таблицата, към която са приложени. Обикновено операцията, която причинява това, е INSERT, DELETES или UPDATES, които нямат ефект поради липсващи редове, няма да предизвика конфликт. Когато възникне конфликт, репликацията спира. Логическият фонов работник ще бъде рестартиран в посочения интервал (wal_retrieve_retry_interval), но репликацията ще се провали отново, докато не бъде разрешена причината за конфликта. Това е критично състояние, което трябва да се лекува незабавно. В противен случай слотът за репликация ще остане блокиран в текущата си позиция възелът на издателя ще започне да натрупва WAL и неизбежно възелът на издателя ще свърши дисково пространство . Конфликтът е най-честата причина, поради която репликацията може да спре, но всяко друго грешно състояние ще има същия ефект:напр. добавихме нова колона NOT NULL към таблица с абонамент, но забравихме да дефинираме стойност по подразбиране, или добавихме колона в публикувана таблица, но забравихме да я дефинираме в таблицата за абонамент, или направихме грешка в нейния тип и двата типа не са съвместими. Всички тези грешки ще спрат репликацията. Има два начина за разрешаване на конфликт:
- Решете действителния проблем
- Пропуснете неуспешната транзакция, като извикате pg_replication_origin_advance
Решение b. както също е показано тук, може да бъде опасно и сложно, тъй като основно е процес на проба и грешка и ако някой избере текущия LSN на издателя, той/тя може лесно да се окаже с повредена система за репликация, тъй като може да има операции между проблемния LSN и текущия LSN, който бихме искали да запазим. Така че най-добрият начин е действително да решите проблема от страна на абоната. напр. ако възникне нарушение на УНИКАЛЕН КЛЮЧ, тогава може да актуализираме данните за абоната или просто да изтрием реда. В производствена среда всичко това трябва да бъде автоматизирано или поне полуавтоматизирано.
Настройване на възли на издател и абонат
За общ преглед на логическата репликация на практика, моля, прочетете този блог.
Съответните параметри за логическа репликация са:
- Страна на издателя
- wal_level>=„логически“
- max_replication_slots>=#subscriptions + първоначално синхронизиране на таблица
- max_wal_senders>=max_replication_slots + other_physical_standbys
- Страна на абоната
- max_replication_slots>=#subscriptions
- max_logical_replication_workers>=#subscriptions + първоначално синхронизиране на таблица
- max_worker_processes>=max_logical_replication_workers + 1 + max_parallel_workers
Ще се съсредоточим върху специалните съображения, които произтичат от нашата специална цел, която ни е необходима логическа репликация, за да постигнем:създайте клъстер на тестова база данни за използване от отдела за тестване . Публикацията може да бъде дефинирана или за всички таблици, или таблица по таблица. Предлагам подхода таблица по таблица, тъй като ни дава максимална гъвкавост. Общите стъпки могат да бъдат обобщени по следния начин:
- Извършете нов initdb на абонатния възел
- Изхвърлете схемата на издателския клъстер и копирайте в абонатния възел
- Създайте схемата на абоната
- Решете кои таблици ви трябват и кои не са ви необходими.
Що се отнася до горния куршум, има две причини, поради които може да не се нуждаете от таблица за репликиране или настройка за репликация:
- Това е фиктивна таблица без значение (и може би трябва да я изхвърлите и от производството)
- е локална таблица за производствената среда, което означава, че е напълно логично същата таблица в тестовата (абонатна) среда да има свои собствени данни.
Всички таблици, участващи в логическата репликация, трябва да имат РЕПЛИКА ИДЕНТИЧНОСТ. Това по подразбиране е ПЪРВИЧНИЯ КЛЮЧ и ако не е наличен, може да се дефинира УНИКАЛЕН ключ. Следваща стъпка за намиране на състоянието на таблиците по отношение на REPLICA IDENTITY.
- Намерете таблиците без очевиден кандидат за REPLICA IDENTITY
select table_schema||'.'||table_name from information_schema.tables where table_type='BASE TABLE' AND table_schema||'.'||table_name NOT IN (select table_schema||'.'||table_name from information_schema.table_constraints WHERE constraint_type in ('PRIMARY KEY','UNIQUE')) AND table_schema NOT IN ('information_schema','pg_catalog') ;
- Намерете таблиците без ПЪРВИЧЕН КЛЮЧ, но с УНИКАЛЕН ИНДЕКС
select table_schema||'.'||table_name from information_schema.table_constraints WHERE constraint_type = 'UNIQUE' EXCEPT select table_schema||'.'||table_name from information_schema.table_constraints WHERE constraint_type = 'PRIMARY KEY';
- Прегледайте горните списъци и решете какво да правите с всяка таблица
- Създайте публикацията с таблиците, за които съществува PK
select 'CREATE PUBLICATION data_for_testdb_pub FOR TABLE ONLY ' || string_agg(qry.tblname,', ONLY ') FROM (select table_schema||'.'||quote_ident(table_name) as tblname from information_schema.tables where table_type='BASE TABLE' AND table_schema||'.'||table_name IN (select table_schema||'.'||table_name from information_schema.table_constraints WHERE constraint_type in ('PRIMARY KEY')) AND table_schema NOT IN( 'information_schema','pg_catalog') ORDER BY 1) as qry; \gexec
- След това създайте абонамента на абонатния възел
Горното също ще копира данните.create subscription data_for_testdb_pub CONNECTION 'dbname=yourdb host=yourdbhost user=repmgr' PUBLICATION data_for_testdb_pub ;
- Добавете желаните от вас таблици, които имат УНИКАЛЕН индекс
Изпълнете както в възли на издател, така и в абонатни възли, напр.:
На издателя:ALTER TABLE someschema.yourtable REPLICA IDENTITY USING INDEX yourindex_ukey;
На абоната:ALTER PUBLICATION data_for_testdb_pub ADD TABLE ONLY someschema.yourtable;
ALTER SUBSCRIPTION data_for_testdb_pub REFRESH PUBLICATION WITH ( COPY_DATA );
- В този момент (синхронизация) винаги трябва да имате под око дневника на PostgreSQL на абонатния възел. Не искате никакви грешки или нещо (таймаут), което забранява продължаването на логическата репликация. РЕШЕТЕ НЕЗАБАВНА ГРЕШКА , или издателят ще продължи да натрупва WAL файлове в pg_wal и в крайна сметка ще остане без място. Така че трябва да се справите с
- Всички ГРЕШКИ или всяко съобщение относно логическия работник, което води до излизане
- Погрижете се и за
- wal_receiver_timeout
- wal_sender_timeout
След като решите всички проблеми, вашият абонатен възел трябва да работи щастливо. Така че следващият въпрос е как да го използваме като тестов сървър на база данни. Ще трябва да се справите с тези проблеми/проблеми:
- Анонимизиране
- Първични ключове и уникални ключове, които се основават на нарушения на последователности
- Общ набор от добри практики
- Мониторинг
Анонимизиране
По отношение на анонимизирането на лични данни, което се прилага от GDPR в ЕС, трябва ВИНАГИ да напишете някои тригери, които изпразват всички полета относно адреси, банкови сметки, семейно положение, телефонни номера, имейли и т.н. Трябва да се консултирате с вашия служител по сигурността във вашата компания за какво да запазите и какво да зачеркнете. Тригерите трябва да бъдат дефинирани като ВИНАГИ, тъй като логическият работник изпълнява изразите като REPLICA.
Първични ключове с последователности
Що се отнася до последователностите, очевидно ще има проблем с тези ключове, освен ако не бъдат разгледани преди стартирането на какъвто и да е тест. Помислете за този случай:
- В петък следобед правите някои тестове на базата данни на абонатите, като вмъквате нов ред в някаква таблица. Това ще има като идентификатор следващата стойност, генерирана от последователността.
- Прибирате се у дома за уикенда.
- Някой производствен потребител въвежда ред в същата таблица в базата данни на издателя.
- Редът ще бъде репликиран въз основа на РЕПЛИКАТА ИДЕНТИФИКАЦИЯ към абонатния възел, но няма да бъде успешен поради ГРЕШКА при нарушение на PK. Логическият фонов работник ще излезе и ще опита отново. Но ще продължи да се проваля, докато проблемът продължава.
- Репликацията ще блокира. Слотът за репликация ще започне да натрупва WAL.
- На издателя свършва дисково пространство.
- През уикенда получавате имейл, че вашият първичен възел е в ПАНИКА!
Така че, за да разрешите проблема с последователността, можете да приложите следния подход:
select 'SELECT setval(''' || seqrelid::regclass||''','||CASE WHEN seqincrement <0 THEN -214748364 ELSE 214748364 END||');' from pg_sequence where seqtypid=20;
\gexec
Това, което прави по-горе, е да настроите последователностите на достатъчно голяма стойност, така че никога да не се припокриват за доста голям прозорец в бъдеще, което ви позволява да имате тестов сървър без проблеми.
Набор от добри практики
Наистина трябва да кажете на своите програмисти да направят своите тестове непостоянни. Така че всеки тест, след като завърши, трябва да остави базата данни в същото състояние, както е било преди теста. При вмъкванията на идентификатори, базирани на последователност, това не е проблем, видяхме по-рано решение. Но с не-последователност (например комбинирани) УНИКАЛНИ ключове това може да е проблем. Затова е най-добре да изтриете тези тестови данни, преди някакъв производствен ред със същата стойност да достигне таблицата за абонамент.
Тук трябва да добавим и работа с промени в схемата. Всички промени в схемата трябва да се извършват и на абоната, за да не се прекъсва репликираният DML трафик.
Изтеглете Бялата книга днес Управление и автоматизация на PostgreSQL с ClusterControl Научете какво трябва да знаете, за да внедрите, наблюдавате, управлявате и мащабирате PostgreSQLD Изтеглете Бялата книгаНаблюдение
Наистина трябва да инвестирате в добро решение за наблюдение. Трябва да следите за ...
При абоната:
- ВСИЧКИ съобщения в дневника на абоната, които са свързани с логическия изход на работника. Инсталирането на инструмент като tail_n_mail наистина може да помогне за това. Конфигурация, за която е известно, че работи:
След като получим сигнал, идващ от tail_n_mail, трябва незабавно да разрешим проблема.INCLUDE: ERROR: .*publisher.* INCLUDE: ERROR: .*exited with exit.* INCLUDE: LOG: .*exited with exit.* INCLUDE: FATAL: INCLUDE: PANIC:
- pg_stat_subscription. Pid не трябва да е нула. Също така изоставането трябва да е малко.
При издателя:
- pg_stat_replication. Това трябва да има толкова редове, колкото трябва да бъдат:по един за всяко свързано поточно репликация в готовност (включени са абонатни възли и други физически режими на готовност).
- pg_replication_slots за слота за абонати. Това трябва да е активно.
По принцип отнема известно време, докато идеалният сървър на тестова база данни работи без проблеми, но след като ги решите всички, вашите програмисти ще ви благодарят, че го имате!