Перевантаження з'єднаннями: коли ProxySQL обов'язковий
Застосунок рідко економить на з'єднаннях: типовий сценарій — відкрити підключення на один-два запити й закрити. Поки звернень десятки, це непомітно; на піку їх сотні, і база впирається в ліміт з'єднань.
Далі запускається ланцюжок: частину спроб відбиває відмовою, частина стає в чергу на боці сервера, застосунок повторює невдалі звернення й добиває ліміт остаточно.
Час відповіді в такій ситуації зростає не лінійно, а стрибками.
Поки є вільний обробник, відгук рівний; за порогом черга наростає швидше, ніж надходить трафік, і 95-й перцентиль іде вгору в рази за майже незмінної медіани — за графіком це виглядає як «база раптом стала повільною».
Вузьке місце при цьому не в процесорі й не в диску, а в постійному перестворенні підключень: на кожне витрачається узгодження, перевірка прав і виділення сесії.
Локальний пул усередині застосунку проблему не знімає: за горизонтального масштабування копії сервісів множать власний пул, і межа знову поруч. Тут і потрібен ProxySQL — шар між застосунком і базою.
Він тримає довгоживучі з'єднання до сервера, клієнтам віддає вже готові, розводить читання й запис, обмежує повтори, а замість відмови ставить запит у чергу з передбачуваним лімітом очікування.
Саме налаштування не зводиться до встановлення: потрібні правила маршрутизації, таймаути, розміри пулів під профіль навантаження та метрики, за якими видно, що межу відсунуто. Розбираємо, як це закривається.
Що дає керований пул з'єднань застосунку
Кожен робочий процес застосунку тримає власне з'єднання з базою. Поки їх десятки, це непомітно. Щойно застосунок масштабують під пікове навантаження, кількість процесів упирається в стелю з'єднань: запити чекають на відкриття каналу, і хвіст затримок зростає швидше, ніж трафік.
Керований пул з'єднань знімає цю зв'язку. Проміжний шар приймає тисячі клієнтських підключень і мультиплексує їх у невелику кількість постійних з'єднань до серверів бази: 2000 вхідних лягають на 40 вихідних.
Застосунок перестає залежати від ліміту на кількість процесів — під піком зростає пропускна здатність, а стабільний час відповіді лишається в тих самих межах, що й на спокійному навантаженні.
Розгортаємо ProxySQL і налаштовуємо правила маршрутизації: читання йдуть на репліки, запис — на мастер, з'єднання перевикористовуються між запитами. Доступність вузлів перевіряється постійно, тому перемикання за відмови займає секунди й не потребує втручання в код застосунку.
Клієнтські з'єднання за короткого збою вузла не рвуться — перепідключення робить пул, а не застосунок, і тимчасові помилки не долітають до користувача.
Ефект підтверджуємо метриками: частка запитів, обслужених без очікування з'єднання, час відповіді за перцентилями до й після піку, глибина черги та кількість перемикань за відмови.
Порівняння режимів маршрутизації запитів
Маршрутизація читання й запису вирішується на одному з чотирьох рівнів — від проміжного шару перед базою до явного вибору з'єднання в коді. Рівень визначає, де живе логіка розведення трафіку і скільки коду доведеться змінювати за зміни топології. Нижче — умови застосовності та обмеження кожного варіанта.
Проміжний шар на кшталт ProxySQL стає між застосунком і базою: застосунок бачить одну адресу, а шар тримає пул, стежить за станом вузлів і сам розводить читання й запис. Це шлях із найменшими правками в коді, коли сервісів кілька і мови різні.
| Варіант | Коли підходить | Обмеження |
|---|---|---|
| Проміжний шар перед базою | Кілька застосунків і мов, потрібен спільний пул і розведення читання й запису без змін у коді | Ще одна точка відмови та зайва ділянка мережі, потрібні власний моніторинг, оновлення й запас за з'єднаннями |
| Вбудований пул у застосунку | Один сервіс із передбачуваним навантаженням, пул живе в межах процесу | За масштабування кількість з'єднань зростає кратно, ліміти бази рахують вручну, відмову вузла обробляє код |
| Пул на боці драйвера | Застосунок уже працює з базою напряму, потрібне перевикористання з'єднань і перевірка доступності | Маршрутизацію читання й запису драйвер не робить, перемикання за відмови вузла лишається на застосунку |
| Ручний розподіл | Разові завдання: міграції, звіти, вивантаження на конкретний вузол | Не масштабується, логіка розповзається по коду, помилку у виборі вузла видно лише на реальному навантаженні |
На практиці варіанти комбінують: проміжний шар тримає спільний пул і розведення трафіку, вбудований пул згладжує сплески всередині процесу. Ручний розподіл лишають для разових робіт — як виняток, а не як постійну схему.
Як ми впроваджуємо пул з'єднань: етапи робіт
ProxySQL перед базою — не «поставили й забули». Порядок робіт визначає, чи переживе база пік без зростання помилок і без правок у коді застосунку. Помилка в послідовності майже завжди вилазить на проді: пул є, а з'єднання все одно впираються в ліміт ведучого вузла. Розбираємо, як будуємо роботу.
-
Зняття метрик і профілю навантаження. З бойових серверів збираємо статистику: скільки з'єднань відкривається і скільки живе, які запити домінують, де зростає час очікування. Це база для порівняння «до і після» — без неї налаштування перетворюється на вгадування.
-
Проєктування схеми маршрутизації. Визначаємо, що йде на ведучий вузол, що на репліки і як поводиться застосунок, якщо репліка відстає. Точки відмови та порядок перемикання фіксуємо на схемі заздалегідь.
-
Налаштування пулу й правил перезапису запитів. Задаємо межі пулу за користувачем і базою, час життя з'єднань, кількість серверних підключень на одне клієнтське.
Правила перезапису приводять різні запити до одного вигляду — зростає частка влучань у кеш, навантаження на сервери падає.
-
Перевірка під навантаженням. Повторюємо на стенді профіль з першого етапу і окремо ламаємо вузол: дивимося, як швидко перебудовується маршрутизація і чи зростають помилки в застосунку. Правила правимо за цифрами, а не за відчуттями.
-
Введення в роботу. Вмикаємо поступово — спочатку частка трафіку, потім увесь, зі спостереженням за затримками та кількістю з'єднань. Шлях відключення лишається: трафік можна повернути напряму, якщо метрики вийдуть за межі.
-
Передача й навчання. Віддаємо конфігурації, схему, правила та розбір статистики: як читати стан пулу і що змінювати за зростання навантаження. Команда має сама додати правило або розширити пул.
Політики доступу, конфігурації та регламенти
Перед введенням пулу з'єднань в експлуатацію замовник отримує пакет артефактів, за яким систему можна обслуговувати, передавати між змінами й відновлювати після збою. Нижче — обов'язковий мінімум: без нього проксі ProxySQL живе на ручних правках у момент інциденту.
- Файли конфігурації. Основний конфіг і перевизначення за бекендами, розкладені за контурами та під версійним контролем, з описом: який параметр за що відповідає і що зміниться за його правки.
- Схеми потоків. Шлях запиту від застосунку через проксі до реплік: правила розділення читання й запису, розбір запитів, поведінка за відмови вузла.
- Облікові записи й права. Роздільні користувачі для застосунку, моніторингу й адміністрування, мінімально необхідні привілеї, прив'язка до правил маршрутизації; секрети — у сховищі, не у файлі на диску.
- Ліміти з'єднань. Межі на пул, користувача, хост і бекенд з обґрунтуванням кожної: за якого сценарію вона досягається і як система деградує далі.
- Політики доступу. Хто і з яких мереж потрапляє в адміністративний інтерфейс, що застосовується до клієнтських запитів, чим закрито зовнішній периметр.
- Регламент обслуговування й чергувань. Порядок правки правил і лімітів, перезавантаження конфігурації без обриву живих з'єднань, вікна робіт, точки відкату та інструкція черговому: що дивитися і що робити першим.
Документи актуалізуємо разом з конфігурацією — за наступної зміни топології логіку не відновлюють з пам'яті.
Кейс: як зросла пропускна здатність бази
Служба з нерівномірним потоком: у ранкові та вечірні години пік кількість одночасних звернень до бази зростала кратно, між ними навантаження падало майже до нуля.
Кожен робочий процес тримав своє з'єднання з MySQL, і застосунок упирався в стелю за їхньою кількістю: додати процеси було не можна — база починала деградувати за всіма запитами одразу.
До: час відповіді зростав разом із навантаженням
У години пік час відповіді на 95-му перцентилі зростав утричі проти спокійних годин, частина запитів ішла в таймаут. Головний клас відмов — з'єднання закінчувалися, нові запити ставали в чергу й падали з помилкою встановлення зв'язку.
Пропускна здатність зростала разом із кількістю процесів лише до певної точки, далі зростав тільки час відповіді.
Після: рівна лінія на піку
Між застосунком і базою став ProxySQL — проксійний шар із власним пулом з'єднань, який перевикористовує їх між робочими процесами.
Правила маршрутизації розділили читання й запис, аналітичні запити пішли на репліку, а health-check виводив проблемний вузол із ротації до того, як на ньому накопичувалися помилки.
Час відповіді в години пік перестав роз'їжджатися з навантаженням: лінія 95-го перцентиля стала рівною й близькою до спокійних годин.
Пропускна здатність зросла кратно на тому самому обладнанні, стелю за кількістю процесів знято, відмови класу «з'єднання закінчилися» в спостереженнях більше не повторювалися.
Чим ProxySQL відрізняється від пулу всередині застосунку
Вбудований пул живе всередині процесу застосунку: з'єднання відкриваються за першого запиту, повертаються в локальний набір і перевикористовуються наступним викликом. Поки сервіс один, цього достатньо — накладні витрати на встановлення з'єднання не повторюються на кожен запит.
Проблема починається за горизонтального масштабування: кожна копія застосунку тримає власний набір, і кількість з'єднань до бази зростає разом із кількістю копій, а не разом із реальним навантаженням.
Окремий шар перед базою змінює схему. Застосунок більше не тримає довгоживучих з'єднань — він віддає короткі сесії, а спільні з'єднання до сервера баз даних підтримує проміжний вузол із фіксованим розміром набору.
Десять копій сервісу і один вузол дають передбачувану кількість підключень, яка не залежить від того, скільки екземплярів ви підняли цієї миті. Заодно знімається біль із перезапусками: за оновлення застосунку з'єднання до бази не рвуться й не перестворюються лавиною.
Друга відмінність — незалежність від мови. Вбудований пул налаштовується засобами конкретної бібліотеки доступу до даних, і в кожного стека свої параметри, свої таймаути й своя поведінка за обриву.
Проміжний шар стоїть на мережевому рівні, тому сервіси різними мовами ходять через один і той самий вхід з однаковими правилами.
Третя — єдина точка правил. Маршрутизація читання на репліки, розрив довгих запитів, пріоритет фонових завдань, обмеження частоти звернень — усе описується в одному конфігураційному файлі, а не дублюється в коді кожного сервісу. Це помітно спрощує розбір інцидентів: видно, чий запит і куди він пішов.
Практичний висновок: вбудований пул розумний як локальний кеш з'єднань усередині екземпляра, а окремий шар потрібен, коли сервісів більше одного і правила роботи з базою мають бути спільними. ProxySQL у цій ролі закриває обидва сценарії — і перевикористання з'єднань, і централізацію правил.
Технічні сумніви: питання щодо налаштування пулу
Сумніви перед увімкненням ProxySQL зазвичай одні й ті самі: що буде за відмови вузла, чи потрібні правки в коді, чи витримає пул сплеск. Нижче — короткі відповіді; на розборі задачі ми перевіряємо кожен пункт на вашій схемі реплікації.
Що відбувається, коли вузол бази перестає відповідати?
Пул перевіряє доступність вузлів і прибирає той, що відмовив, з видачі, запит іде на живий. Незавершене з'єднання закривається й не повертається в пул, клієнт отримує помилку замість завислого відгуку; граничний час очікування й кількість спроб задаються явно.
Чи потрібно правити код застосунків?
Застосунок підключається до пулу як до звичайного сервера — змінюється лише адреса в налаштуваннях підключення. Правки потрібні там, де в коді зашиті адреси конкретних вузлів або власна логіка вибору репліки: її ми переносимо на рівень пулу.
Чи витримає пул сплеск навантаження?
З'єднання перевикористовуються, тому зростання кількості клієнтів не дає лавину підключень до бази. На сплеску вмикається черга на вході та ліміт одночасних з'єднань на вузол: надлишкові запити чекають, а не добивають сервер.
Як ділиться читання й запис?
Вибірки йдуть на репліки, записи та все всередині транзакцій — на ведучий вузол. Вибірки з блокуванням розпізнаються як змінювальні й теж ідуть на ведучий вузол, тому застосунок не отримує застарілих даних.
Чи можна обмежити доступ?
Облікові записи й права видаються на рівні пулу, а прямий доступ до портів бази закривається на міжмережевому екрані. У журналі видно, хто і який запит надіслав — розбір інцидентів помітно спрощується.
Обговоримо задачу й повернемося з оцінкою та планом
Для предметного розбору достатньо того, що вже є під рукою: схема контуру, конфіги та статистика за показовий період. Чим ближчі надіслані дані до реального трафіку, тим точніша оцінка й план — без здогадів і «на око».
З вашого боку корисно надіслати:
- схему поточного контуру: застосунки, бекенди, точки входу в базу та шляхи трафіку;
- поточні конфіги проксі та правила маршрутизації, включно з роздачею прав і розділенням читальних і пишечих вузлів;
- вивантаження статистики за період із помітним навантаженням: піки з'єднань, частка відмов, час очікування в черзі;
- перелік відомих точок зростання — що вже ламалося, де ліміти піднімали вручну;
- обмеження: вікна обслуговування, вимоги до відкату, порядок узгодження змін.
За підсумками розбору ви отримуєте оцінку та план: цільову схему пулу, порядок робіт за етапами, критерії приймання й набір перевірок, які показують результат до виведення в бойовий контур.
Перемикання плануємо без зупинки сервісу — спочатку налаштовуємо ProxySQL на копії контуру, проганяємо навантаження, потім переносимо на робочий.
Опишіть задачу й надішліть те, що є, — повернемося з оцінкою та планом.







