MySQL проти MariaDB на VPS з 16 ГБ: коли реплікація та пулінг стають обов’язковими

Було корисно?

На одному VPS з 16 ГБ можна обслуговувати багато бізнесу. До того моменту, поки не стане неможливо. Незапланований відмову рідко буває «він одразу впав». Гірше: він кульгає, потім ваш додаток створює ще більше підключень, і база даних перетворюється на завантажений ресторан з одним кухарем і 200 людьми із картками.

Саме тут «MySQL проти MariaDB» перестає бути дебатом про дизайни і стає операційним рішенням: яка СУБД дає безпечніші дефолти, чіткішу спостережуваність і менше сюрпризів під час додавання реплікації та пулінгу — бо ви додасте їх, якщо дбаєте про доступність.

Реальність VPS з 16 ГБ: ви не маєте великого запасу потужності

VPS з 16 ГБ — це «середній седан» у хостингу баз даних. Достатньо, щоб відчувати впевненість. Одночасно це досить мало, щоб один неправильний тюнінг перетворився на інцидент із завантаженістю ЦП, голодуванням I/O, активним свопом та питанням «чому load average 40?».

Ось що насправді ви купуєте з 16 ГБ:

  • Бюджет пам’яті: не 16 ГБ. Ядро, кеш файлової системи, ваш зоопарк агентів і сама база хочуть свою частку. Розраховуйте на 12–13 ГБ придатних для процесів MySQL/MariaDB, перш ніж ризикувати свопом і нестабільністю.
  • Потолок I/O: VPS «NVMe» часто означає «спільний NVMe». Спайки латентності — не баг; це ваш сусід.
  • Конкуренція за ЦП: навіть при виділених vCPU шумні сусіди проявляються як %steal, затримки планувальника і непередбачувана хвістова латентність.
  • Радіус ураження одного хоста: kernel panic, корупція файлової системи, технічні роботи провайдера, випадкове rm — і ви офлайн.

На такому сервері реплікація і пулінг — це не «покращення продуктивності». Це різниця між поганим днем і кар’єрно обмежувальним днем.

Факти та історія, які й досі важливі в продакшені

Деякі контекстні пункти — тривія, поки вони не вдарять вас під час вікна оновлення.

  1. MariaDB відгалузилася від MySQL у 2009 році після поглинання Sun компанією Oracle. Цей форк був не лише про ідеологію; він визначив темп релізів і дефолти.
  2. MySQL 5.6/5.7 зробили InnoDB безперечним центром; ера MyISAM переважно в минулому, але багато застарілих схем досі носять відповідні припущення.
  3. MariaDB довше підтримувала інші інженси зберігання (і додала нові). Це сила й ризик: більше опцій — більше шансів обрати невірно.
  4. MySQL 8.0 повністю прибрав query cache (це була глобальна mutex-вечірка). MariaDB довше підтримувала його версію, але при високій конкуренції він рідко приносить користь.
  5. GTID реалізації відрізняються між MySQL та MariaDB. «GTID увімкнено» — не кінець розмови; це початок питань сумісності.
  6. За замовчуванням плагін автентифікації MySQL змінився (caching_sha2_password став більш поширеним). Старі клієнти та деякі проксі мали з цим проблеми.
  7. MariaDB і MySQL з часом розійшлися в поведінці оптимізатора. Один і той же SQL може мати різні плани. На VPS регрес плану дорожчий, бо місця для маневру немає.
  8. Реплікація еволюціонувала з «best effort» у операційну основу: безпечні метадані реплікації, багатопотокові аплаєри, опції semi-sync. Але вам усе одно потрібно тестувати відмовостійкість серйозно.

MySQL проти MariaDB: як обирати на VPS

Формулювання рішення: гарантії операційності, а не список фіч

На VPS з 16 ГБ вас обмежують дві речі: латентність і варіативність. Пікова пропускна здатність менш важлива за стабільний час відгуку під навантаженням і безпечне відновлення, коли щось іде не так.

Тому обирайте движок, виходячи з:

  • Безпечності оновлень: наскільки передбачувані мажорні/мінорні оновлення і наскільки добре команда їх розуміє?
  • Сумісності інструментів: чи поводяться ваш проксі, інструменти бекапу, ORM і моніторинг стабільно?
  • Ергономіки реплікації: чи отримуєте ви чіткий статус реплікації, просте пересівання і менше граничних сюрпризів?
  • Стабільності продуктивності: чи уникає він патологічних зависань (metadata locks, flushing stalls, thrash буферного пулу) при вашому навантаженні?

