Привет, Хабр!
Сегодня мы рассмотрим Resource Groups в MySQL — и перестанем жить на одной CPU.
Resource Groups — это контроль над CPU прямо из SQL. Вы создаёте логическую группу, говорите «эта группа может использовать только 2 CPU и работать на низком приоритете», и назначаете туда тяжелые, но второстепенные задачи. Всё. Дальше MySQL сам всё регулирует.
Прежде чем начать
Сначала проверим, включена ли вообще эта фича:
SHOW VARIABLES LIKE 'resource_group_enabled';
Если ON
— отлично. Если OFF
, скорее всего:
У вас macOS (там это не работает в принципе).
Или у вас включён thread pool (он конфликтует).
Или вы сидите на древней версии MySQL.
Если всё норм, едем дальше.
По дефолту есть две группы
SELECT * FROM INFORMATION_SCHEMA.RESOURCE_GROUPS\G
Получите вот такое:
RESOURCE_GROUP_NAME: USR_default
RESOURCE_GROUP_TYPE: USER
VCPU_IDS: 0-3
THREAD_PRIORITY: 0
То есть, если вы никогда ничего не настраивали, весь ваш код, все ваши запросы, API, ETL, BI, всё работает в одном тазике USR_default
. Без приоритета и без ограничений.
Наведём порядок
Допустим, у нас есть ETL-запросы или отчёты из Metabase, которым ни к чему мешать пользователям. Хотим их ограничить по CPU и поставить в конец очереди.
Создаём:
CREATE RESOURCE GROUP etl_group
TYPE = USER
VCPU = 2-3
THREAD_PRIORITY = 15;
Переводим на русский:
VCPU = 2-3
— используем только два ядра.THREAD_PRIORITY = 15
— низкий приоритет (где 0 — норм, 19 — спи спокойно, малыш).
Назначаем сессию в группу
Узнали CONNECTION_ID()
и назначаем поток:
SET RESOURCE GROUP etl_group FOR 123;
Или если хотим назначить себе прямо сейчас:
SET RESOURCE GROUP etl_group;
Теперь SQL будет отрабатывать их не мешая никому.
Но можно и точечно — только один запрос
SELECT /*+ RESOURCE_GROUP(etl_group) */ COUNT(*) FROM big_table;
Всё, что внутри запроса — будет выполнено с ограничениями группы.
Проверим, кто куда попал
SELECT THREAD_ID, RESOURCE_GROUP_NAME
FROM performance_schema.threads
WHERE PROCESSLIST_ID = CONNECTION_ID();
Если всё ок — будете видеть etl_group
как текущую группу.
Как менять группу на ходу
Ночью можно дать больше приоритета:
ALTER RESOURCE GROUP etl_group
VCPU = 0-3,
THREAD_PRIORITY = 5;
Днём снова поджали:
ALTER RESOURCE GROUP etl_group
VCPU = 2,
THREAD_PRIORITY = 18;
А если не помогает — значит нет прав
Да, нужны привилегии. Вот как их выдать:
GRANT RESOURCE_GROUP_ADMIN ON *.* TO 'my_admin'@'%';
Тогда можно будет создавать и менять группы. А если просто использовать:
GRANT RESOURCE_GROUP_USER ON *.* TO 'etl_worker'@'%';
Некоторые проблемы
Список всех проблем:
macOS не поддерживается вообще.
FreeBSD и Solaris игнорируют приоритеты. Всё всегда на
0
.Linux требует
CAP_SYS_NICE
. Без этого приоритеты игнорируются. Включить:
sudo setcap cap_sys_nice+ep /usr/sbin/mysqld
Лучше — через systemd:
sudo systemctl edit mysql
Добавьте:
[Service]
AmbientCapabilities=CAP_SYS_NICE
Thread Pool plugin ломает всё. Его надо отключить.
Три кейса использования
BI-отчёты на Metabase не душат REST-API
На одном сервере живут фронтовое API (latency < 100 мс) и Metabase, который в пик дня гоняет SELECT … GROUP BY
на десятки секунд. Фронт-энд периодически замирает.
Решение
-- создаём группу под BI
CREATE RESOURCE GROUP bi_low
TYPE = USER
VCPU = 3 -- одно «спокойное» ядро
THREAD_PRIORITY = 18; -- почти самый низкий приоритет
В настройках подключения Metabase добавляем startup-query:
SET RESOURCE GROUP bi_low;
Теперь все BI-запросы ограничены одним ядром и низким приоритетом — API обслуживается без скачков latencies.
Ночные ETL-джобы Parallel Ingest против дневного OLTP
Cron в 02:00 поднимает Java-процесс, который заливает данные пачками INSERT … ON DUPLICATE KEY UPDATE
. Днём всё ок, но если бэкап сместился и ETL стартовал в рабочий час — база становится резиновой.
Решение
-- заводим группу для ETL
CREATE RESOURCE GROUP etl_batch
TYPE = USER
VCPU = 1-2 -- два ядра из восьми
THREAD_PRIORITY = 10;
Java-процессу в строку подключения пишем:
jdbc:mysql://db:3306/app?sessionVariables=resource_group=etl_batch
Днём ETL не вылазит за выделенные CPU, ночью при желании можно поднять приоритет:
ALTER RESOURCE GROUP etl_batch
VCPU = 0-3
THREAD_PRIORITY = 2;
Крутить ad-hoc-запросы
Иногда нужно быстро проверить гипотезу, и кто-то запускает EXPLAIN ANALYZE
на таблицу в 200 М строк. Если соединение открыто под обычной учёткой, запрос лезет в ту же очередь, что и боевые платежи.
Решение
-- создаём песочницу для ручных запросов
CREATE RESOURCE GROUP dev_lab
TYPE = USER
VCPU = 2-3
THREAD_PRIORITY = 16;
Даем разработчикам отдельный логин:
GRANT RESOURCE_GROUP_USER ON *.* TO 'dev'@'%';
GRANT USAGE ON *.* TO 'dev'@'%';
GRANT SELECT, EXPLAIN ON prod_db.* TO 'dev'@'%';
И в .my.cnf
этого логина пишем:
[client]
user = dev
password = ****
init_command = "SET RESOURCE GROUP dev_lab"
Итоги
Resource Groups — полезная фича MySQL: закрепили ядра, задали приоритеты, и тяжёлые BI- или ETL-потоки больше не топят прод; настройка занимает минуты, а выигрыш — стабильные миллисекунды отклика в пиковые часы. Если вам уже довелось приручать запросы через свои группы, поделитесь в комментарих вашим опытом — коллективный опыт всегда мощнее любой официальной документации.
Освоить MS SQL Server на профессиональном уровне и расширить свои возможности в IT можно на онлайн-курсе "MS SQL Server Developer".
Если интересно узнать свой уровень знаний для поступления на курс, пройдите вступительное тестирование.
Akina
При выполнении показанного запроса есть неиллюзорный шанс получить Empty Set. Ну хотя бы потому, что имя статусной переменной - Resource_group_supported.
Впрочем, даже запрос с правильным именем переменной может вернуть Empty Set.
Получите Unknown column 'RESOURCE_GROUP_NAME' in 'field list'. Правильное имя поля в указанной таблице - RESOURCE_GROUP.
А вот поле с указанным именем можно найти в таблице INFORMATION_SCHEMA.RESOURCE_GROUPS.