PostgreSQL та налаштування узгодженості запису для кожного конкретного з'єднання

Переклад статті підготовлений спеціально для студентів курсу "Бази даних". Цікаво розвиватись у цьому напрямі? Запрошуємо вас на День відкритих дверей, де ми докладно розповідаємо про програму, особливості онлайн-формату, компетенції та кар'єрні перспективи, які чекають випускників після навчання.

PostgreSQL та налаштування узгодженості запису для кожного конкретного з'єднання

PostgreSQL та налаштування узгодженості запису для кожного конкретного з'єднання
Нам у Compose доводиться мати справу з багатьма базами даних, саме це дає нам можливість познайомитися ближче з їхнім функціоналом та недоліками. У міру того, як ми вчимося любити функціональні особливості нових баз даних, ми іноді починаємо думати про те, як було б добре, якби подібні функції були присутні і в більш зрілих інструментах, з якими ми працюємо вже давно. Одна з нових особливостей, яку хотілося бачити в PostgreSQL, була узгодженість запису під з'єднання в усьому кластері. І як виявилося, вона у нас вже є, і сьогодні ми хочемо поділитися з вами інформацією про те, як ви можете її використати.

Навіщо мені це?

Те, як повинен поводитися кластер залежить від вашої програми. Візьмемо, наприклад, додаток на оплату рахунків. Вам знадобиться стовідсоткова узгодженість у кластері, тому вам доведеться включити синхронні коміти, щоб ваша база даних чекала, доки будуть внесені всі зміни. Однак, якщо ваша програма - це соціальна мережа, що швидко розвивається, то ви напевно віддасте перевагу стовідсотковій узгодженості швидкий відгук. Щоб цього досягти, ви можете використовувати у вашому кластері асинхронні комміти.

Знайомтесь, компроміс

Вам доведеться піти на компроміс між узгодженістю даних та продуктивністю. PostgreSQL крокує від узгодженості, оскільки конфігурація за умовчанням у такому разі виходить передбачуваною і без несподіваних сюрпризів. А тепер знайомитимемося з компромісами.

Компроміс 1: Продуктивність

Якщо кластеру PostgreSQL не потрібна узгодженість, він може працювати асинхронно. Запис проводиться на лідера кластера, а його реплікам через кілька мілісекунд буде відправлено оновлення. Коли кластеру PostgreSQL потрібна узгодженість, він має працювати синхронно. Запис буде зроблено в лідері кластера, який відправить реплікам оновлення і дочекається підтвердження, що кожен зробив запис, перед тим як надіслати підтвердження клієнту, який ініціював запис, про те, що він пройшов успішно. Практична різниця між цими підходами полягає в тому, що асинхронний метод вимагає два стрибки по мережі, а синхронний – чотири.

Компроміс 2: Узгодженість

Результат у разі збою у роботі лідера у цих двох підходах теж буде різним. Якщо робота виконується асинхронно, то при виникненні такої помилки не всі записи будуть зафіксовані репліками. Скільки буде втрачено? Залежить від самого застосування та ефективності реплікації. Реплікація Compose завадить репліці стати лідером у разі, якщо кількість інформації в ній на 1 Мб менша, ніж у лідері, тобто потенційно може бути втрачено до 1 Мб записів при асинхронній роботі.

У синхронному режимі цього немає. Якщо лідер відмовляє, всі репліки оновлюються, оскільки будь-який запис, підтверджений на лідері, має бути підтверджений у репліках. Ось вона – узгодженість.

Синхронна поведінка має сенс використовувати у додатку для оплати рахунків, де узгодженість має явну перевагу у пошуку компромісу між узгодженістю та продуктивністю. Найголовніше для такої програми – валідні дані. А тепер згадайте про соціальну мережу, в якій основне завдання полягає в тому, щоб утримувати увагу користувача, відповідаючи на запити якнайшвидше. У такому разі продуктивність із меншою кількістю стрибків по мережі та меншим очікуванням коммітів буде у пріоритеті. Однак компроміс між продуктивністю та узгодженістю не єдиний, про який доводиться думати.

Компроміс 3: Збої

Дуже важливо розуміти, як поводиться кластер під час збою. Розглянемо ситуацію, коли одна чи більше реплік відмовляють. Коли комміти обробляються асинхронно, лідер продовжуватиме функціонувати, тобто приймати і обробляти записи, не чекаючи відсутніх реплік. Коли репліки повертаються до кластера, вони наздоганяють лідера. При синхронній реплікації, якщо репліки не відповідають, то лідер не матиме вибору і він продовжуватиме очікувати підтвердження комміту, поки репліка не повернеться до кластера і не зможе прийняти і підтвердити запис.

По одному з'єднанню на транзакцію?