MySQL: «нудний дефолт», і він нудний не просто так

Якщо у вас типовий веб-навантаження (таблиці InnoDB, OLTP-запити, трохи звітності), MySQL 8.0 часто є безпечним вибором. Він широко протестований у екосистемі, з проксі, драйверами та сервісами. Операційно це важить більше, ніж блискуча фічі, яку ви ніколи не застосуєте.

Переваги MySQL на VPS:

  • Передбачувана підтримка екосистеми: драйвери, конектори та хмарні інструменти частіше орієнтовані спочатку на MySQL.
  • Зрілість Performance Schema: відмінно підходить для діагностики чекань, блокувань і «топових» SQL без здогадок.
  • «Нормальність» реплікації: багато інструментів для фейловера та рукописних рукбуків написані з урахуванням семантики MySQL.

MariaDB: сильний варіант, але сприймайте сумісність як проєкт

MariaDB може бути чудовим вибором, коли потрібні її специфічні можливості або в організації вже є стандартизація на ній. Але не думайте, що це «MySQL з іншим логотипом». Розбіжності реальні, і на малому хості операційні витрати сюрпризів зростають.

Переваги MariaDB на VPS:

  • Інші варіанти реплікації та кластеризації: MariaDB + Galera — поширений патерн (з застереженнями), і можливості реплікації MariaDB можуть виглядати привабливими залежно від версії.
  • Рухливість спільноти та пакування: деякі дистрибутиви та вендори мають сильні дефолти та бекпорти для MariaDB.

Думка: Якщо ви починаєте з нуля і ваш стек типовий (веб-додаток + проксі + стандартні конектори), оберіть MySQL 8.0. Якщо ви вже стабільно працюєте на MariaDB — не мігруйте просто з нудьги; робіть це, коли маєте чітку проблему і протестований план.

Цитата про надійність, яку варто записати на стікері

Werner Vogels: «Все ламається постійно.» (парафразована ідея)

Коли пулінг підключень стає обов’язковим (а не «приємним»)

На VPS з 16 ГБ ваш сервер бази даних не лише виконує запити. Він ще й няньчиться з підключеннями. Потоки, пам’ять на підключення, контекстні переключення, рукопашні аутентифікації, TLS та внутрішня бухгалтерія. Ці накладні витрати невидимі аж до моменту, коли вони раптово проявляються.

Пулінг стає обов’язковим, коли ви бачите будь-який із цих патернів

  • Шторм підключень: автоскейл інстансів додатку, cron-налагодження, деплоя чи ретраїв створюють сплески сотень/тисяч нових підключень за секунду.
  • Багато коротких запитів: класичний веб-OLTP, де запити швидкі, але численні; накладні витрати на підключення стають вузьким місцем.
  • Висока конкурентність на малому хості: навіть якщо кожен запит дешевий, БД витрачає час на планування, а не на роботу.
  • Чутливість до хвостової латентності: вам важливі p95/p99, а не середнє. Налаштування підключення і планування потоків псуватимуть хвости.

Чесна правда: якщо ваш додаток відкриває і закриває підключення на запит, пулінг не опціональний. БД рано чи пізно почне тримати вас на уздрі CPU, mutex-контенцією або пам’ятним тиском. І зробить це в найнеприємніший момент.

Жарт #1: База без пулінгу — як нічний клуб з охоронцем, який перевіряє ваш документ щоразу, коли ви моргнули.

Що означає «пулінг» у продакшені

Є два рівні:

  • Пулінг на боці додатку (базовий і бажаний): ваш додаток підтримує стабільний пул підключень на інстанс. Це добре, але масштабування лінійно з кількістю інстансів.
  • Пулінг/проксі на мережевому рівні (обов’язковий в міру зростання): pooler/proxy, як-от ProxySQL, мультиплексує багато сесій клієнта на меншу кількість серверних підключень, застосовує правила маршрутизації і захищає БД від штормів.

Розмір пулу на VPS з 16 ГБ: перестаньте думати «max_connections = 2000»

Високе max_connections — не гордість. Часто це визнання того, що ви не зробили пулінг і компенсуєте відмовою.

На 16 ГБ зазвичай бажано:

  • Розумна кількість серверних підключень: часто у сотнях або менше, залежно від навантаження.
  • Строгі таймаути: вбивайте ідл-клієнтів раніше, ніж вони перетворяться на витік ресурсів.
  • Зворотний тиск: пулери, які ставлять у чергу і скидатимуть навантаження замість того, щоб дозволити БД померти.

