psql_quotolin. Расширенное квотирование вычислительных ресурсов#

Версия: 1.0.

В исходном дистрибутиве установлено по умолчанию: нет

Связанные компоненты: отсутствуют

Схема размещения: ext

Функциональность доступна только для редакций Enterprise и Enterprise для ERP-систем.

Разработано СУБД Pangolin.

Расширение psql_quotolin предназначено для продвинутого управления вычислительными ресурсами в СУБД Pangolin. Оно позволяет администраторам:

  • задавать лимиты по CPU, оперативной памяти, памяти подкачки (swap), числу параллельных рабочих процессов;

  • ограничивать скорость чтения/записи на диск (I/O) в разрезе табличных пространств;

  • устанавливать дисковые квоты (soft/hard) для ролей, схем и БД;

  • задавать индивидуальные ограничения для конкретного сеанса по PID;

  • планировать применение лимитов по датам, времени суток и дням недели;

  • наследовать планы ресурсов от родительских ролей.

Ключевой механизм работы psql_quotolinпланы ресурсов, которые назначаются ролям и автоматически применяются фоновым процессом Quotolin Launcher в реальном времени для новых и уже активных сеансов.

Доработка#

Доработка не проводилась.

Ограничения#

Функциональность поддерживается только на операционных системах REDOS 7.3.5, REDOS 8 в связи с использованием библиотеки libcgroup версии 3.x.x.

Для работы необходима поддержка cgroups v2 и установленный пакет libcgroup (≥ 3.0.0).

Ограничение

Описание

Контроль пула сессий

Не входит в состав решения, так как реализован через pg_quota.conf

Область действия

Ограничения действуют только в той базе данных, где установлено расширение

Первоначальная настройка

Требует участия администратора ОС для включения и настройки cgroups v2

CPU

Лимиты применяются только при конкуренции за ресурсы. Процесс с лимитом CPU может удерживать участок памяти, необходимый другому процессу, замедляя его

Dry-run

Режим предварительной проверки (dry-run) отсутствует

Ресурсные планы

Предопределенных глобальных планов нет. Планы задаются при подключении расширения к каждой БД

Назначение планов

Планы ресурсов можно назначать только ролям с атрибутом LOGIN

Часовой пояс

Все планы, назначенные одной роли, должны иметь одинаковый timezone

Минимумы

Время активности — 5 мин; память — 100 Мбайт; swap — 10 Мбайт

Swap

Рекомендуется размер не меньше объема RAM. При превышении лимитов RAM или swap процесс замедляется, но продолжает работу

Применение изменений

Изменения ограничений для роли могут задерживаться до значения psql_quotolin.launcher_interval

Дисковые квоты

Не применяются к сжатым таблицам

DISKIO

Лимиты накладываются на блочное устройство, где находится tablespace. Если на одном устройстве заданы разные лимиты, действует самый строгий

Наследование планов

При наследовании от нескольких ролей применяется план роли с меньшим OID

Docker

Не поддерживается

Ручные изменения

Ручное редактирование /sys/fs/cgroup/postgres приводит к неопределенному поведению

Поведение ограничений ресурсов#

Ограничение на процессорное время#

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

Ограничение на оперативную память#

При превышении лимита избыточные страницы отправляются в файл подкачки ОС. Если это невозможно (например, из-за лимита swap), процесс будет искусственно замедлен, и выделение памяти станет происходить с задержкой.

Ограничение на файлы подкачки#

Применяется к суммарному размеру файлов подкачки, используемых сеансом. При достижении лимита отправка страниц в swap прекращается.

Ограничение на параллельные рабочие процессы#

Проверяется в момент старта запроса. Уже запущенный запрос продолжает работать с ранее определенным количеством параллельных воркеров, даже если план изменился во время выполнения.

Ограничение на чтение/запись диска (DISKIO)#

Применяется к операциям чтения и записи. При превышении лимита операции замедляются, предотвращая перегрузку дисковой подсистемы.

Дисковые квоты#

Активны всегда. Два типа ограничений:

  • мягкое (soft) — выдается предупреждение при превышении;

  • жесткое (hard) — генерируется ошибка, запрещающая дальнейшую запись.

