Швидкість відновлення — це те місце, де теорія баз даних стикається з неприємною реальністю затримок сховища, конкуренції за CPU і панікою «почекайте, який же це бекап був справжній?». Ваш RTO — це не число в таблиці. Це час від першого виклику в пейджер і до моменту, коли ваш додаток перестає поводитися як злий автомат з продажу.
Якщо вам потрібен RTO менше 15 хвилин, ви не «оптимізуєте відновлення». Ви проєктуєте весь шлях бекап+відновлення як виробничу систему: передбачувану, вимірювану, відрепетирувану і безжально нудну.
Що насправді означає «RTO менше 15 хвилин»
RTO — це час до відновлення сервісу, а не час «закінчити відновлення». Якщо ваш сервіс потребує бази даних, а база даних потребує connection pooling, DNS, секрети і сумісність схеми — усе це входить у зону відповідальності. 9-хвилинне відновлення бази даних може означати 30-хвилинний простої, якщо у вас є:
- 12-хвилинне доження WAL/binlog, бо ви забули, що робите PITR.
- 6-хвилинне прогрівання кешу, бо ваш додаток «заново відкриває» продуктивність з холодного стану.
- 10-хвилинна людська затримка, бо кроки відновлення живуть у чиїйсь голові.
Для RTO менше 15 хвилин, припускайте, що часу на роздуми не буде. Ви маєте виконувати готове дерево рішень, з попередньо виділеною ємністю і точно знати (не сподіватися), що бекап валідний.
Неприємна математика
15 хвилин — це 900 секунд. Якщо ваш фізичний каталог даних — 800 GB, ви не відновите його з об’єктного сховища на швидкості 200 MB/s. Хіба що фізика також у вашому on-call ротації.
Отже, досягти 15 хвилин зазвичай означає одну з цих архітектур:
- Hot standby / промоція репліки (відновлення = промоція + перенаправлення).
- Відкат через snapshot (відновлення зі snapshot ZFS/LVM/EBS і приєднання).
- Фізичне відновлення бекапу на попередньо прогріті вузли (перенесення даних локальне або вже заздалегідь підготовлене).
- Достатньо малий набір даних, щоб повноцінне відновлення вмістилося в вікно (рідкість для дорослих систем).
Логічні дампи для великих систем — це для міграцій і археології. Вони не ваш план на RTO < 15 хв.
Шляхи відновлення: MariaDB vs PostgreSQL (що швидко, а що ні)
Найшвидший відновлення зазвичай — «не відновлювати»
Для обох — MariaDB і PostgreSQL — найшвидше відновлення це промоція репліки, яка вже встигла наздогнати. Якщо ви можете задовольнити RPO асинхронною реплікацією — добре. Якщо ні — платіть за синхронну реплікацію або прийміть більший радіус ураження.
Фізичне vs логічне: розвилка доріг
Логічне відновлення (mysqldump/mariadb-dump, pg_dump) повільне, бо воно повторно виконує SQL, перебудовує індекси і змушує базу даних виконати велику роботу CPU, яка вже колись була зроблена. Часто воно також однопотокове в невдалих місцях.
Фізичне відновлення (MariaDB: Mariabackup; PostgreSQL: pgBackRest, pg_basebackup, відновлення на рівні файлів) швидке, бо ви в основному копіюєте файли й потім робите replay при старті.
Профіль швидкості відновлення MariaDB
- Швидкий шлях: фізичний бекап Mariabackup, підготовлений заздалегідь, copy-back на швидке сховище, потім InnoDB crash recovery / застосування redo при старті.
- Де болить: крок prepare (якщо відкладено), I/O під час copy-back і InnoDB recovery, якщо логи великі або поведінка fsync консервативна.
- PITR: після відновлення базового бекапу застосовують binlog. Це може бути швидко або болісно послідовно залежно від обсягу записів і обмежень однопотокового застосування у вашому середовищі.
Профіль швидкості відновлення PostgreSQL
- Швидкий шлях: відновлення фізичного бекапу (pgBackRest restore або basebackup), запуск інстансу, програвання WAL до консистентного стану або до цільової точки (PITR), промоція.
- Де болить: швидкість програвання WAL (I/O і CPU), пропускна здатність команди restore (отримання WAL-сегментів) та налаштування чекпоінтів/redo.
- PITR: може бути дуже швидким, якщо WAL-архів локальний і паралелізований; може бути жахливим, якщо WAL віддалений і послідовно завантажується або якщо ціль відновлення дуже далека.
Орієнтована порада: якщо вам потрібен RTO менше 15 хвилин — проєктуйте під промоцію або відкат через snapshot. Якщо регуляторні вимоги вимагають «відновлення з бекапу», принаймні використовуйте фізичні бекапи і підготуйте їх на цільовому сховищі заздалегідь.
Факти та історія, що впливають на швидкість відновлення
- WAL у PostgreSQL був центральним ще з 1990-х; безпека при краху і PITR були закладені в архітектуру рано, і відновлення це по суті «перегравати логи до консистентності».
- InnoDB став дефолтним движком MySQL у 5.5, і MariaDB успадкувала цю лінію. Швидкість відновлення значною мірою — «наскільки швидко InnoDB зможе зробити себе консистентним».
- pg_dump навмисно логічний і портативний; він відмінний для міграцій і стрибків версій, і жахливий для жорсткого RTO у великих масштабах.
- Mariabackup — це форк Percona XtraBackup, створений для гарячих фізичних бекапів без зупинки записів. Фаза «prepare» існує, бо потрібно зробити бекап консистентним.
- Реплікаційні слоти PostgreSQL не дозволяють видаляти WAL, поки споживач його потребує; чудово для надійності, але погано, якщо ви забудете про закинутий слот і диск заповниться під час кризи.
- Реплікація MySQL/MariaDB історично мала проблеми з паралельним apply у певних робочих навантаженнях; сучасні поліпшення допомагають, але застосування binlog усе ще часто псує RTO.
- Файлові системи copy-on-write (ZFS, btrfs) змінили правила гри для швидких відкатів через snapshot — при правильному використанні. При неправильному використанні вони також винайшли нові способи наситити IOPS.
- PostgreSQL 9.6 покращив програвання WAL і поведінку vacuum, що опосередковано допомагає часу відновлення при навантаженні на запис (менше bloat, менше churn, краща фонова поведінка після відновлення).
- MariaDB і PostgreSQL обидва залежать від семантики fsync; швидкість відновлення може домінуватися гарантіями збереження даних у сховищі більше, ніж кодом бази даних.
Вузькі місця відновлення, від яких не втекти
1) Переміщення байтів: пропускна спроможність і IOPS
Фізичне відновлення — це проблема копіювання файлів плюс replay. Якщо ваші дані на HDD або мережевому сховищі з непередбачуваною латентністю, ваш RTO — по суті прогноз погоди.
Для RTO менше 15 хв ви хочете:
- SSD/NVMe для тома бази даних.
- Локальне підгортання останнього базового бекапу.
- Передбачувану послідовну пропускну здатність і достатньо випадкових IOPS для WAL/redo apply.
2) Replay відновлення: поведінка WAL vs redo log
Відновлення PostgreSQL реплює WAL. MariaDB/InnoDB реплює redo і застосовує зміни до сторінок даних. Обидва чутливі до:
- скільки брудних сторінок потрібно синхронізувати;
- частоти чекпоінтів і розміру буферів логів;
- швидкості fsync і write amplification.
3) CPU і вибір стиснення
Стиснення — класична пастка: воно допомагає в мережі і зберіганні, а потім тихо вбиває CPU під час відновлення. Якщо ви сильно стискаєте бекапи, переконайтеся, що хости відновлення мають запас CPU і ви можете паралелізувати декомпресію.
Жарт №1: Стиснення — як абонемент у спортзал: купувати його приємно, а користуватися під час аварії — дуже особисто.
4) «Відновлено» не означає «придатно в користуванні»
Навіть після старту бази даних ви можете залишатися безпорадними:
- PostgreSQL: довге crash recovery або replay; потім автovacuum шторми; потім холодний кеш.
- MariaDB: InnoDB buffer pool холодний; adaptive hash index прогрівається; реплікація відбудовується; запити таймаутять через нестійкість планів.
5) Мета-дані: привілеї, розширення та дрейф конфігурації
Логічні відновлення голосно падають, коли бракує розширень або ролей. Фізичні відновлення тихо «падають», коли конфіг відрізняється, інстанс стартує з іншими налаштуваннями, і додаток бачить зміни поведінки під навантаженням.
Одна перефразована ідея від Werner Vogels (CTO Amazon): Проєктуйте системи, припускаючи, що щось зламається; надійність приходить від підготовки і автоматизації, а не від надії.
Плейбук швидкої діагностики
Це послідовність дій на on-call, коли час відновлення розпливається і вам потрібно знайти вузьке місце за хвилини, а не за постмортем.
Перш за все: ви копіюєте байти чи перебираєте логи?
- Якщо ви ще копіюєте файли: у вас проблема з пропускною здатністю/шляхом I/O.
- Якщо БД «стартує», але не «готова»: у вас проблема з replay відновлення або чекпоінтами.
- Якщо вона «готова», але додаток не працює: у вас проблема з підключеннями, обліковими даними або прогріванням.
По-друге: перевіряйте латентність сховища, а не тільки пропускну здатність
Відновлення часто роблять сплески дрібних записів. Латентність вбиває вас першою. Ви можете мати величезне MB/s число і все одно втрачати хвилини через fsync.
По-третє: підтвердіть, чи PITR затягує час
PITR для деяких організацій є неприпустимим. Добре. Але його потрібно інженерно забезпечити: WAL/binlog архівовано локально, паралельне отримання і протестоване рішення «наскільки далеко ми йдемо назад».
По-четверте: переконайтесь, що ви не саботуєте себе налаштуванням
Під час відновлення/реплею деякі налаштування варто тимчасово зробити агресивнішими, а потім повернути. Якщо ви цього не планували, залишаєтеся з дефолтами, які оптимізовані під безпеку, а не швидкість (що справедливо, але не відповідає вашому RTO).
По-п’яте: валідуйте цілісність бекапу рано
Якщо ваш бекап пошкоджений, кожна хвилина «тонкої настройки» — це хвилина, коли ви не переключилися на репліку або snapshot. Перевіряйте швидко, переходьте до плану Б швидко.
Практичні завдання: команди, виводи, рішення
Ці завдання призначені для виконання під час планування і під час інциденту. Кожне містить: команду, що означає вивід, і яке рішення приймати далі. Використовуйте їх як основу рукбука.
Завдання 1: виміряйте сирий дисковий пропуск (послідовний) на цільовому вузлі відновлення
cr0x@server:~$ sudo fio --name=seqread --filename=/var/lib/postgresql/fio.test --size=4G --bs=1M --iodepth=16 --rw=read --direct=1 --numjobs=1
seqread: (groupid=0, jobs=1): err= 0: pid=22341: Thu Dec 31 10:11:12 2025
read: IOPS=1650, BW=1650MiB/s (1730MB/s)(4096MiB/2481msec)
Значення: Висока пропускна здатність означає, що послідовне копіювання не буде вашим вузьким місцем. Якщо ви бачите <300 MiB/s при очікуваннях SSD/NVMe — у вас неправильний клас сховища або ви його погано ділили.
Рішення: Якщо пропускна здатність низька, припиніть планувати «відновлення з нуля». Плануйте промоцію репліки або відкат через snapshot.
Завдання 2: виміряйте латентність fsync-інтенсивних операцій (випадковий запис) на цільовому вузлі
cr0x@server:~$ sudo fio --name=randwrite --filename=/var/lib/mysql/fio.test --size=2G --bs=4k --iodepth=64 --rw=randwrite --direct=1 --numjobs=4 --time_based --runtime=30
randwrite: (groupid=0, jobs=4): err= 0: pid=22410: Thu Dec 31 10:12:02 2025
write: IOPS=42000, BW=164MiB/s (172MB/s), lat (usec): avg=610, max=22000
Значення: Середня латентність у сотнях мікросекунд — пристойно. Мілісекунди під навантаженням розтягнуть crash recovery і WAL replay.
Рішення: Якщо латентність погана — зменшіть паралелізм відновлення (обмежте задачі), перемістіть WAL/binlog на швидший том або перемкніться на вузол з кращим сховищем.
Завдання 3: перевірити стан recovery PostgreSQL і прогрес replay
cr0x@server:~$ sudo -u postgres psql -c "select pg_is_in_recovery(), now() as ts, pg_last_wal_receive_lsn(), pg_last_wal_replay_lsn();"
pg_is_in_recovery | ts | pg_last_wal_receive_lsn | pg_last_wal_replay_lsn
-------------------+-------------------------------+-------------------------+------------------------
t | 2025-12-31 10:13:11.552781+00 | 4A/9B2C1F20 | 4A/9B29A4D8
(1 row)
Значення: Receive LSN попереду replay LSN означає, що replay відстає (CPU/I/O завантаження). Якщо receive LSN NULL — ви не отримуєте WAL (проблема архіва/стрімінгу).
Рішення: Якщо replay сильно відстає, перевірте латентність диска і налаштування відновлення; якщо WAL не отримується — виправте отримання архіву або підключення реплікації.
Завдання 4: переглянути логи PostgreSQL на предмет вузьких місць відновлення
cr0x@server:~$ sudo tail -n 30 /var/log/postgresql/postgresql-16-main.log
2025-12-31 10:12:58.123 UTC [21011] LOG: starting PostgreSQL 16.2 on x86_64-pc-linux-gnu
2025-12-31 10:12:58.456 UTC [21011] LOG: entering standby mode
2025-12-31 10:13:05.990 UTC [21011] LOG: redo starts at 4A/9A000028
2025-12-31 10:13:11.770 UTC [21011] LOG: consistent recovery state reached at 4A/9B0000A0
2025-12-31 10:13:11.771 UTC [21011] LOG: restored log file "000000010000004A0000009B" from archive
Значення: Повторюване повільне повідомлення «restored log file … from archive» вказує, що вузьким місцем є отримання архіву (мережа, латентність об’єктного сховища). Якщо redo починається і потім зависає з чекпоінтами — страждає сховище.
Рішення: Якщо отримання архіву повільне — підготуйте WAL локально або увімкніть паралельне отримання WAL через інструменти бекапу.
Завдання 5: перевірити стан pgBackRest restore і здоров’я WAL-архіву
cr0x@server:~$ sudo -u postgres pgbackrest info
stanza: prod
status: ok
cipher: none
db (current)
wal archive min/max (16): 000000010000004A00000090/000000010000004A000000A1
full backup: 2025-12-31 03:00:02+00
size: 612.3GB, repo size: 201.7GB
backup reference list:
Значення: Існує недавній повний бекап, діапазон WAL-архіву присутній. Якщо статус не ok або WAL min/max застарілий — ваш PITR може бути неможливим.
Рішення: Якщо WAL-архів не здоровий — припиніть обіцяти PITR. Промотуйте репліку або відновіть до останньої валідної точки.
Завдання 6: виявити тиск чекпоінтів PostgreSQL (провал продуктивності після відновлення)
cr0x@server:~$ sudo -u postgres psql -c "select checkpoints_timed, checkpoints_req, buffers_checkpoint, buffers_backend, stats_reset from pg_stat_bgwriter;"
checkpoints_timed | checkpoints_req | buffers_checkpoint | buffers_backend | stats_reset
------------------+-----------------+--------------------+-----------------+-------------------------------
112 | 87 | 98122310 | 442190 | 2025-12-31 09:40:00+00
(1 row)
Значення: Високий checkpoints_req свідчить про примусові чекпоінти (часто через занадто малий max_wal_size або різкі сплески записів). Це може уповільнити відновлення і ранній трафік.
Рішення: Збільште max_wal_size і налаштуйте checkpoint_timeout/checkpoint_completion_target для більш гладкого I/O — особливо на вузлах відновлення.
Завдання 7: перевірити поведінку InnoDB під час відновлення MariaDB і підказки часу crash recovery
cr0x@server:~$ sudo tail -n 40 /var/log/mysql/error.log
2025-12-31 10:11:22 0 [Note] InnoDB: Starting crash recovery.
2025-12-31 10:11:22 0 [Note] InnoDB: Reading tablespace information from the .ibd files...
2025-12-31 10:12:10 0 [Note] InnoDB: 5.6.0 started; log sequence number 987654321
2025-12-31 10:12:10 0 [Note] InnoDB: Completed initialization of buffer pool
2025-12-31 10:12:54 0 [Note] InnoDB: Crash recovery finished.
Значення: Якщо crash recovery займає хвилини — це частина вашого RTO. Довші часи часто корелюють з великими redo логами, обсягом брудних сторінок або повільними fsync.
Рішення: Якщо crash recovery регулярно довгий — налаштуйте частоту чекпоінтів/flush та переконайтесь, що redo логи і дані розміщені на низьколатентному сховищі.
Завдання 8: валідувати готовність фізичного бекапу MariaDB (prepared vs not)
cr0x@server:~$ sudo mariabackup --prepare --target-dir=/backups/mariadb/full-2025-12-31
[00] 2025-12-31 10:14:03 completed OK!
Значення: «completed OK» означає, що бекап тепер консистентний і готовий до швидкого copy-back. Якщо ви відкладаєте prepare до часу інциденту — ви витратите свій RTO на паперову роботу.
Рішення: Завжди тримайте останній бекап вже підготовленим (або підготуйте його одразу після створення), якщо ви прагнете відновлень менше 15 хв.
Завдання 9: відновлення MariaDB з підготовленого бекапу (copy-back) і перевірка власності
cr0x@server:~$ sudo systemctl stop mariadb
cr0x@server:~$ sudo rm -rf /var/lib/mysql/*
cr0x@server:~$ sudo mariabackup --copy-back --target-dir=/backups/mariadb/full-2025-12-31
[00] 2025-12-31 10:15:44 completed OK!
cr0x@server:~$ sudo chown -R mysql:mysql /var/lib/mysql
Значення: Успішний copy-back необхідний, але недостатній. Неправильна власність заблокує запуск або спричинить дивні проблеми з правами.
Рішення: Якщо власність/SELinux/AppArmor неправильні — виправте негайно. Не «подивіться, чи стартує». Ні — не стартує, і ви втратите час.
Завдання 10: підтвердити, що MariaDB приймає підключення і не застрягла у відновленні
cr0x@server:~$ sudo systemctl start mariadb
cr0x@server:~$ mysql -uroot -e "select @@version, @@innodb_flush_log_at_trx_commit, @@sync_binlog\G"
@@version: 10.11.6-MariaDB
@@innodb_flush_log_at_trx_commit: 1
@@sync_binlog: 1
Значення: Сервер запущений і конфіги видно. Якщо з’єднання зависає — перевірте лог помилок на crash recovery або fsync-стали.
Рішення: Для аварійних вузлів відновлення ви можете тимчасово послабити стійкість (див. нижче), якщо ваша організація це приймає — потім поверніть налаштування.
Завдання 11: оцінити час відновлення PostgreSQL вимірюванням декомпресії та копіювання
cr0x@server:~$ time sudo -u postgres pgbackrest --stanza=prod restore --type=immediate --target-action=promote
real 6m42.118s
user 2m10.044s
sys 1m02.991s
Значення: «real» — це стінний час. Якщо user time великий — декомпресія/розшифрування зв’язане з CPU. Якщо sys time великий — ядро і I/O головна історія.
Рішення: CPU-зв’язане: додайте ядер, змініть стиснення, паралелізуйте. I/O-зв’язане: швидші диски, локальне репо, менше мережевих стрибків.
Завдання 12: перевірити, чи PostgreSQL чекає на отримання WAL-архіву
cr0x@server:~$ sudo -u postgres psql -c "select now(), wait_event_type, wait_event, state, query from pg_stat_activity where pid = pg_backend_pid();"
now | wait_event_type | wait_event | state | query
------------------------------+-----------------+------------+--------+-------------------------------------
2025-12-31 10:17:12.118+00 | Activity | WALRead | active | select now(), wait_event_type, ...
(1 row)
Значення: Очікування WALRead під час відновлення часто вказує на повільний I/O або отримання архіву.
Рішення: Якщо WAL віддалений — наблизьте архів або переключіться на стрімінг із живого upstream; якщо локальний — дослідіть латентність диска.
Завдання 13: знайти забутий replication slot PostgreSQL, який роздуває WAL (гігієна до інциденту)
cr0x@server:~$ sudo -u postgres psql -c "select slot_name, active, restart_lsn from pg_replication_slots;"
slot_name | active | restart_lsn
---------------+--------+-------------
analytics_etl | f | 4A/01000000
(1 row)
Значення: Неактивний слот утримує WAL назад. З часом це роздуває обсяг WAL, що збільшує час PITR і може заповнити диски у найгірший момент.
Рішення: Якщо споживач мертвий — видаліть слот після підтвердження безпечності. Потім виправте управління споживачами.
Завдання 14: перевірити доступність binlog MariaDB для PITR і годинник, у якому ви біжите
cr0x@server:~$ mysql -uroot -e "show binary logs;"
Log_name File_size
binlog.000221 104857600
binlog.000222 104857600
binlog.000223 51239871
Значення: Binlog-и існують і розміри вказують на активну ротацію. Якщо логи відсутні через занадто короткий ретеншн — PITR це фантазія.
Рішення: Встановіть ретеншн binlog виходячи з максимального вікна PITR, який ви обіцяєте. Потім моніторте це як production (бо це і є production).
Завдання 15: валідувати успіх відновлення перевіркою базових інваріантів (PostgreSQL)
cr0x@server:~$ sudo -u postgres psql -c "select count(*) from pg_class; select now();"
count
-------
4182
(1 row)
now
-------------------------------
2025-12-31 10:18:55.11002+00
(1 row)
Значення: Ви не доводите правильність, але доводите, що каталог читається і сервер відповідає. Додайте перевірки на рівні додатка далі.
Рішення: Якщо будь-який запит дає помилки з повідомленнями про корупцію — зупиняйтесь. Миттєво перемикайтеся на промоцію репліки або інший бекап.
Завдання 16: валідувати успіх відновлення перевіркою базових інваріантів (MariaDB)
cr0x@server:~$ mysql -uroot -e "show engine innodb status\G" | head -n 25
*************************** 1. row ***************************
Type: InnoDB
Name:
Status:
=====================================
2025-12-31 10:19:21 0x7f2c4c1fe700 INNODB MONITOR OUTPUT
=====================================
Per second averages calculated from the last 4 seconds
-----------------
BACKGROUND THREAD
-----------------
srv_master_thread loops: 12 srv_active, 0 srv_shutdown, 245 srv_idle
Значення: InnoDB працює. Ви також можете бачити, чи воно ще виконує важку фонову роботу. Якщо система thrash-ить — очікуйте повільну поведінку додатка, навіть якщо «відновлення завершено».
Рішення: Розгляньте тимчасове зниження трафіку додатка або перевод у режим лише для читання, поки система стабілізується, залежно від моделі вашого сервісу.
Три міні-історії з корпоративного життя
Міні-історія 1: Аварія через неправильне припущення
Компанія була в процесі міграції: моноліт на MariaDB, новий сервіс на PostgreSQL. SRE команда мала чітку ціль RTO і неакуратну реальність. Усі погодилися, що «у нас є бекапи», що є корпоративним еквівалентом фрази «у нас є парасолі», стоячи в урагані.
Припущення було просте: логічні дампи «достатні», бо датасет «не такий вже великий». Ніхто не виміряв відновлення повністю від початку до кінця. Рукбук on-call казав: забрати останній дамп з об’єктного сховища, відновити, застосувати міграції, перенаправити додаток.
Потім інцидент зі сховищем знищив первинний том. Команда почала відновлення дампу. Воно повзло, CPU завантажений, диск світиться, а час йде. Створення індексів домінувало. Потім виконали міграції додатка, що додало блокування і ще більше часу. Через годину у них була база даних. Через ще деякий час — щось, що міг використовувати додаток. RTO було пропущено не на хвилини; його пропустили на цілу нараду.
Постмортем не був про героїчні налаштування. Це було про визнання того, що дампи — не стратегія відновлення у масштабі. Вони впровадили фізичні бекапи, побудували теплий standby і почали вимірювати час відновлення щомісяця. Виправлення було переважно непомітним. Ось чому воно спрацювало.
Міні-історія 2: Оптимізація, що відпрацювала проти
Інша організація пишалася своєю ефективністю зберігання. Вони все сильно стискали: базові бекапи, WAL-архіви — все. Витрати впали. Дашборди виглядали акуратно. Фінанси були короткочасно задоволені.
Під час реального інциденту вони відновлювали PostgreSQL з стисненого бекапу на вузол з меншим числом ядер, ніж продакшн. На папері було «ок», бо цей вузол існував лише для аварій. В реальності декомпресія стала горлом пляшки. Відновлення тривало настільки довго, що команда почала «оптимізувати» в реальному часі: змінювати налаштування стиснення посеред процесу, перезапускати процеси і влаштовувати виконавський танець замість передбачуваної процедури.
Вони повернули базу, але ціль RTO зникла. Найбільший шкваліт: економія на зберіганні була реальною, але мала значно менший вплив, ніж вартість простою і шкода репутації. Вони знайшли баланс: помірне стиснення, більше паралелізму і вузли для аварійного відновлення, розраховані під навантаження відновлення, а не під звичайний QPS.
Жарт №2: Нічого так не говорить «ми готові», як виявлення, що ваша коробка для відновлення — по суті картоплина з мережевим кабелем.
Міні-історія 3: Сумно, але правильно, що врятувало день
Компанія, що працює поруч із платіжними сервісами, запускала і MariaDB, і PostgreSQL для різних сервісів. Їх найцінніша звичка була не інструмент. Це був ритуал: щотижня один інженер виконував репетицію відновлення в ізольованому середовищі, використовуючи ті ж команди, що й в інцидентному рукбуці.
Вони відслідковували три часи: час виділення обчислювальних ресурсів і сховища, час відновлення базового бекапу і час до «здорового додатка». Вони також реєстрували причини провалів — права, відсутні WAL сегменти, дрейф схеми, зламані секрети — і виправляли їх із тією самою спокоєм, яку може надихнути лише повторювана тренування.
Коли стався інцидент (корумпований том плюс погане оновлення ядра, бо реальність любить поєднання), відновлення не було ідеальним. Але його відрепетирували. Вони виконали плейбук, одразу побачили відставання WAL-архіву, переключилися на промоцію репліки і повернулися в межі вікна.
Ніхто не писав героїчне повідомлення у Slack потім. Ось як ви зрозумієте, що все спрацювало.
Типові помилки: симптом → корінь → виправлення
Цей розділ читають, коли відновлення «майже готове» вже в п’ятий раз.
1) Симптом: відновлення стартує швидко, потім повзе при 5–10% CPU
- Корінь: латентність I/O і fsync-стали, часто через спільне сховище або витрачені кредити на burst.
- Виправлення: Перемістіть дані та WAL/redo на низьколатентні SSD/NVMe; зменшіть шумних сусідів; перевірте бюджет IOPS; розгляньте відкат через snapshot або промоцію репліки.
2) Симптом: PostgreSQL застряг у «restoring log file … from archive» повільно
- Корінь: вузьке місце отримання WAL-архіву (латентність віддаленого об’єктного сховища, серіалізоване завантаження або обмежена мережа).
- Виправлення: Використовуйте локальне репо/кеш для WAL, увімкніть паралельне отримання WAL у інструменті бекапу або стрімте з живого upstream, якщо доступно.
3) Симптом: запуск MariaDB після copy-back займає вічність
- Корінь: InnoDB crash recovery повільно застосовує redo; часто налаштування логів і латентність сховища поєднуються проти вас.
- Виправлення: Тримайте бекапи підготовленими; забезпечте, щоб redo лог і дані були на швидкому сховищі; перегляньте innodb_flush_log_at_trx_commit і sync_binlog для вузла відновлення, якщо це прийнятно.
4) Симптом: «бекап відновлено», але в додатку вибухають помилки
- Корінь: Відновлено БД, але не середовище: неправильні користувачі, відсутні розширення, дрейф конфігурації або застарілий DNS/рядки з’єднання.
- Виправлення: Автоматизуйте smoke-тести після відновлення; управляйте ролями/розширеннями через конфіг-менеджмент; забезпечте незмінні конфіги для цілей відновлення.
5) Симптом: PITR зупиняється наполовину через відсутні WAL/binlog
- Корінь: занадто короткий ретеншн, архівація не моніториться або прогалина утворилася під час попереднього інциденту.
- Виправлення: Моніторте неперервність архіву; ставте алерти на відсутні сегменти; встановіть ретеншн відповідно до обіцяного вікна відновлення; практикуйте відновлення, щоб це довести.
6) Симптом: відновлення швидкі в тестах, повільні в реальних інцидентах
- Корінь: Тести проходять на порожніх хостах і тихому сховищі; інциденти відбуваються під час конкуренції і деградації.
- Виправлення: Тестуйте відновлення під навантаженням і з реалістичною конкуренцією I/O; резервуйте потужність для відновлення; тримайте «вузли відновлення» розміром і прогрітими.
Чеклісти / покроковий план
Покроково: як дістатися до RTO менше 15 хв (практичний шлях)
- Виберіть стратегію відновлення за розміром набору даних. Якщо ваш каталог даних достатньо великий, що його копіювання займає більше 10 хв — припиніть прикидатися. Використовуйте промоцію репліки або snapshot.
- Стандартизуйтесь на фізичних бекапах для обох движків. MariaDB: Mariabackup. PostgreSQL: pgBackRest (або еквівалентне фізичне рішення). Дампи стануть другорядними.
- Підготуйте останній базовий бекап локально. Ваш вузол відновлення не повинен під час інциденту тягнути сотні гігабайтів по best-effort мережі.
- Тримайте бекапи «готовими до відновлення». Для MariaDB це означає підготовлені бекапи. Для PostgreSQL — перевірені маніфести/контрольні суми і архів, що насправді містить потрібні сегменти.
- Інженеруйте PITR як систему першого класу. Архівація WAL/binlog має моніторитися, зберігатися і тестуватися. Розриви слід трактувати як Sev-2, а не «поправимо потім».
- Виділіть вузли відновлення під навантаження відновлення. Відновлення — це сплеск: високий I/O, високий CPU (декомпресія), багато операцій з метаданими. Розмірюйте під це, а не під середній QPS.
- Розділяйте томи даних і логів, коли це допомагає. PostgreSQL: тримайте WAL на швидкому сховищі. MariaDB: лог-файли і дані виграють від низької латентності; розділення може зменшити конкуренцію.
- Напишіть односторінковий рукбук з деревом рішень. «Якщо архів WAL повільний — промотуємо репліку.» Зробіть його виконуваним о 3 ранку.
- Автоматизуйте переключення сервісу. DNS/VIP оновлення, reload пулерів, оновлення рядків з’єднання. Ваш RTO вмирає у клейових кроках.
- Репетируйте щомісяця з секундоміром. Відслідковуйте три часи: відновлення бази, відновлення до консистентності, «здоровий додаток». Виправляйте найбільші джерела затримок першими.
Тактики конфігурації, що зазвичай допомагають (і коли бути обережним)
Це не універсальні «натисни цю кнопку і стало швидко». Це важелі. Тягніть їх усвідомлено, бажано лише на вузлах відновлення або під час відновлення.
- PostgreSQL: забезпечте швидке отримання WAL (локальний кеш); налаштуйте чекпоінти під вашу нагрузку; уникайте надто малого max_wal_size на системах з великою кількістю записів; розмір shared_buffers розумно (занадто великий може уповільнити перезапуск через поведінку брудних буферів).
- MariaDB: тримайте бекапи підготовленими; уникайте патологічних flush-настроювань, що створюють велике crash recovery; забезпечте стратегію прогрівання buffer pool, якщо ви на ньому залежите; розгляньте відкладення частини durability, лише якщо ваш ризиковий профіль дозволяє.
ЧАВО
1) Що відновлюється швидше: MariaDB чи PostgreSQL?
Жоден не «перемагає» універсально. Фізичне відновлення PostgreSQL плюс програвання WAL дуже передбачуване, коли архів WAL здоровий і локальний. Фізичне відновлення MariaDB може бути дуже швидким, але поведінка InnoDB під час відновлення і застосування binlog може здивувати. Переможцем більше стає ваше сховище і стратегія PITR, ніж бренд движка.
2) Чи можу я досягти RTO 15 хв з mysqldump або pg_dump?
Лише для маленьких наборів даних і простих схем. Як тільки індекси і обмеження суттєві — час логічного відновлення зростає. Для жорсткого RTO використовуйте фізичні бекапи, snapshots або промоцію репліки.
3) Який один найбільший фактор у часі відновлення?
Для фізичних відновлень: латентність сховища (fsync-інтенсивний випадковий I/O) і пропускна здатність програвання логів (WAL/redo). Для PITR: швидкість отримання архіву і неперервність.
4) Як snapshot-и порівнюються з фізичними бекапами?
Snapshot-и (EBS/ZFS/LVM) можуть бути найшвидшим «відновленням», якщо вони crash-consistent і ваша база даних це дозволяє (зазвичай дозволяє з відновленням). Їх також легко зловжити: snapshot-нути неправильний набір томів або забути, що потрібно консистентні snapshot-и даних і WAL.
5) Чи повинні WAL/binlog бути на окремих дисках?
Часто так, коли це зменшує конкуренцію і дає логам меншу латентність. Але окремі диски не виправлять повільні диски. Один швидкий NVMe може обіграти дві посередні мережеві томи будь-якого дня тижня.
6) Чи допомагає стиснення швидкості відновлення?
Воно допомагає часу передачі і економії простору, але може нашкодити часу відновлення, якщо вузьке місце — CPU або однопотокова операція. Помірне стиснення з паралелізмом зазвичай оптимальне для систем, орієнтованих на RTO.
7) Як довести, що мій RTO реальний?
Проведіть повну репетицію: виділити ресурси → відновити → recovery/PITR → перевірки здоров’я додатка → переключення. Робіть це під реалістичним навантаженням і з тими самими людьми, що будуть на on-call.
8) Що моніторити, щоб захистити швидкість відновлення?
Неперервність архівації WAL/binlog, успішність бекапів і їх валідація, lag реплікації, латентність сховища, вільне місце на дисках (включно з ростом WAL) і «час репетиції відновлення» як окремий SLO.
9) Якщо я можу промотувати репліку, чи все одно потрібні бекапи?
Так. Репліки захищають від деяких відмов (втрата вузла). Бекапи захищають від інших проблем (помилки оператора, корупція даних, погані деплоя, ransomware). RTO дають репліки; відновлення від некоректних даних дають бекапи.
Наступні кроки, які ви можете зробити цього тижня
- Заміряйте час відновлення для MariaDB і PostgreSQL у staging: від початку до кінця, зі стопером. Зафіксуйте, куди йде час: копіювання, підготовка, програвання WAL/binlog, готовність додатка.
- Запустіть тести латентності сховища (fio random write) на ваших фактичних вузлах відновлення. Якщо латентність погана — ваш RTO це вигадка, поки не зміните сховище.
- Валідуйте PITR-вхідні дані: перевірте діапазон WAL-архіву (PostgreSQL) або ретеншн binlog (MariaDB). Налаштуйте алерти на прогалини.
- Змініть ваш рукбук на дерево рішень: «відновлення з бекапу» vs «промоція репліки» vs «відкат через snapshot». Зробіть компроміси явними.
- Заплануйте щомісячну репетицію відновлення і трактуйте провали як production-інциденти. Якщо ви не можете відновити у вівторок, ви не відновите у неділю.
RTO менше 15 хв — це не вправляння в тюнінгу. Це вибір в культурі операцій: фізичні бекапи, підготовлені артефакти, швидке сховище і репетиції, які роблять нудний шлях дефолтним. Зробіть це — і відновлення стануть процедурою. Пропустіть — і відновлення стануть історією.