Коли реплікація стає обов’язковою (навіть якщо ви боїтеся складності)

Реплікація — це не лише «для масштабування читань». На одному VPS вона передусім про виживання: бекапи, час відновлення, техобслуговування і тестування. Перший раз, коли ваш єдиний хост відмовить і відновлення займе години, ви полюбите репліки.

Реплікація стає обов’язковою, коли вам потрібне будь-що з переліченого

  • RPO < 1 година без ставок на бінлог-бекапи і ідеальні процедури відновлення.
  • Вікна технічного обслуговування без простоїв: оновлення ОС, апгрейди БД, міграція сховища.
  • Бекапи, що не давлять продакшен: робіть логічні бекапи або запускайте важкі читання проти репліки.
  • Безпечні експерименти: тестуйте зміни в схемах, плани запитів, побудову індексів.
  • Розумні дії при інциденті: потрібне чисте місце для судових запитів без боротьби з живим трафіком.

Репліка на іншому VPS: мінімально життєздатна архітектура

Для primary з 16 ГБ поширений «дорослий» крок такий:

  • Primary (16GB): приймає записи
  • Replica (8–16GB): обслуговує читання, виконує бекапи, може бути піднята в роль primary
  • Pooler/proxy (малий VM або на хостах додатка): контролює конкурентність і маршрутизацію

Це не гламурно. Це надійно. Як вогнегасник: нудно, поки не стане абсолютно потрібним.

Асинхронна vs semi-sync реплікація на VPS

Асинхронна — дефолт: primary повертає успіх до того, як репліка підтвердить. Швидко, але можна втратити останні транзакції при падінні primary.

Semi-sync може зменшити цей ризик, чекаючи підтвердження хоча б однієї репліки перед комітом. На VPS з мережевою варіативністю semi-sync також може посилити хвостову латентність. Використовуйте його, коли ви можете терпіти цю латентність і маєте стабільне з’єднання з реплікою; інакше зосередьтеся на добрих бекапах і швидкому фейловері.

Жарт #2: Реплікація — як чищення зубів: всі обіцяють почати після першої надзвичайної ситуації.

Швидкий план діагностики: знайти вузьке місце швидко

Коли латентність стрибає або пропускна здатність падає, не починайте з редагування конфігу. Почніть з того, щоб з’ясувати, що робить сервер зараз. Це найкоротший шлях від паніки до правильного рішення.

Перше: це CPU, пам’ять чи I/O?

  1. Насичення CPU / черга виконання: якщо CPU завантажений і load average високий, шукайте дорогі запити, mutex-чекання або занадто багато потоків.
  2. Тиск пам’яті: якщо йде своп або reclaim, ви не просто тюните — ви тонеєте. Зменшіть використання пам’яті й кількість підключень, потім перегляньте розміри буферів InnoDB.
  3. Латентність I/O: якщо час очікування диска зростає, ви можете мати багато CPU і все одно бути «вниз». Поведінка InnoDB при flush, doublewrite, частота fsync та сусідські шумові операції мають значення.

Друге: занадто багато підключень чи занадто мало ресурсів на підключення?

  1. Перевірте кількість потоків, активні підключення, aborted connections.
  2. Перевірте, чи блокуються запити через блокування або очікують на I/O.
  3. Шукайте шторм підключень після деплоїв і подій автоскейлу.

Третє: регрес плану запиту чи борг у схемі/індексах?

  1. Визначте топ-запити за загальним часом і p95 латентністю.
  2. Підтвердіть використання індексів і оцінки рядків.
  3. Шукайте відсутні складені індекси й випадкові повні скани.

Четверте: стан реплікації (якщо вона є)

  1. Затримка репліки: кілька секунд відставання від джерела, ріст relay log.
  2. Аплаєрні потоки застрягли на транзакції, очікування блокувань.
  3. Диск на репліці повний через binlogs/relay logs.

Практичні завдання: команди, приклади виводів та рішення

Ось реальні перевірки, які я виконую на VPS з 16 ГБ, коли щось відчувається неправильно. Кожна містить команду, типовий вивід, що це означає і яке рішення я приймаю.

Завдання 1: Підтвердити тиск пам’яті та активність свопу

cr0x@server:~$ free -h
               total        used        free      shared  buff/cache   available
