Узгодженість read-after-write у кластері Galera
Кластер Galera або Percona XtraDB сертифікує запис при коміті і застосовує його на інших вузлах миттю пізніше, а читання, спрямоване в цей проміжок, бачить минуле.
У цій статті 6 розділів
- У кластері на основі сертифікації коміт означає, що запис сертифіковано на кожному вузлі, а не те, що кожен вузол його застосував. Застосування відбувається миттю пізніше, зазвичай від десятків до кількох сотень мілісекунд.
- Читання, збалансоване на вузол, який ще не застосував запис, повертає старий рядок. У CMS це читається як втрачена правка: редактор зберігає, оновлює сторінку, бачить старий текст і зберігає знову поверх новішої версії. Жодної помилки ніде не виникає.
- wsrep_sync_wait закриває цей проміжок, змушуючи читання чекати, доки його вузол наздожене. Це коштує затримки застосування на читаннях, що йдуть за записом, тому його обмежують сесіями, яким він потрібен, і не вмикають для сторінок, які віддає edge-кеш.
Коміт означає сертифіковано, а не застосовано
Кластер Galera виконує транзакцію на одному вузлі. При коміті цей вузол розсилає write set кластеру, кожен вузол сертифікує його відносно write set, які вже в польоті, і коміт повертається клієнту. З цієї миті запис є довговічним у кластері і однаково впорядкованим усюди.
Чого ще не сталося, так це застосування. Кожен вузол бере сертифікований write set і застосовує його до власної копії даних у власних applier threads, трохи після того, як коміт повернувся. Працюють два годинники: сертифікація є загальнокластерною і частиною коміту, застосування є локальним і йде після. У здоровому кластері відстань між ними становить від десятків до кількох сотень мілісекунд. Вона зростає під час сплесків запису, великих транзакцій і змін схеми, і її видно як ненульовий wsrep_local_recv_queue на вузлі, що відстає.
Куди йде читання
Кластер з балансуванням читань надсилає читання туди, куди вирішить proxy. Один запит пише на вузлі A. Наступний запит того самого користувача, кілька сотень мілісекунд пізніше, читає на вузлі B. Якщо вузол B отримав, але ще не застосував write set, він відповідає рядком таким, яким той був до запису. З погляду вузла B відповідь правильна: це його закомічений стан. Нічого не логується, ніщо не тривожить, і монітор затримки мовчить, бо його побудовано ловити тривалу затримку, а не перші сто мілісекунд після однієї транзакції.
Ось чому симптом виглядає випадковим. Він залежить від того, який вузол обрав балансувальник, як швидко повернувся користувач і наскільки зайнятими були appliers у ту мить.
Як це виглядає в застосунку
Шаблон такий: запис, за яким одразу йде читання від того самого користувача, що потрапляє на інший вузол. У CMS це зниклий абзац: зберегти, оновити, старий текст, передрукувати, зберегти, і друге збереження перезаписує перше. У магазині це замовлення, якого не існує на сторінці підтвердження. У процесі автентифікації це токен, який щойно видали і не знайшли.
Два інші механізми дають схожу історію, і їх варто виключити першими. Back-forward cache браузера може відновити застарілу копію форми, і повторне збереження запише цю застарілу копію. Плагін може робити read-modify-write на тому самому рядку з двох запитів. Обидва реальні, і жоден не є кластером. Цикл, який пише мітку часу на одному вузлі і читає її з інших, розділяє їх за хвилину.
Налаштування: wsrep_sync_wait
wsrep_sync_wait є бітовою маскою. З установленим бітом 1 SELECT чекає, доки вузол застосує кожен write set, отриманий до цієї миті, перш ніж виконатися. Читанню тоді гарантовано побачити все, що було закомічено будь-де в кластері до його початку. Його можна встановити для однієї сесії, що є правильним обсягом для редактора або шляху оформлення замовлення, або глобально, коли все навантаження чутливе до read-after-write.
-- for one session: the request path that writes and then reads
SET SESSION wsrep_sync_wait = 1;
-- for the whole node: my.cnf, under [mysqld]
wsrep_sync_wait = 1Альтернативою є маршрутизація: надсилати читання, що йдуть за записом, на вузол, який писав, правилами запитів proxy або в застосунку. Це працює для шляхів, які воно покриває. Один шлях у коді, який ніхто не змаршрутизував, знову відкриває проміжок, і тому налаштування є кращим там, де ціну можна заплатити: воно адресує механізм, а не один шлях через нього.
Чого це коштує і де за це платити
Читання під wsrep_sync_wait чекає, доки локальний applier наздожене, тому воно платить затримку застосування один раз на кожне читання, що йде за записом. У здоровому кластері це від десятків до кількох сотень мілісекунд. Сесії авторизованих користувачів, шляхи адміністраторів і редакторів та оформлення замовлення є тими місцями, де ця ціна щось купує. Анонімні сторінки, які віддаються з edge-кешу, при влучанні не торкаються бази даних і не зачіпаються. Налаштування набирає чинності з наступного оператора і так само скасовується, тож його можна виміряти на місці зі справжнім навантаженням, а не оцінювати.
Як перевірити власний кластер
Три показники все вирішують. Чи читання взагалі чекають; наскільки відстає вузол під час сплеску запису; і як часто міжвузлове read-after-write насправді бачить минуле, з циклу, який пише на одному вузлі і читає з інших.
SHOW GLOBAL VARIABLES LIKE 'wsrep_sync_wait'; -- 0 means reads do not wait
SHOW GLOBAL STATUS LIKE 'wsrep_local_recv_queue'; -- received, not yet appliedМи експлуатуємо кластери Percona XtraDB з балансуванням читань за ProxySQL і HAProxy і можемо відповісти на ці три запитання для будь-якого кластера, яким керуємо, включно з тим, чого коштує це налаштування на тому конкретному навантаженні.
Прямі відповіді
Чи є реплікація Galera синхронною?+
Сертифікація так: запис сертифікується на кожному вузлі, перш ніж коміт повернеться. Застосування на кожному вузлі відбувається миттю пізніше. Обидві половини мають значення, і саме в другій живуть проблеми read-after-write.
Чому моя CMS втрачає правки в кластері?+
Читання після збереження спрямували на вузол, який отримав write set, але ще не застосував його. Редактор побачив старий вміст, передрукував його і зберіг поверх новішої версії. Жодної помилки не виникає, тому це виглядає нерегулярним.
Чи допомагає очищення кешу?+
Зазвичай ні. Кеш зберіг те, що повернула база даних, а на мить база даних повернула минуле. Діагностуйте шлях читання. Кеш тут є носієм симптому, а не причиною.
Чого коштує wsrep_sync_wait?+
Затримки застосування, яку платять читання, що йдуть за записом, зазвичай від десятків до кількох сотень мілісекунд у здоровому кластері. Сторінки, що віддаються з edge-кешу, не зачіпаються. Обмежте його сесією, щоб платити лише там, де це має значення.
Експлуатуєте кластер з балансуванням читань?
Поговоріть з інженером про те, чи ввімкнено read-after-write і чого це коштує на вашому.
Поговоріть з інженером (shell cta.talkToEngineer)Ви дійшли до кінця.
Застосуйте прочитане на практиці
Що ви запускаєте?
Розкажіть нам про навантаження, трафік і вимоги до відновлення. Почніть з конструктора сервера або обговоріть деталі з інженером.
Написано інженерами, які будують і експлуатують інфраструктуру, про яку йдеться.Поговоріть з інженером
