Налаштування MySQL Connection Pooling через MaxScale (MariaDB)

Пікове навантаження рве з'єднання, а застосунок іде в черги та таймаути. Ми налаштовуємо MaxScale під ключ: знімаємо заміри, підбираємо схему пулу та балансування під ваш профіль запитів. Пул перестає впиратися в ліміти, відмови на піку зникають, а конфігурації та регламенти передаємо вашій команді.
Часті запитання

Налаштування MaxScale: де рветься пул з'єднань до MySQL

Типова картина виглядає так: застосунок відкриває з'єднання під кожен запит і закриває одразу після відповіді — на піку це сотні коротких сесій за секунду.

Бекенд впирається в max_connections, заповнюється черга очікування на вході, частина запитів повертається відмовою, а обробники застосунку тримають потоки в очікуванні звільненого слота. Зовні це виглядає як «база гальмує», хоча вузьке місце — не запити, а їх доставка до сервера.

Підняти max_connections — шлях у глухий кут. Кожне з'єднання резервує пам'ять під стек потоку та буфери сортування і з'єднань, тому ліміт упирається в пам'ять раніше, ніж у процесор, а перемикання контексту між сотнями активних потоків з'їдає виграш.

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

MaxScale стає між застосунком і MySQL як проксі-шар і перевикористовує бекенд-з'єднання: у простої клієнтські сесії поділяють одні й ті самі підключення до сервера, а не займають своє.

Параметр max_connections у секції service задає, скільки з'єднань до бекенду проксі тримає одночасно, multiplex_timeout — скільки він чекає перед поверненням звільненого підключення до загального набору.

Налаштування MaxScale зводиться до того, щоб черги з'єднань формувалися на вході в проксі, де їх можна виміряти, а не у вигляді відмов усередині бази.

Окремо синхронізуємо таймаути: wait_timeout і back_log на сервері мають бути не коротшими за connection_timeout і multiplex_timeout у проксі, інакше MaxScale віддає з'єднання, яке бекенд уже закрив, і клієнт отримує помилку на рівному місці. Розбираємо, як це налаштовується.

Що дає керований пул з'єднань на практиці

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

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

База бачить рівний потік і в спокійні години, і на піку — сходинка із сотень одночасних підключень зникає.

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

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

Перевіряти результат варто за трьома числами — скільки з'єднань база бачить на піку, скільки триває перемикання, скільки помилок підключення залишилося за добу. MaxScale закриває всі ці пункти на рівні проксі, без змін у коді застосунків.

Варіанти балансування та режими маршрутизації запитів

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

У MaxScale це роблять модулі: readwritesplit розбирає тип запиту і відводить читання з реплік, readconnroute роздає з'єднання цілком, hintrouter дозволяє застосунку задати ціль прямо в коментарі до запиту.

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

Варіант Коли підходить Обмеження
Зовнішній пул з'єднань у проксі Різнорідні застосунки, багато коротких підключень Додатковий мережевий перехід; перевіряти сумісність із підготовленими виразами
Пул у драйвері застосунку Один застосунок, стабільне навантаження, важлива мінімальна затримка Ліміти рахуються на процес, немає спільного перерозподілу
Проксі на рівні застосунку Потрібні власні правила маршрутизації Власна підтримка й тести, відставання від змін у СУБД
Пряме підключення до реплік Мало вузлів, немає жорстких вимог до свіжості даних Відставання реплік і перемикання при відмові — на боці коду

На практиці режими комбінують: запис іде на мастер, звітні вибірки — на репліки, а запити, чутливі до свіжості даних, адресують мастеру явною вказівкою.

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

Етапи налаштування MaxScale: від аудиту навантаження до передачі

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

  1. Аудит навантаження бази. Знімаємо реальний профіль з'єднань: піки за добу й тиждень, розподіл за застосунками, частка коротких і довгих сесій. На виході — обґрунтований розмір пулу замість значення «на око».
  2. Схема маршрутизації. У MaxScale розділяємо потоки на читання й запис, визначаємо склад реплік і ознаку, за якою вузол виводиться з ротації при відставанні. Схема фіксується до правок конфігурації.
  3. Налаштування лімітів. Задаємо межу одночасних з'єднань на вузол, час утримання простоюючої сесії та поведінку при переповненні — черга з обмеженням або швидка відмова.
  4. Копія бойового контуру. Стенд повторює топологію та ролі вузлів, тому результати перевірок переносяться на бойову систему без поправок.
  5. Перевірка під навантаженням. Проганяємо знятий профіль і окремо ламаємо систему: гасимо репліку, перезапускаємо вузол, рвемо з'єднання на середині запиту. Дивимося тривалість відмови та швидкість повернення трафіку.
  6. Передача в експлуатацію. Віддаємо метрики пулу й відмов, пороги оповіщень, регламент планових перемикань і порядок відкату на попередню схему.

Етап закрито не після запуску, а після того, як чергова зміна провела за нашою схемою планове перемикання.

Що передаємо на руки: конфігурації, схеми, регламенти