Mem:            15Gi        12Gi       520Mi       310Mi       2.6Gi       1.8Gi
Swap:          2.0Gi       1.2Gi       820Mi

Що це означає: Своп використовується активно. «Available» маленький. Очікуйте затримок, особливо під навантаженням записами.

Рішення: Негайно зменшити кількість підключень і пам’ять на підключення. Якщо ви використовуєте великі sort/join буфери, зупиніть це. Потім правильно визначте розмір InnoDB buffer pool і впровадьте пулінг.

Завдання 2: Перевірити насичення CPU і %steal

cr0x@server:~$ mpstat -P ALL 1 5
Linux 6.1.0 (server)  12/31/2025  _x86_64_  (4 CPU)

12:00:01 AM  CPU   %usr  %sys  %iowait  %steal  %idle
12:00:02 AM  all   72.4  10.8     1.2     8.6    7.0
12:00:03 AM  all   70.1  11.2     0.9     9.3    8.5

Що це означає: CPU сильно завантажений і %steal високий. Ви конкуруєте за CPU хоста.

Рішення: Зменшіть конкурентність (пулінг), знизьте max_connections і пріоритезуйте ефективність запитів. Розгляньте перенесення БД на тариф з меншим контеншеном або з виділеними CPU.

Завдання 3: Швидка перевірка латентності диска

cr0x@server:~$ iostat -x 1 3
Device            r/s     w/s   rkB/s   wkB/s  await  svctm  %util
nvme0n1          35.2   210.7  2200.1  9800.4  18.40  0.52  96.8

Що це означає: Диск майже насичений і середній await високий. InnoDB буде зупинятися на fsync і flush операціях.

Рішення: Дослідіть write amplification (binlogs, doublewrite, redo), перевірте flush-поведінку «dirty pages» і зменшіть сплески (пакетування, розмір транзакцій). Якщо це шум від спільного сховища, реплікація не вирішить проблему; потрібне краще сховище.

Завдання 4: Підтвердити версію MySQL/MariaDB і движок

cr0x@server:~$ mysql -e "SELECT VERSION() AS version, @@version_comment AS comment\G"
*************************** 1. row ***************************
version: 8.0.36
comment: MySQL Community Server - GPL

Що це означає: Точна «марка» і версія визначають, які лічильники продуктивності, поля статусу реплікації і дефолти застосовуються.

Рішення: Узгодьте кроки усунення неполадок з версією. Не застосовуйте поради для MariaDB до MySQL 8.0 без перевірки (і навпаки).

Завдання 5: Перевірити тиск підключень і використання потоків

cr0x@server:~$ mysql -e "SHOW GLOBAL STATUS LIKE 'Threads_%'; SHOW VARIABLES LIKE 'max_connections';"
+-------------------+-------+
| Variable_name     | Value |
+-------------------+-------+
| Threads_cached    | 12    |
| Threads_connected | 385   |
| Threads_created   | 98123 |
| Threads_running   | 42    |
+-------------------+-------+
+-----------------+-------+
| Variable_name   | Value |
+-----------------+-------+
| max_connections | 800   |
+-----------------+-------+

Що це означає: Багато створених потоків свідчить про churn. Велика кількість підключених потоків на малому сервері часто — накладні витрати, а не корисна робота.

Рішення: Запровадьте пулінг. Зменшіть max_connections. Встановіть адекватні таймаути. Якщо churn потоків високий, перевірте thread_cache_size і повторне використання підключень.

Завдання 6: Виявити топ чекань (Performance Schema)

cr0x@server:~$ mysql -e "SELECT event_name, COUNT_STAR, SUM_TIMER_WAIT/1000000000000 AS total_s
FROM performance_schema.events_waits_summary_global_by_event_name
WHERE event_name LIKE 'wait/io/file/innodb/%'
ORDER BY SUM_TIMER_WAIT DESC
LIMIT 5;"
+----------------------------------------+------------+---------+
| event_name                             | COUNT_STAR | total_s |
+----------------------------------------+------------+---------+
| wait/io/file/innodb/innodb_log_file    |    8421132 |  912.21 |
| wait/io/file/innodb/innodb_data_file   |   20122341 |  311.45 |
| wait/io/file/innodb/innodb_temp_file   |    1023311 |   88.17 |
+----------------------------------------+------------+---------+

Що це означає: Сильні чекання на log file вказують на fsync/логовий тиск. Чекання на data file — на I/O-залежність читань/записів.

