Зачем вообще Thread Pool в MariaDB
Классическая модель MySQL/MariaDB — один поток ОС на одно активное соединение. При росте числа одновременных клиентов (сотни и тысячи) это выливается в море контекстных переключений, рост накладных расходов планировщика, конкуренцию за CPU и ухудшение предсказуемости задержек. Плагин Thread Pool меняет модель: много соединений мультиплексируются поверх ограниченного числа рабочих потоков. Итог — меньше активных нитей, стабильнее задержки, лучше утилизация CPU при типичных OLTP-нагрузках.
Важно понимать: Thread Pool — не волшебная кнопка. Он помогает при высокой степени конкуренции коротких/средних запросов (InnoDB, транзакции), но почти не ускоряет долгие аналитические запросы и не лечит блокировки на уровне данных. Правильный тюнинг и здравые ожидания — обязательны.
Как это работает в общих чертах
Плагин создаёт несколько групп потоков. Соединения распределяются по группам, а внутри каждой группы планировщик решает, сколько рабочих потоков реально держать активными. Ключевая идея — удерживать число одновременно работающих потоков на уровне, который соответствует возможностям CPU и подсистемы хранения, а остальным соединениям давать подождать очереди, чтобы не заглушить систему перегревом.
Несколько понятий, которые пригодятся при тюнинге:
- Размер пула/групп — сколько независимых групп потоков существует. Чаще всего его соотносят с числом доступных CPU (ядер/аппаратных потоков).
- Oversubscribe — насколько планировщик готов превышать «идеальное» число одновременно работающих потоков в группе, чтобы сгладить пики.
- Приоритеты — режим, в котором короткие транзакции получают повышенный приоритет, чтобы снижать латентность под смешанной нагрузкой.
- Stall limit — защита от «залипания» рабочих нитей на долгих запросах; помогает планировщику вовремя отдавать квоту другим.
Когда Thread Pool реально помогает
Типичные сценарии, где эффект заметен:
- Высококонкурентный OLTP (много коротких InnoDB-запросов, частые транзакции, пики в десятки/сотни одновременных клиентов).
- Нагрузочные профили, где узким местом становится переключение контекста и системные накладные расходы, а не диск/сеть.
- Серверы с большим количеством ядер, где «один поток на соединение» раскручивает активных нитей гораздо больше, чем позволяет эффективно загрузить CPU.
Сценарии, где прирост минимален или отсутствует:
- Небольшое число клиентов с очень тяжёлыми запросами (долгие сканы/агрегации).
- Блокировки на уровне строк/таблиц: Thread Pool не уменьшит время ожидания, если узкое место — конкуренция за данные.
- Когда приложение уже использует агрессивный connection pooling и держит мало одновременных активных запросов.