В работе расширения используются таблицы с foreign key. При обычном pg_dump возможны ошибки восстановления из-за нарушений ограничений. Рекомендуется использовать pg_dump -Fc и pg_restore, при которых восстановление выполняется корректно.

Параметры конфигурации (GUC)#

Параметр

По умолчанию

Диапазон/значения

Уровень

Назначение

psql_quotolin.max_workers

5

1–128

SIGHUP

Максимум воркеров Launcher

psql_quotolin.launcher_interval

5

1–60 сек

SIGHUP

Пауза между проходами Launcher

psql_quotolin.active

on

on/off

SIGHUP

Глобальное включение ограничений

psql_quotolin.maintenance_quota_check

on

on/off

SIGHUP

Учет квот при обслуживании БД

psql_quotolin.plan_inh

on

on/off

SIGHUP

Наследование планов

psql_quotolin.log_violations

off

on/off

SIGHUP

Лог нарушений лимитов

psql_quotolin.max_cpu_violations

5

1–1000

SIGHUP

Порог фиксации нарушений CPU

Требуется shared_preload_libraries = 'psql_quotolin' в конфигурации сервера.

Установка#

Администратор операционной системы включает и настраивает cgroups v2.

Администратор базы данных устанавливает расширение, создает/назначает планы, управляет квотами, меняет GUC.

Подготовка операционной системы#

  1. Проверьте поддержку cgroups v2:

    mount | grep cgroup
    

    Должна присутствовать строка:

    cgroup2 on /sys/fs/cgroup type cgroup2
    
  2. Установите пакеты:

    # для REDOS
    dnf install libcgroup-tools
    
  3. Создайте cgroup и выдайте права:

    cgcreate -g cpu,memory,io:/postgres
    chown -R postgres /sys/fs/cgroup/postgres
    chown postgres /sys/fs/cgroup/cgroup.procs
    

Настройка Pangolin#

  1. Включите предварительную загрузку расширения в postgresql.conf:

    shared_preload_libraries = 'psql_quotolin'
    
  2. Перезапустите кластер и в СУБД Pangolin выполните:

    CREATE EXTENSION psql_quotolin;
    

Привилегии#

После установки расширения все права на управление квотами имеют только суперпользователи.

Доступ к просмотру конфигурационных таблиц и функциям мониторинга, кроме суперпользователей, имеет предопределенная расширением роль psql_read_all_quotolin_stats.

Делегирование прав осуществляется через команду GRANT.

Примеры#

Делегация прав на изменение GUC:

GRANT EXECUTE ON FUNCTION pg_reload_conf TO new_role;
GRANT ALTER SYSTEM ON PARAMETER psql_quotolin.active TO new_role;

Делегация прав на использование функции:

GRANT USAGE ON SCHEMA quotolin TO new_role;
GRANT EXECUTE ON FUNCTION quotolin.quotolin_current_plan TO new_role;

Делегация доступа к просмотру конфигурационных таблиц и функциям мониторинга:

GRANT psql_read_all_quotolin_stats TO new_role;

Описание объектов БД#

Роли#

psql_read_all_quotolin_stats — предопределенная роль расширения для агрегирования доступов на просмотр таблиц и функций мониторинга.

Таблицы#

quotolin.quotolin_plans — хранит список всех ресурсных планов и их параметры (CPU, память, swap, параллельные воркеры, ограничения на ввод-вывод).

quotolin.quotolin_user_plans — содержит соответствия ролей и назначенных им планов с указанием временных периодов и часов.

quotolin.quotolin_disk_limits — хранит ограничения дисковой квоты (мягкие и жесткие) для ролей, схем и табличных пространств.

quotolin.quotolin_plans_io_limits — хранит лимиты скорости чтения и записи на диск.

Функции#

Управление планами ресурсов:

  • quotolin.quotolin_create_plan(plan_name, cpu_limit, memory_limit_mb, swap_limit_mb, parallel_worker_limit) — создает новый план ресурсов;

  • quotolin.quotolin_update_plan(plan_name, cpu_limit, memory_limit_mb, swap_limit_mb, parallel_worker_limit) — изменяет существующий план;

  • quotolin.quotolin_rename_plan(old_plan_name, new_plan_name) — переименовывает план;

  • quotolin.quotolin_delete_plan(plan_name) — удаляет план (если он не назначен ролям).