Рішення: Якщо домінують чекання на лог, перегляньте розмір транзакцій, налаштування durability і розмір redo log. Якщо домінують чекання на дані, гляньте на hit rate buffer pool і плани запитів.

Завдання 7: Перевірити ефективність InnoDB buffer pool

cr0x@server:~$ mysql -e "SHOW GLOBAL STATUS LIKE 'Innodb_buffer_pool_read%';"
+---------------------------------------+-----------+
| Variable_name                         | Value     |
+---------------------------------------+-----------+
| Innodb_buffer_pool_read_requests      | 987654321 |
| Innodb_buffer_pool_reads              | 12345678  |
+---------------------------------------+-----------+

Що це означає: Співвідношення read_requests до reads дає приблизний коефіцієнт промахів кеша. На VPS промахи коштують дорого через сховище.

Рішення: Якщо промахів багато і пам’ять доступна — збільште buffer pool. Якщо пам’яті немає — виправляйте запити/індекси і зменшуйте робочий набір.

Завдання 8: Знайти найгірші запити за загальним часом

cr0x@server:~$ mysql -e "SELECT DIGEST_TEXT, COUNT_STAR, ROUND(SUM_TIMER_WAIT/1e12,2) AS total_s, ROUND(AVG_TIMER_WAIT/1e9,2) AS avg_ms
FROM performance_schema.events_statements_summary_by_digest
ORDER BY SUM_TIMER_WAIT DESC
LIMIT 3\G"
*************************** 1. row ***************************
DIGEST_TEXT: SELECT * FROM orders WHERE user_id = ? ORDER BY created_at DESC LIMIT ?
COUNT_STAR: 1243321
total_s: 812.44
avg_ms: 0.65

Що це означає: Запит дешевий у середньому за виклик, але домінує за часом через обсяг. Це історія про пулінг і індексацію, а не про «більший сервер».

Рішення: Переконайтеся в наявності коректного складеного індексу (user_id, created_at). Розгляньте кешування на рівні додатку. Додайте пулінг, щоб уникнути накладних витрат підключень при високому QPS.

Завдання 9: Швидко знайти блокування

cr0x@server:~$ mysql -e "SHOW ENGINE INNODB STATUS\G"
TRANSACTIONS
------------
Trx id counter 123456789
Purge done for trx's n:o < 123456700 undo n:o < 0 state: running
History list length 9821

LATEST DETECTED DEADLOCK
------------------------
*** (1) TRANSACTION:
... WAITING FOR THIS LOCK TO BE GRANTED:
RECORD LOCKS space id 123 page no 456 n bits 72 index PRIMARY of table `app`.`accounts` trx id 123456780 lock_mode X locks rec but not gap waiting

Що це означає: Deadlock-и і чекання свідчать про конфліктні записи або довгі транзакції, що утримують блокування.

Рішення: Скоротіть транзакції, додайте правильні індекси і зробіть оновлення детермінованими. Якщо ORM виконує «select then update» патерни, виправте це.

Завдання 10: Перевірити статус реплікації (MySQL)

cr0x@replica:~$ mysql -e "SHOW REPLICA STATUS\G"
Replica_IO_Running: Yes
Replica_SQL_Running: Yes
Seconds_Behind_Source: 4
Last_SQL_Error:

Що це означає: Репліка здорова з невеликим лагом.

Рішення: Ви можете безпечно знімати читання/бекапи з репліки. Якщо лаг зростає — припиніть навантажувати її важкими читаннями і перевірте аплаєр/IO вузькі місця.

Завдання 11: Підтвердити зберігання binlog та тиск на диск

cr0x@server:~$ mysql -e "SHOW BINARY LOGS;"
+------------------+-----------+
| Log_name         | File_size |
+------------------+-----------+
| binlog.000231    | 1073741824|
| binlog.000232    | 1073741824|
| binlog.000233    | 1073741824|
+------------------+-----------+

Що це означає: Binlog-и великі і численні. На диску VPS binlog-и тихо можуть з’їсти кореневий файловий простір і перетворити гарний тиждень на цикл перезавантажень.

Рішення: Встановіть явну політику зберігання (expire settings), моніторте використання файлової системи і переконайтеся, що репліки не блокують видалення через офлайн-стан.

Завдання 12: Перевірити ємність файлової системи та виснаження inode

cr0x@server:~$ df -h /var/lib/mysql
Filesystem      Size  Used Avail Use% Mounted on
/dev/vda1       200G  186G   14G  94% /