Кожному додатку потрібен особливий тип поєднання узгодженості та продуктивності. Якщо воно звичайно ж не є нашим додатком для оплати рахунків, який ми уявляємо повністю узгодженим, або нашим майже ефемерним додатком для соціальної мережі. В інших випадках будуть моменти, коли деякі операції повинні бути синхронними, а деякі - асинхронними. Ви можете не хотіти, щоб система чекала, поки повідомлення, відправлене в чат, буде закоммічено, але якщо в цьому ж додатку відбувається платіж, то чекати доведеться.

Всі ці рішення, звичайно ж, приймає розробник програми. Правильні рішення про те, коли застосовувати той чи інший підхід допоможуть вичавити максимум із кластера. Важливо, щоб розробник міг перемикатися між ними на рівні SQL для підключень та транзакцій.

Забезпечення контролю на практиці

За промовчанням PostgreSQL забезпечує узгодженість. Це контролюється параметром сервера synchronous_commit. За умовчанням він у положенні on, Але в нього є три інші варіанти: local, remote_write або off.

При установці параметра в off зупиняються всі синхронні комміти, навіть у локальній системі. Параметр local local визначає синхронний режим для локальної системи, але записи в репліки виконуються асинхронно. Remote_write заходить ще далі: записи в репліки виробляються асинхронно, але повертаються, коли репліка прийняла запис, але записала її на диск.

Розглядаючи наявний діапазон опцій, ми вибираємо поведінку і, пам'ятаючи, що on - Це синхронні записи, ми оберемо local для асинхронних комітів через мережу, при цьому залишивши локальні коміти синхронними.

Тепер ми розповімо вам, як налаштувати це в одну мить, але уявіть, що ми встановили synchronous_commit в local для сервера. Ми запитали, чи можна змінювати параметр synchronous_commit на льоту, і виявилося, що не просто можна, для цього навіть є два способи. Перший – це задати сесію вашого з'єднання так:

SET SESSION synchronous_commit TO ON;  
// Your writes go here

Усі наступні записи у сесії підтверджуватимуть операції запису для реплік, перш ніж повертати позитивний результат підключеному клієнту. Якщо, звичайно, ви не зміните налаштування synchronous_commit знову. Можна опустити частину SESSION в команді, оскільки вона буде за замовчуванням.

Другий спосіб хороший, коли ви просто хочете переконатись, що отримуєте синхронну реплікацію для однієї транзакції. У багатьох базах даних покоління «NoSQL» поняття транзакцій немає, але існує в PostgreSQL. У цьому випадку ви запускаєте транзакцію, а потім встановлюєте synchronous_commit в on перед виконанням запису для транзакції. COMMIT зафіксує транзакцію, використовуючи будь-яке значення параметра synchronous_commit, яка була встановлена ​​в той момент, хоча найкраще задавати змінну заздалегідь, щоб переконатися, що інші розробники розуміють, що записи не є асинхронними.

BEGIN;  
SET LOCAL synchronous_commit TO ON;  
// Your writes go here
COMMIT;  

Усі коміти транзакцій тепер будуть підтверджуватись, як записані у репліки ще до того, як база даних поверне позитивну відповідь підключеному клієнту.

Налаштування PostgreSQL

До цього ми уявляли собі систему PostgreSQL з synchronous_commit, встановленим у local. Щоб це було реально на стороні сервера, вам потрібно буде встановити два параметри конфігурації сервера. Ще один параметр synchronous_standby_names буде вступати у свої права, коли synchronous_commit буде в on. Він визначає які репліки мають право на синхронні коміти, і ми встановимо його в *, що означатиме задіяння всіх реплік. Ці значення зазвичай налаштовуються в файл конфігурації шляхом додавання:

synchronous_commit = local  
synchronous_standby_names='*'

Встановивши параметр synchronous_commit на значення local, ми створюємо систему, в якій локальні диски залишаються синхронними, але коміти мережних реплік за промовчанням є асинхронними. Якщо, звичайно, ми не вирішимо зробити ці комміти синхронними, як показано вище.

Якщо ви стежили за розвитком проекту Governor, ви могли помітити деякі останні зміни (1, 2), які дозволили користувачам Governor тестувати ці параметри та контролювати їхню узгодженість.

Ще кілька слів…

Буквально тиждень тому, я вам сказав би, що неможливо настільки тонко налаштувати PostgreSQL. Саме тоді Курт, член команди платформи Compose, наполягав, що така можливість є. Він утихомирив мої заперечення і знайшов у документації PostgreSQL наступне:

PostgreSQL та налаштування узгодженості запису для кожного конкретного з'єднання

Цей параметр можна змінити у будь-який час. Поведінка для будь-якої транзакції визначається налаштуванням, що діє під час коміту. Тому можливо і корисно, щоб для деяких транзакцій коміти відбувалися синхронно, а для інших – асинхронно. Наприклад, щоб змусити одну multistatement транзакцію робити комміти асинхронно, коли значення параметра за промовчанням протилежне, задайте SET LOCAL synchronous_commit TO OFF у транзакції.

За допомогою такої невеликої модифікації у файлі конфігурації ми дали користувачам можливість контролювати їхню узгодженість та продуктивність.

Джерело: habr.com

Додати коментар або відгук