Ограничения на ввод-вывод (DISKIO):

  • quotolin.quotolin_plan_add_io_limits(plan_name, tbs_name, io_rkbps_limit, io_wkbps_limit) — добавляет ограничения на чтение/запись для табличного пространства;

  • quotolin.quotolin_plan_update_io_limits(plan_name, tbs_name, io_rkbps_limit, io_wkbps_limit) — обновляет параметры I/O;

  • quotolin.quotolin_plan_remove_io_limits(plan_name, tbs_name) — удаляет ограничения I/O.

Назначение и управление планами:

  • quotolin.quotolin_grant_plan(role_name, plan_name, from_date, till_date, start_time, end_time, days_of_week, timezone) — назначает план роли на период;

  • quotolin.quotolin_revoke_plan(role_name, plan_name) — отзывает план у роли;

  • quotolin.quotolin_current_plan(role_name) — возвращает текущий активный план роли;

  • quotolin.quotolin_update_timeframe(role_name, plan_name, from_date, till_date, start_time, end_time, days_of_week, timezone) — изменяет временной интервал действия плана.

Сессионные ограничения:

  • quotolin.quotolin_prepare_session_quota(session_pid) — подготавливает сеанс к установке индивидуальных лимитов;

  • quotolin.quotolin_set_session_quota(session_pid, cpu_limit, memory_limit_mb, swap_limit_mb, parallel_worker_limit) — устанавливает лимиты для сессии;

  • quotolin.quotolin_delete_session_quota(session_pid) — удаляет лимиты сессии;

  • quotolin.quotolin_set_session_io_limit(session_pid, tbs_name, io_rkbps_limit, io_wkbps_limit) — назначает I/O-ограничения для сессии;

  • quotolin.quotolin_remove_session_io_limits(session_pid, tbs_name) — удаляет I/O-ограничения сессии.

Дисковые квоты:

  • quotolin.quotolin_plan_add_disk_limits(role_name, schema_name, tablespace_name, soft_limit, hard_limit) — назначает мягкие и жесткие лимиты дисковой квоты (можно задать NULL для схемы или tablespace);

  • quotolin.quotolin_plan_update_disk_limits(role_name, schema_name, tablespace_name, soft_limit, hard_limit) — обновляет квоты;

  • quotolin.quotolin_plan_remove_disk_limits(role_name, schema_name, tablespace_name) — снимает дисковые квоты;

  • quotolin.quotolin_recalculate_disk_quota() — пересчитывает дисковые квоты после изменений или смены владельцев объектов.

Мониторинг:

  • quotolin.quotolin_get_disk_quota_hash() — возвращает доступное дисковое пространство для пользователей;

  • quotolin.quotolin_get_session_limit_hash() — показывает наличие активных сессионных ограничений;

  • quotolin.quotolin_get_user_plan_hash() — выводит текущие планы для пользователей;

  • quotolin.quotolin_get_plan_usage_stats() — статистика использования ресурсов по каждому плану;

  • quotolin.quotolin_get_session_limits_stats() — статистика использования ресурсов по сеансам.

Основные функции API#

Управление планами ресурсов (без DISKIO)#

  1. Создание нового плана ресурсов

    SELECT quotolin.quotolin_create_plan(
        plan_name TEXT,
        cpu_limit INT,             # NULL - ограничение отсутствует
        memory_limit_mb INT,       # NULL - ограничение отсутствует
        swap_limit_mb INT,         # NULL - ограничение отсутствует
        parallel_worker_limit INT  # NULL - ограничение отсутствует
    ) RETURNS BOOLEAN;
    
  2. Обновление неназначенного плана ресурсов

    SELECT quotolin.quotolin_update_plan(
        plan_name TEXT,
        cpu_limit INT,             # NULL - ограничение отсутствует
        memory_limit_mb INT,       # NULL - ограничение отсутствует
        swap_limit_mb INT,         # NULL - ограничение отсутствует
        parallel_worker_limit INT  # NULL - ограничение отсутствует
    ) RETURNS BOOLEAN;
    
  3. Переименование плана ресурсов

    SELECT quotolin.quotolin_rename_plan(
        old_plan_name TEXT,
        new_plan_name TEXT
    ) RETURNS BOOLEAN;
    
  4. Удаление неназначенного плана ресурсов

    SELECT quotolin.quotolin_delete_plan(
    plan_name TEXT
    ) RETURNS BOOLEAN;
    