Що це означає: Ви близькі до повного диска. MySQL почне поводитися неправильно задовго до 100%, бо йому потрібне місце для тимчасових таблиць, логів і відновлення після аварій.

Рішення: Звільніть місце зараз. Видаліть старі логи, перемістіть бекапи поза хост, збільшіть диск або зменшіть час зберігання. Якщо у бізнес-години ви вже на 94% — ви запізнилися.

Завдання 13: Перевірити тиск тимчасових таблиць (пам’ять vs диск)

cr0x@server:~$ mysql -e "SHOW GLOBAL STATUS LIKE 'Created_tmp%tables';"
+-------------------------+----------+
| Variable_name           | Value    |
+-------------------------+----------+
| Created_tmp_disk_tables | 842113   |
| Created_tmp_tables      | 902331   |
+-------------------------+----------+

Що це означає: Високе відношення tmp disk tables означає, що запити паркуються на диск. На VPS це податок на латентність.

Рішення: Додайте індекси, зменшіть розмір результатів, виправте GROUP BY/ORDER BY патерни і уникайте великих сортувань. Не «вирішуйте» це сліпим збільшенням tmp_table_size, поки не впевнені, що не досягнете OOM.

Завдання 14: Перевірити розміри таблиць/індексів, щоб зрозуміти робочий набір

cr0x@server:~$ mysql -e "SELECT table_schema, table_name,
ROUND((data_length+index_length)/1024/1024,1) AS mb
FROM information_schema.tables
WHERE table_schema='app'
ORDER BY (data_length+index_length) DESC
LIMIT 5;"
+-------------+----------------+------+
| table_schema| table_name     | mb   |
+-------------+----------------+------+
| app         | events         | 8420 |
| app         | orders         | 3120 |
| app         | users          | 980  |
+-------------+----------------+------+

Що це означає: Ваші найбільші таблиці визначають потреби buffer pool. Якщо «гарячий» набір не поміщається — ви завжди платитимете за I/O.

Рішення: Розділіть/архівуйте холоді дані, додайте зведені таблиці або винесіть аналітику окремо. Масштабування вгору не вирішить вічно зростаючий робочий набір на одному VPS.

Три корпоративні міні-історії з реального життя

Міні-історія 1: Інцидент через неправильне припущення

Вони запускали SaaS-додаток на одному 16 ГБ VM. Все працювало місяцями. З’явилася нова інтеграція, і команда припустила: «база може обробляти більше підключень; це ж просто параметр». Вони підняли max_connections і продовжили роботу.

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

Латентність зросла. Додаток робив ретраї. Це створило ще більше підключень. ОС почала свопити. Тепер кожен запит мав «особливу приправу» — page faults пам’яті. Інженери дивилися на графіки CPU і не розуміли, чому «додавання підключень» не додало пропускної здатності.

Виправлення не було героїчним тюнінгом. Вони ввели пулінг, зменшили max_connections до значення, яке машина могла реально витримати, і додали невеликий проксі-слой для поглинання сплесків. Далі з’явилася реплікація — не для читань, а щоб робити бекапи без того, щоб тягнути продакшен в кисіль.

Міні-історія 2: Оптимізація, що відкотилася

Інша компанія мала повільні звітні запити. Хтось вирішив, що найкраще — збільшити тимчасові таблиці і більше пам’яті для сортувань. Підняли session і global буфери агресивно: sort buffers, join buffers, temp table sizes. Звіти стали швидшими на стейджингу. Усі аплодували і відправили на продакшен.

Продакшен не впав миттєво. Він «впав чемно». Під конкурентністю кожне підключення могло виділяти великі шматки пам’яті. Сотні підключень помножені на «розумні» пер-канекшн буфери стали «сюрприз, у вас закінчилась пам’ять». Сервер почав свопити. Потім база вдарилася у стіну зависань: I/O злетів, fsync-и в черзі, а час відгуку прагнув до нескінченності.

Команда ганялася за привидами: мережа? провайдер? ядро? Насправді вони перетворили контрольований бюджет пам’яті на рулетку пер-канекшн алокацій.

Откат був принижувальним: зменшили буфери на підключення, використали правильні індекси, переписали звіти і винесли важку звітність на репліку. Вони також усвідомили просту істину: на малих хостах передбачувані обмеження ресурсів краще за «швидко коли сам» кожного разу.

Міні-історія 3: Нудна, але правильна практика, що врятувала день