Проєкт закривається не звітом про виконану роботу, а набором артефактів, за якими ваша команда експлуатує пул з'єднань без нашої участі.

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

  • Робочі конфігурації пулу з'єднань — файли сервісів і слухачів із лімітами з'єднань, таймаутами очікування та поведінкою при вичерпанні пулу; параметри прокоментовано, щоб значення змінювалося усвідомлено.
  • Схеми маршрутизації — які вузли приймають запис, які читання, як розподіляються запити між репліками і що відбувається, коли репліка відстає або випадає.
  • Правила доступу до бази — окремі облікові записи під кожен сервіс, розділення прав на читання й запис, ротація паролів і порядок видачі доступу новому сервісу.
  • Каталог типових збоїв — «пул вичерпано», «вузол випав із кластера», «репліка відстала»: симптом, імовірна причина, дія чергового, ознака відновлення.
  • Інструкції для чергової зміни — покрокові сценарії перевірки здоров'я вузлів, ручного перемикання на резерв і порядок ескалації, якщо сценарій не спрацював.
  • Регламент експлуатації — як змінювати ліміти пулу, коли розширювати кількість з'єднань, які метрики дивитися щодня і які пороги вважати тривожними.
  • Панель метрик і оповіщення — зайнятість пулу, кількість відмов підключення, затримка реплікації; оповіщення налаштовані на пороги, а не на факт падіння.

Конфігурації зберігаються в репозиторії з історією змін — відкат на попередній стан займає хвилини й не потребує розбору навпомацки.

Розбір впровадження: пік навантаження та черги з'єднань

Клієнт — платіжний сервіс із нерівномірним трафіком: до вечора та в дні акцій одночасних користувачів ставало втричі більше.

Застосунок тримав з'єднання з базою напряму, у кожного екземпляра був свій пул, і на піку до сервера відкривалося до дев'ятисот з'єднань при стелі в п'ятсот.

Очікування слота сягало чотирьох секунд, частина запитів обривалася за таймаутом, а про проблему черговий дізнавався від користувачів.

Ми винесли управління з'єднаннями на окремий шар — MariaDB MaxScale у режимі читання-запису: застосунки ходять до проксі, а він тримає спільний пул до бази, розділяючи вхідні сесії та реальні з'єднання.

З'єднання перевикористовуються між запитами, зайві закриваються за простоєм, а не висять до перезапуску застосунку.

Метрики до і після

Показник До Після
З'єднань до бази на піку ~900 120
Очікування слота підключення до 4 секунд десяті частки секунди
Запити, обірвані за таймаутом 6-7% менше 0,1%
Відмова вузла бази ручне перемикання автоматично, за секунди

Відмову вузла перевіряли окремо: гасили репліку під навантаженням. Проксі зняв її з балансування, живі сесії перерозподілилися — застосунок не побачив розриву, ручних перемикань і повторів запитів не знадобилося.

Чим мультиплексування відрізняється від пулу з'єднань у коді?

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

Мультиплексування з'єднань працює на іншому рівні — між застосунком і базою. Проксі, у нашому випадку MaxScale, тримає власний набір сесій до сервера і розподіляє їх між клієнтськими підключеннями.

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

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

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

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

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

Часті технічні питання щодо пулу з'єднань

Пул з'єднань здається простим, поки вузол не відвалюється на середині транзакції. Сумніви зазвичай не про сам пул, а про поведінку при відмові та при перемиканні запису на репліку.

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

Що відбувається з відкритою транзакцією, якщо вузол перестав відповідати?

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

Чи потрібно змінювати код застосунку?

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

Як читання йде на репліки?

Правилом маршрутизації: запис іде на мастер, читання — на репліки. Окремо налаштовуємо поведінку при відставанні репліки, щоб після запису застосунок не отримав застарілі дані.

Як діагностувати залишкові з'єднання та черги?

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

Чи можна відкотити зміни?

Конфігурація лежить у системі контролю версій: повернення до попереднього набору правил — одна команда, без перезапуску застосунку.

Обговоримо задачу: підберемо схему пулу під ваше навантаження

Пул з'єднань — це не один параметр, а вибір схеми: як трафік розподіляється між мастером і репліками, що робити з транзакціями та довгими запитами, як поводиться застосунок при відмові вузла.

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

Що надіслати для первинного розбору:

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

Ми уточнюємо підбір схеми маршрутизації: розділення читання й запису, балансування з'єднань, закріплення сесії за вузлом, таймаути та поведінку при відмові мастера.

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

Далі — супровід бази: моніторинг метрик пулу та планові зміни під зростання навантаження. Опишіть задачу — повернемося з оцінкою та планом.

Наші компетенції:

Останні роботи

  • Розробка сайту компанії B2B ADVANCE
    Розробка сайту компанії B2B ADVANCE
    1542
  • Розробка веб-додатків для компанії FEEDME
    Розробка веб-додатків для компанії FEEDME
    1394
  • Розробка веб-сайту для компанії БЕЛФІНГРУП
    Розробка веб-сайту для компанії БЕЛФІНГРУП
    1081
  • Розробка інтернет магазину для компанії FURNORO
    Розробка інтернет магазину для компанії FURNORO
    1369
  • Розробка логотипу компанії B2B Advance
    Розробка логотипу компанії B2B Advance
    816
  • Розробка веб-додатків для компанії Enviok
    Розробка веб-додатків для компанії Enviok
    1141