Расширение ресурсных планов ограничениями на скорость чтения/записи диска (DISKIO)#

  1. Прикрепление ограничений на скорость чтения/записи диска к ресурсному плану

    SELECT quotolin.quotolin_plan_add_io_limits(
        plan_name TEXT,
        tbs_name TEXT,
        io_rkbps_limit INT,  # NULL - ограничение отсутствует
        io_wkbps_limit INT   # NULL - ограничение отсутствует
    ) RETURNS BOOLEAN;
    
  2. Изменение ограничений на скорость чтения/записи диска

    SELECT quotolin.quotolin_plan_update_io_limits(
        plan_name TEXT,
        tbs_name TEXT,
        io_rkbps_limit INT,  # NULL - ограничение отсутствует
        io_wkbps_limit INT   # NULL - ограничение отсутствует
    ) RETURNS BOOLEAN;
    
  3. Удаление ограничений на скорость чтения/записи диска

    SELECT quotolin.quotolin_plan_remove_io_limits(
        plan_name TEXT,
        tbs_name TEXT
    ) RETURNS BOOLEAN;
    

Управление назначением ресурсных планов и временем их активности#

  1. Назначение ресурсного плана роли:

    SELECT quotolin.quotolin_grant_plan(
        role_name TEXT,
        plan_name TEXT,
        from_date TIMESTAMP,  # NULL - текущая дата
        till_date TIMESTAMP,  # NULL - бесконечно
        start_time TIME,      # NULL - активен с начала дня
        end_time TIME,        # NULL - активен до конца дня
        days_of_week TEXT[],  # NULL - активен в любой день недели
        timezone TEXT         # NULL - используется временная зона текущего сеанса
    ) RETURNS BOOLEAN;
    
  2. Изменение времени активности назначенного ресурсного плана:

    SELECT quotolin.quotolin_update_timeframe(
        role_name TEXT,
        plan_name TEXT,
        from_date TIMESTAMP,  # NULL - текущая дата
        till_date TIMESTAMP,  # NULL - бесконечно
        start_time TIME,      # NULL - активен с начала дня
        end_time TIME,        # NULL - активен до конца дня
        days_of_week TEXT[],  # NULL - активен в любой день недели
        timezone TEXT         # NULL - используется временная зона текущего сеанса
    ) RETURNS BOOLEAN;
    
  3. Отзыв назначенного ресурсного плана:

    SELECT quotolin.quotolin_revoke_plan(
        role_name TEXT,
        plan_name TEXT
    ) RETURNS BOOLEAN;
    
  4. Получение активного ресурсного плана для роли:

    SELECT quotolin.quotolin_current_plan(
        role_name TEXT
    ) RETURNS BOOLEAN;
    

Управление ограничениями для сессии#

  1. Подготовка сессии к пользовательским ограничениям:

    SELECT quotolin.quotolin_prepare_session_quota(
        session_pid INT
    ) RETURNS BOOLEAN;
    
  2. Установка ограничений для сессии (без DISKIO):

    SELECT quotolin.quotolin_set_session_quota(
        session_pid INT,
        cpu_limit INT,             # NULL - ограничение отсутствует
        memory_limit_mb INT,       # NULL - ограничение отсутствует
        swap_limit_mb INT,         # NULL - ограничение отсутствует
        parallel_worker_limit INT  # NULL - ограничение отсутствует
    ) RETURNS BOOLEAN;
    
  3. Удаление ограничений для сессии (без DISKIO):

    SELECT quotolin.quotolin_delete_session_quota(
        session_pid INT
    ) RETURNS BOOLEAN;
    
  4. Установка ограничения на скорость чтения/записи диска для сессии (DISKIO):

    SELECT quotolin.quotolin_set_session_io_limit(
        session_pid INT,
        tbs_name TEXT,
        io_rkbps_limit INT,  # NULL - ограничение отсутствует
        io_wkbps_limit INT   # NULL - ограничение отсутствует
    ) RETURNS BOOLEAN;
    
  5. Удаление ограничения на скорость чтения/записи диска для сессии (DISKIO):

    SELECT quotolin.quotolin_remove_session_io_limits(
        session_pid INT,
        tbs_name TEXT
    ) RETURNS BOOLEAN;
    