Ще одна команда тримала MySQL з реплікою в іншому регіоні. Нічого особливого: асинхронна реплікація, щоденні логічні бекапи і щотижневий тест відновлення. Ніхто не хвалився цим на зустрічах, бо це було занадто нудно, щоб вражати.

Потім у них стався інцидент зі сховищем на primary VPS. Файлова система стала лише для читання посеред робочого дня. База зробила те, що роблять бази в такому стані: поскаржилася, перестала просувати транзакції і залишила всіх вибирати між простоєм і поганими рішеннями.

Вони не панікували і не почали тюнити. Вони підняли репліку згідно з відпрацьованим рукописом, перелаштували додаток на новий primary через пулер і вивели старий primary з ротації. Сервіс дещо деградував; він не впав. Пізніше вони перебудували старий ноду з нуля і чисто пересіяли дані.

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

Поширені помилки: симптом → причина → виправлення

Саме тут більшість розгортань баз на VPS з 16 ГБ гине: не від однієї великої помилки, а від кількох операційних непорозумінь.

1) Симптом: раптове зростання латентності після деплою

Причина: шторм підключень (нові поди додатку стартують, кожен відкриває пул; або пулінг вимкнений і підключення створюються на запит).

Виправлення: застосуйте пулінг, обмежте конкуренцію на проксі, налаштуйте wait_timeout/interactive_timeout належно і тримайте max_connections реалістичним. Якщо використовуєте ProxySQL, налаштуйте мультиплексування уважно і протестуйте з вашими транзакційними патернами.

2) Симптом: CPU високий, QPS на місці, «Threads_running» високий

Причина: занадто багато конкурентних запитів, блокування або регрес плану запиту, що викликає дорогі скани.

Виправлення: визначте топ-digest-и, додайте індекси, зменшіть конкуренцію через пулінг і виправте довгі транзакції. Не «вирішуйте» підняттям CPU, поки не з’ясуєте, чому потоки виконуються.

3) Симптом: load average величезний, але CPU не повністю зайнятий

Причина: I/O wait або блоковані потоки (fsync-перекоси, jitter диска, metadata locks).

Виправлення: використайте iostat -x, перевірте чекання Performance Schema і шукайте довгі DDL або беккап-операції на primary. Виносьте бекапи і важкі читання на репліку.

4) Симптом: затримка репліки зростає під час піку

Причина: I/O вузьке місце репліки, одно-поточний аплаєр, або важкі читання, що відбирають ресурси.

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

5) Симптом: помилки «Too many connections» хоча сервер здається простим

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

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

6) Симптом: періодичні зупинки кожні кілька хвилин

Причина: контрольні точки або flush-стали, переливи в тимчасові таблиці, або фонові завдання, що роблять сплески.

Виправлення: згладьте записову роботу, перевірте поведінку dirty pages, уникайте великих транзакцій і розкладіть батч-джоби. На VPS сховище карає великі сплески латентністю.

Чеклісти / покроковий план

Крок за кроком: зробіть пулінг реальністю на VPS з 16 ГБ

  1. Інвентаризація клієнтів: перелічіть всі сервіси/джоби, що підключаються до БД (додаток, воркери, cron, BI-інструменти).
  2. Спочатку виправте пулінг у додатку: встановіть явний розмір пулу, max lifetime і idle timeout. Уникайте «необмежених пулів».
  3. Поставте проксі/пулер, коли у вас є кілька нод додатку або непередбачувані сплески.
  4. Встановіть server max_connections на число, яке хост може дозволити. Це запобіжник, а не ручка продуктивності.
  5. Налаштуйте таймаути, щоб вбивати ідл-підключення і завислі сесії.
  6. Моніторте Threads_created, Threads_connected, aborted connects. Бажані — стабільні, нудні графіки.

Крок за кроком: додайте реплікацію, не перетворіть це на хобі

  1. Виберіть топологію: один primary + одна репліка — базова конфігурація. Тримайте просто.
  2. Розмістіть репліку в окремій домені відмови: інший VPS хост, бажано інша зона провайдера.
  3. Увімкніть binary logging і встановіть зберігання відповідно до потреб відновлення та розміру диска.
  4. Засійте репліку правильно: використайте консистентний знімок (фізичний бекап-інструмент або логічний дамп з правильними lock/GTID-параметрами).
  5. Переконайтеся в здоров’ї реплікації і налаштуйте алерти на lag та помилки.
  6. Напишіть і відрепетируйте кроки промоції. Повторіть тест при оновленнях версій.
  7. Перенесіть бекапи і важкі читання на репліку. Тримайте фейловер-репліку чистою і не перевантаженою.