Подготовка: версия, окружение, замеры
Перед включением плагина убедитесь, что версия MariaDB поддерживает Thread Pool (поддержка присутствует в стабильных ветках уже много лет), а также что вы понимаете профиль нагрузки: количество одновременных запросов, средняя/95-процентиль задержка, CPU steal в виртуальной среде, структура индексов и горячие таблицы.
Соберите базовую метрику: до включения Thread Pool зафиксируйте p95/p99 задержки, TPS/QPS, план загрузки CPU по ядрам, длину очередей диска и частоту контекстных переключений. Так вы сможете объективно оценить эффект и быстро откатиться, если что-то пошло не так. Для компактных серверов пригодится материал с практическими настройками: тюнинг MySQL/MariaDB на малом VDS.
Установка и включение Thread Pool
В большинстве дистрибутивов плагин уже поставляется вместе с сервером MariaDB и включается командой SQL. Выполните от имени администратора:
-- загрузить плагин динамически (однократно до перезапуска)
INSTALL SONAME 'thread_pool';
-- проверить, что он активен
SHOW PLUGINS LIKE 'thread_pool';
-- посмотреть текущий режим обработки потоков
SHOW VARIABLES LIKE 'thread_handling';
Чтобы плагин загружался при каждом старте, добавьте в конфигурацию MariaDB (обычно /etc/mysql/mariadb.conf.d/50-server.cnf или /etc/my.cnf):
[mysqld]
plugin_load_add = thread_pool
# явное указание режима планирования потоков
thread_handling = pool-of-threads
Перезапустите сервер и убедитесь, что плагин активен. Если ваша поставка MariaDB разбита на под-пакеты, может понадобиться установить пакет с плагином из репозитория дистрибутива. Ошибки загрузки обычно видны в журнале MariaDB при старте.
Базовый тюнинг: параметры, которые действительно важны
Ниже — ключевые настройки, которые чаще всего дают эффект. Не все они обязаны быть изменены, но понимать их смысл полезно.
Размер пула: thread_pool_size
Определяет число групп потоков. Практическая отправная точка — соотнести значение с числом доступных CPU (ядер/аппаратных потоков) и характером нагрузки. Слишком малое значение создаёт очереди и растит задержки; слишком большое — размоет эффект и приблизит систему к модели «много активных нитей».
Подход: начните с значения, близкого к числу физических ядер (или к ограничению cgroups, если сервер запущен в контейнере), затем корректируйте по метрикам p95 задержки и утилизации CPU.
Превышение квоты: thread_pool_oversubscribe
Параметр определяет, насколько планировщик может запускать больше одного активного рабочего потока на группу, чтобы лучше переживать пики. Небольшое превышение помогает сгладить всплески без ухода в бесконтрольный рост активных нитей. Если значение завысить — снова придёте к лишним переключениям контекста и пилам по задержкам.
Защита от «залипания»: thread_pool_stall_limit
Указывает порог времени, после которого долго работающий запрос считается «подозрительным» с точки зрения планировщика. Это помогает не дать одной длинной операции «удушить» группу, когда много коротких запросов ждут своей очереди. Ставьте консервативно и тестируйте под своей нагрузкой.
Приоритеты коротких транзакций
Параметры thread_pool_high_priority_mode и родственные управляют повышением приоритета коротких транзакций (или первых запросов в транзакции), сокращая пользовательскую латентность под смешанной нагрузкой. Полезно в системах с большим количеством коротких операций записи/чтения, где очереди быстро растут.
Другие настройки пула
Имеются параметры, ограничивающие общее число рабочих нитей, таймауты простоя и прочие детали. Они пригодятся в узких сценариях или при отладке. Для начала достаточно сфокусироваться на размере пула, oversubscribe и приоритетах.
Примеры конфигурации
Стартовый профиль для типичного OLTP на InnoDB с десятками-сотнями одновременных клиентов и сервером на 8–16 физических ядер:
[mysqld]
plugin_load_add = thread_pool
thread_handling = pool-of-threads
# стартовая точка — близко к числу физических ядер
thread_pool_size = 12
# умеренное превышение квоты для сглаживания пиков
thread_pool_oversubscribe = 3
# консервативный порог «подозрительной» длительности
thread_pool_stall_limit = 50
# приоритет коротких транзакций
thread_pool_high_priority_mode = transactions
# значение подбирается экспериментально под вашу нагрузку
thread_pool_high_priority_tickets = 100
Замечание по динамике: часть параметров можно менять на лету через SET GLOBAL или SET PERSIST в современных версиях MariaDB. Если сервер ответит ошибкой «read only» — перенесите изменение в конфигурационный файл и перезапустите. В любом случае в проде безопаснее менять по одному параметру за раз и всегда иметь план отката.