Управление дисковыми квотами#

  1. Добавление дисковой квоты:

    SELECT quotolin.quotolin_plan_add_disk_limits(
        role_name TEXT,
        schema_name TEXT,      # NULL - действует для всех схем
        tablespace_name TEXT,  # NULL - действует для всех табличных пространств
        soft_limit BIGINT,     # NULL - ограничение отсутствует
        hard_limit BIGINT      # NULL - ограничение отсутствует
    ) RETURNS BOOLEAN;
    
  2. Изменение дисковой квоты:

    SELECT quotolin.quotolin_plan_update_disk_limits(
        role_name TEXT,
        schema_name TEXT,      # NULL - действует для всех схем
        tablespace_name TEXT,  # NULL - действует для всех табличных пространств
        soft_limit BIGINT,     # NULL - ограничение отсутствует
        hard_limit BIGINT      # NULL - ограничение отсутствует
    ) RETURNS BOOLEAN;
    
  3. Удаление дисковой квоты:

    SELECT quotolin.quotolin_plan_remove_disk_limits(
        role_name TEXT,
        schema_name TEXT,
        tablespace_name TEXT
    ) RETURNS BOOLEAN;
    
  4. Пересчет дисковых квот:

    SELECT quotolin.quotolin_recalculate_disk_quota(
    ) RETURNS BOOLEAN;
    

Мониторинг#

  1. Применение планов ограничений:

    SELECT quotolin.quotolin_get_user_plan_hash()
    RETURNS TABLE(
        db_oid OID,
        role_oid OID,
        plan_id Oid
    );
    
  2. Статистика использования ресурсов по планам ограничений:

    SELECT quotolin.quotolin_get_plan_usage_stats()
    RETURNS TABLE(
        plan_name TEXT,
        cpu_usage BIGINT,
        memory_usage BIGINT,
        swap_usage BIGINT,
        io_usage TEXT
    );
    
  3. Применение сессионных ограничений:

    SELECT quotolin.quotolin_get_session_limit_hash()
    RETURNS TABLE(
        pid INT,
        active BOOLEAN,
        cpu_limit BOOLEAN,
        memory_limit BOOLEAN,
        swap_limit BOOLEAN,
        parallel_worker_limit BOOLEAN,
        parallel_workers INT
    );
    
  4. Статистика использования ресурсов по ограничиваемым сессиям:

    SELECT quotolin.quotolin_get_session_limits_stats()
    RETURNS TABLE(
        pid INT,
        cpu_usage BIGINT,
        memory_usage BIGINT,
        swap_usage BIGINT,
        io_usage TEXT
    );
    
  5. Количество свободного пространства для дисковых квот:

    SELECT quotolin.quotolin_get_disk_quota_hash()
    RETURNS TABLE(
        role_oid OID,
        schema_oid OID,
        tablespace_oid OID,
        db_oid Oid,
        freeSoft BIGINT,
        freeHard BIGINT
    );
    

Диагностика#

При включенном log_violations в журнал пишутся предупреждения:

WARNING: CPU limit exceeded for PID 12345: usage 85% > limit 50%

Для анализа загрузки:

SELECT * FROM quotolin.quotolin_get_plan_usage_stats();
SELECT * FROM quotolin.quotolin_get_session_limits_stats();

Проверка cgroups:

  • для сессий: /proc/<pid>/cgroup должен указывать на .../session_<pid>;

  • для планов: /proc/<pid>/cgroup .../plan_<db_oid>_<plan_id>;

  • параметры проверяются в /sys/fs/cgroup/postgres/quota/<cgroup_name>/ (cpu.weight, memory.high, memory.swap.max, io.max).

Резервное копирование/восстановление#

Рекомендуемый формат pg_dump -Fc / pg_restore.

Важно

Таблицы расширения содержат foreign key, поэтому для корректного восстановления необходимо использовать именно pg_dump -Fc.