Крок за кроком: налаштуйте InnoDB для VPS з 16 ГБ без самонанесення шкоди

  1. Правильно розмірюйте buffer pool виходячи з пам’яті вільної і робочого набору. Не позбавляйте повністю OS cache.
  2. Тримайте пер-канекшн буфери помірними. Глобальні буфери безпечніші за сюрпризи per-connection.
  3. Слідкуйте за переливом тимчасових таблиць і виправляйте запити перед тим, як роздувати ліміти пам’яті.
  4. Підтвердіть налаштування durability відповідно до бізнес-вимог. Не копіюйте небезпечні налаштування тільки, щоб виграти бенчмарки.
  5. Міряйте, міняйте одне і знову міряйте. «Тюнінг», що змінює 30 параметрів одразу, — шлях до створення таємниць.

FAQ

1) Що обрати: MySQL чи MariaDB для одного VPS з 16 ГБ?

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

2) Коли пулінг підключень справді обов’язковий?

Коли у вас є сплески, багато інстансів додатку або короткі запити на високому QPS. Якщо ви бачите churn потоків (Threads_created швидко зростає) або шторм підключень під час деплоїв — це вже обов’язково.

3) Чи можна просто підняти max_connections замість пулінгу?

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

4) Реплікація лише для масштабування читань?

Ні. На VPS реплікація перш за все для відновлення, бекапів і обслуговування. Масштабування читань — приємний побічний ефект, а не основна мотивація.

5) Асинхронна реплікація ризикована. Чи варто використовувати semi-sync?

Можливо. Semi-sync може зменшити втрату даних при падінні primary, але на VPS це може додати хвостової латентності. Вибирайте за RPO і стабільністю мережі, а потім тестуйте під навантаженням.

6) Чому моя репліка відстає під час звітів?

Тому що читання конкурують з аплаєром реплікації за CPU і I/O. Якщо репліка планується як target для фейловера, тримайте важку звітність подалі від неї або забезпечте окрему аналітичну репліку.

7) Який перший метрик дивитися на малому DB-хості?

Латентність диска (iostat await / utilization) і тиск пам’яті (активність свопу). Графіки CPU можуть вводити в оману, коли реальний вузький момент — I/O wait або свопінг.

8) Galera (MariaDB) — хороша ідея на VPS?

Може працювати, але це не безкоштовний обід. Синхронно-подібна координація записів може бити по латентності, а ризики split-brain зростають, якщо кворум спроектований неправильно. Якщо ви не готові оперувати кластером — спочатку робіть primary+replica.

9) Чи потрібен ProxySQL, якщо додаток вже має пул?

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

10) Яке найшвидше безпечне покращення, яке можна зробити цього місяця?

Додайте репліку для бекапів і відпрацьованого фейловера, і впровадьте пулінг підключень з суворими лімітами. Ці два кроки запобігають найбільш поширеним інцидентам «один VPS розплавився».

Висновок: що зробити наступного тижня

Якщо ви на VPS з 16 ГБ, у вас немає розкоші неакуратної конкуренції. Також у вас немає розкоші думати «ми додамо реплікацію пізніше». «Пізніше» — це коли ви відновлюєтеся з бекапу, а ваш CEO дізнається нові слова.

Практичні кроки:

  1. Впровадьте пулінг (на рівні додатку негайно; додайте проксі, якщо у вас є кілька нод додатку або сплески трафіку).
  2. Встановіть реалістичні ліміти підключень і таймаути; ставте max_connections як запобіжник.
  3. Додайте репліку на окремому VPS і перенесіть туди бекапи/звітність.
  4. Напишіть runbook для фейловера і відрепетируйте його у робочий час з захисними механізмами.
  5. Проведіть швидку діагностику під час наступного сплеску латентності і документуйте висновки.

MySQL проти MariaDB самі по собі не врятують вас. Реплікація і пулінг — врятують. Оберіть ту СУБД, яку ваша команда вміє спокійно експлуатувати о 2:00 ночі, а потім інженеруйте систему так, щоб 2:00 ночі залишались нудними.

← Попередня
Ubuntu 24.04 Watchdog-скидання: виявляйте мовчазні зависання, поки вони не вкрали ваш час роботи (випадок №18)
Наступна →
Контрольний список безпеки Proxmox: 2FA, RBAC, брандмауер, оновлення та безпечний віддалений доступ

Залишити коментар