Взаимодействие с InnoDB и системными настройками
Thread Pool — это планировщик запросов на уровне сервера, а не на уровне движка хранения. Чтобы не «двойным слоем» ограничивать параллелизм, держите innodb_thread_concurrency в нуле (без ограничения), если ранее вы его не поднимали сознательно под специфическую нагрузку. Параметры innodb_read_io_threads и innodb_write_io_threads настраиваются отдельно и зависят от подсистемы хранения; Thread Pool не заменяет их.
Не забывайте про общую гигиену: правильный размер буфера innodb_buffer_pool_size, настройки журналирования (innodb_flush_log_at_trx_commit, sync_binlog при включённом бинарном логе), индексы и планы запросов. Thread Pool не компенсирует отсутствие нужного индекса или слишком «широкие» выборки. Если используете кластер, помните про особенности репликации и восстановления: см. обзор по отказоустойчивости GTID/semisync и PITR с GTID в соседних материалах.
Как настраивать методично: пошаговая процедура
- Соберите базу: p95/p99 латентность, QPS/TPS, загрузка CPU по ядрам, длина очередей диска, контекстные переключения.
- Включите плагин без изменения параметров или с минимальным стартовым профилем. Убедитесь, что сервер стабилен, а подключений не меньше, чем до изменений.
- Подберите
thread_pool_size: шагами увеличивайте/уменьшайте и фиксируйте, как меняются латентность и утилизация CPU. Ищите точку, где p95 минимальна при приемлемом использовании CPU. - Подстройте
thread_pool_oversubscribe: небольшое повышение часто уменьшает хвостовые задержки на пиках; слишком высокое — вернёт хаос переключений. - Включите приоритеты, если у вас много коротких транзакций: проверьте, как меняется p95 в транзакционных маршрутах.
- Закрепите конфиг и наблюдайте в течение пиковых часов. Дальше — только точечные правки.
Мониторинг и диагностика
Проверьте, что плагин активен и какие значения у параметров:
SHOW PLUGINS LIKE 'thread_pool';
SHOW VARIABLES LIKE 'thread_handling';
SHOW VARIABLES LIKE 'thread_pool%';
Статистика пула (именования могут отличаться по версиям, ориентируйтесь по префиксу):
SHOW STATUS LIKE 'Threadpool%';
Если видите длинные очереди при одновременно низкой утилизации CPU — thread_pool_size маловат. Если CPU «в кирпич» и высоки контекстные переключения, а очереди всё равно растут — oversubscribe завышен или узкое место — блокировки/диск.
Для InnoDB параллельно смотрите ожидания и блокировки: SHOW ENGINE INNODB STATUS, INFORMATION_SCHEMA.INNODB_TRX, INNODB_LOCK_WAITS. Если задержки вызваны ожиданием блокировок, тюнинг пула не поможет — оптимизируйте транзакции и индексы.
Sysbench: быстрая проверка гипотез
Для локальной оценки эффекта используйте стандартные профили sysbench (например, oltp_read_only и oltp_read_write) с возрастающим числом потоков. Важно: тестируйте на том же железе/хранилище и с приближёнными к продакшену параметрами innodb_buffer_pool_size, журналирования и бинарного лога.
# пример запуска чтения
sysbench oltp_read_only --threads=64 --time=60 --mysql-host=127.0.0.1 --mysql-user=bench --mysql-password=secret --mysql-db=sbtest prepare
sysbench oltp_read_only --threads=64 --time=60 --mysql-host=127.0.0.1 --mysql-user=bench --mysql-password=secret --mysql-db=sbtest run
sysbench oltp_read_only --threads=64 --time=60 --mysql-host=127.0.0.1 --mysql-user=bench --mysql-password=secret --mysql-db=sbtest cleanup
Сравните TPS и p95 задержки до/после включения Thread Pool при 32, 64, 128 потоках. При корректной настройке рост конкуренции не должен приводить к взрывному ухудшению задержек, а CPU будет загружен более равномерно. Если база крутится на VDS с квотами по CPU, учитывайте ограничения при выборе thread_pool_size.
Типичные проблемы и как их распознать
Пики латентности стали выше. Чаще всего значение thread_pool_size слишком маленькое для вашего пика, либо oversubscribe слишком консервативен. Убедитесь, что CPU не простаивает, а очередь на выполнение не растёт.
CPU «в потолок», а TPS хуже, чем без пула. Вероятно, вы завысили thread_pool_oversubscribe, фактически вернув поведение «очень много активных нитей». Снизьте oversubscribe и посмотрите на контекстные переключения ОС.
Пул не даёт эффекта вообще. Или ваш профиль — не про конкуренцию коротких запросов, или узкое место на диске/сети/блокировках. Проверьте планы запросов и индексацию; пересмотрите транзакции и изоляцию.
Неожиданная «голодовка» долгих запросов. При чрезмерной агрессии приоритетов короткие транзакции могут выталкивать длинные. Ослабьте приоритетный режим или уменьшите число «билетов».
Особенности виртуальных и контейнерных сред
В контейнерах и под cgroups MariaDB может видеть больше CPU, чем реально выделено. Привязывайте thread_pool_size к фактической квоте (CPU quota/period) и числу доступных CPU в контейнере. Если используете ограничения по cpuset — ориентируйтесь на число разрешённых CPU. На виртуальных машинах следите за метрикой CPU steal: высокий steal указывает на конкуренцию с соседями и затрудняет тюнинг пула — лучше снизить oversubscribe.
Как безопасно откатиться
Если эксперимент неудачен, можно вернуть модель «один поток на соединение». Для этого выгрузите плагин (на время текущего сеанса) и уберите строки из конфигурации:
UNINSTALL SONAME 'thread_pool';
После удаления директив plugin_load_add и thread_handling = pool-of-threads в конфиге перезапустите сервер — он вернётся к стандартной схеме.
Краткий чек-лист внедрения
- Понимаю профиль нагрузки и зафиксировал базовую метрику.
- Включил плагин, проверил стабильность и совместимость.
- Настроил
thread_pool_sizeотносительно CPU и пикового параллелизма. - Аккуратно подобрал
thread_pool_oversubscribeи приоритеты. - Проверил, что
innodb_thread_concurrencyне конфликтует (обычно 0). - Наблюдаю статус пула и метрики InnoDB; корректирую по фактам.
- Имею план быстрого отката.
Итоги
Thread Pool в MariaDB — практичный инструмент, который помогает укротить конкуренцию запросов и стабилизировать задержки под реальными OLTP-нагрузками на InnoDB. Выигрыш приходит за счёт уменьшения числа одновременно активных потоков, то есть снижения системных накладных расходов и равномерной загрузки CPU. Ключ к успеху — дисциплина замеров, минимальный набор осознанных параметров и понимание, где именно в вашем стеке возникают очереди: в планировщике потоков, в InnoDB, в дисковой подсистеме или в приложении.


