Как раздать пользователям приоритеты
Владимир Пржиялковский,
преподаватель УКЦ Interface Ltd.
Не секрет, что уже достаточно давно фирма Oracle испытывает в области средств моделирования данных нечто вроде кризиса жанра (впрочем, не выделяясь в этом среди своих конкурентов). Взять хотя бы ее искания в этом направлении в продолжении последних лет, а заодно и результаты этих исканий. Замечая на протяжении длительного времени лишь ближние рыночные ориентиры, фирма сама подвела себя к нелегкой ситуации - перспективы в этой области неясны... В области же эксплуатационной то же самое поведение Oracle оказалось не столь пагубным, и наверстывание многого из того, что можно было бы сделать давным-давно, пока возможно, и реально продолжается с каждой последней версией. Словом – здесь лучше поздно, чем никогда, хотя в других областях может статься лучше никогда, чем поздно.
Первое, например, касается очень простой задачи: как научиться выдавать пользователям, работающим с базой данных, приоритеты на процессорное время Oracle? Чтобы какой-нибудь из пользователей, запуская сложные запросы, не мешал работе остальных?
Кое-что по части администрирования использования ресурсов системы известно и применяется на практике давно. Имеются в виду профили, которые можно приписывать пользователям, и которые позволяют ограничивать процессорное время и обращения к диску в рамках отдельных запросов или всего сеанса. Ну а если мы не хотим вводить абсолютные ограничения, а хотим ввести приоритеты?
Такая возможность появилась в версии 8.1. Многие, наверное, обратили внимание на отсутствующие в более ранних версиях термины resource manager или consumer group, появившиеся формах OEM и в документации, но разобраться в них все было недосуг. Между тем, понять, о чем идет речь, вовсе нетрудно, что мы сейчас вместе и сделаем.
Постановка задачи
Допустим, мы хотим разбить пользователей на три группы:
Пусть, в свою очередь, прикладники делятся на
Что для такой организации труда нужно сделать?
Диспетчер ресурсов
…Точнее было бы перевести “диспетчер ресурса” (resource manager), а еще точнее – “диспетчер ресурса процессорного времени”, поскольку сейчас именно и только об этом ресурсе идет речь. В него входят:
Группа потребителей (consumer group) – группа пользователей Oracle, с которой связывается та или иная гарантированная доля процессорного времени
Ресурсный план (resource plan) – именованная схема распределения долей процессорного времени
Рабочая область (pending area) – временная область, в которой, по технологии диспетчера ресурсов, собирается и проверяется на корректность ресурсный план, прежде чем его можно будет употреблять.
Подготовительные действия
Поначалу нужно выбрать пользователя-администратора, который будет создавать группы потребителей и ресурсные планы в рабочей области, расположенной у себя. Если этот пользователь по вашему выбору – не SYS и не SYSTEM (а к такому решению могут располагать организационные моменты), ему нужно дать право:
EXEC DBMS_RESOURCE_MANAGER_PRIVS.GRANT_SYSTEM_PRIVILEGE( -
'SCOTT', 'ADMINISTER_RESOURCE_MANAGER', FALSE);
EXEC DBMS_RESOURCE_MANAGER_PRIVS.GRANT_SYSTEM_PRIVILEGE( -
Технология диспетчера организована так, что привилегия ADMINISTER RESOURCE MANAGER выдается и отбирается не обычными командами GRANT и REVOKE, а процедурно, на манер, как сделано выше.
Теперь администратор диспетчера ресурсов должен создать рабочую область, где будет создаваться и готовиться план (см. предложения ниже):
EXEC DBMS_RESOURCE_MANAGER.CREATE_PENDING_AREA();
Создаем план
От имени администратора диспетчера выдаем:
BEGIN
DBMS_RESOURCE_MANAGER.CREATE_PLAN(
'DAILY',
'The plan for normal daily operations');
DBMS_RESOURCE_MANAGER.CREATE_PLAN(
'APPLICATIONS',
'The subplan for applications');
END;
/
Мы создали два плана: основной ('DAILY') и один подчиненный ('APPLICATIONS'). Подчиненных может быть и больше, а может и вовсе не быть.
Создаем потребительские группы
От имени администратора выдаем:
BEGIN
DBMS_RESOURCE_MANAGER.CREATE_CONSUMER_GROUP(
'Database support',
'Database administration group');
DBMS_RESOURCE_MANAGER.CREATE_CONSUMER_GROUP(
'Operators',
'Customer management department');
DBMS_RESOURCE_MANAGER.CREATE_CONSUMER_GROUP(
'Analytics',
'System analysis group');
END;
/
Тут созданы три потребительские группы; из кода полностью ясно, как.
Кроме указанных, системой автоматически создается группа OTHER_GROUPS, куда попадают все пользователи, не включенные в эти группы.
Привязываем потребительские группы к плану
Из созданной выше структуры для плана строим полноценный план, приписывая этой структуре потребительские группы:
BEGIN
DBMS_RESOURCE_MANAGER.CREATE_PLAN_DIRECTIVE(
'DAILY ',
'Database support',
'Resource allocation for DBA group',
cpu_p1 => 70);
DBMS_RESOURCE_MANAGER.CREATE_PLAN_DIRECTIVE(
'DAILY ',
'APPLICATIONS',
'Resource allocation for application users',
cpu_p1 => 20);
DBMS_RESOURCE_MANAGER.CREATE_PLAN_DIRECTIVE(
'DAILY ',
'OTHER_GROUPS',
'For users not included to any group.',
cpu_p1 => 10);
END;
/
То же самое продолжаем для подчиненного плана:
BEGIN
DBMS_RESOURCE_MANAGER.CREATE_PLAN_DIRECTIVE(
'APPLICATIONS',
'Operators',
'For general operators',
cpu_p1 => 90);
DBMS_RESOURCE_MANAGER.CREATE_PLAN_DIRECTIVE(
'APPLICATIONS',
'Analytics',
'For the report writers',
cpu_p1 => 10);
END;
/
Итак, мы сформировали полный план в виде дерева с двумя уровнями. “Листья” дерева – потребительские группы, а промежуточное звено – подчиненный план.
Передаем план в распоряжение системы
Теперь мы готовы к тому, чтобы проверить сформированный план на правильность: может быть, в нем присутствуют циклы, отсутствующие группы или другие некорректности? Выдадим:
EXEC DBMS_RESOURCE_MANAGER.VALIDATE_PENDING_AREA();
Если все в порядке (а в нашем случае должно быть так), план DAILY можно “сдавать в эксплуатацию”:
EXEC DBMS_RESOURCE_MANAGER.SUBMIT_PENDING_AREA();
Включаем в потребительские группы пользователей Oracle
План готов к работе, но наши потребительские группы созданы только номинально: в них нет пользователей. По технологии, предлагаемой Oracle, пользователь системы может быть подключен к какой-нибудь группе только при наличии у него права SWITCH CONSUMER GROUP. Выдается оно также с помощью API, то есть одного из наших двух пакетов:
BEGIN
DBMS_RESOURCE_MANAGER_PRIVS.GRANT_SWITCH_CONSUMER_GROUP(
'SYSTEM', 'Database support', FALSE);
DBMS_RESOURCE_MANAGER_PRIVS.GRANT_SWITCH_CONSUMER_GROUP(
'SCOTT', 'Operators', FALSE);
DBMS_RESOURCE_MANAGER_PRIVS.GRANT_SWITCH_CONSUMER_GROUP(
'ADAMS', 'Analytics', FALSE);
END;
/
И только теперь пользователей (из списка выше, коль скоро у них появилось на то право) можно фактически включать в группы:
BEGIN
DBMS_RESOURCE_MANAGER.SET_INITIAL_CONSUMER_GROUP(
'SYSTEM', 'Database support');
DBMS_RESOURCE_MANAGER.SET_INITIAL_CONSUMER_GROUP(
'SCOTT', 'Operators');
DBMS_RESOURCE_MANAGER.SET_INITIAL_CONSUMER_GROUP(
'ADAMS', 'Analytics');
END;
/
План начинает действовать
Если теперь ADAMS запустит большой, но “несмертельный” запрос (например, на удвоение безындексной таблицы из полмиллиона записей), никто больше с Oracle не работает, и мы от имени SCOTT попросим выдать EMP, то увидим, что в нашем распоряжении отнюдь не 90% ресурсов. Чтобы план DAILY заработал, требуется поставить последнюю точку:
ALTER SYSTEM SET RESOURCE_MANAGER_PLAN = DAILY;
Думаю, что радость пользователя SCOTT от времени реакции системы после этого с лихвой окупит его страдания от набирания всех [PL/]SQL-операторов, указанных выше !
Точку можно поставить и по-другому. Указание RESOURCE_MANAGER_PLAN = DAILY можно включить в файл INIT.ORA, и тогда план будет автоматически включаться в действие при старте СУБД, а не быть активным только до первого останова.
Усовершенствования
Описанную выше схему организации приоритетного доступа к процессорному времени можно развивать дальше. Вот некоторое, что приходит в голову сразу:
AFTER STARTUP ON DATABASE
DECLARE
switch_to_daily varchar2(40) :=
'ALTER SYSTEM SET RESOURCE_MANAGER_PLAN = DAILY';
switch_to_nightly varchar2(40) :=
'ALTER SYSTEM SET RESOURCE_MANAGER_PLAN = NIGHTLY';
BEGIN
IF (SYSDATE > TRUNC(SYSDATE) + 9 / 24) AND
(SYSDATE < TRUNC(SYSDATE) + 18 / 24) THEN
EXECUTE IMMEDIATE switch_to_daily;
ELSE EXECUTE IMMEDIATE switch_to_nightly;
END IF;
END;
/
В начале статьи молчаливо предполагалось, что выгоды от возможности введения приоритетов для пользователей, работающих с Oracle, настолько очевидны, что не требуют пояснений. Тем не менее, об одной абсолютно выигрышной стороне такой организации работ хотелось бы сказать явно и отдельно. Дело в том, что заведение приоритетов способом, описанным только что, никак не затрагивает устройство вашего приложения. Прикладную систему менять не надо и ее код никак при этом не модифицируется. Все делается на совершенно другом, изолированном от прикладного, уровне.
Это значит, что в ваши старые приложения вы можете “вдохнуть новую жизнь”, не переписывая ни одной строки кода. Приятное свойство!
Что делать дальше
Как это часто бывает в Oracle, простые внешне идеи при реализации обрастают пугающим новичка изобилием технических подробностей, в которых отнюдь не просто разобраться. (Объективно это или субъективно – для меня пока загадка. Поделитесь своим мнением!. Есть они и в случае с диспетчером ресурсов. Любознательные имеют возможность ознакомиться с ними, заглянув в документацию по Oracle. Надо надеяться, что полнофункциональный пример, приведенный выше, сделает такое знакомство менее травмирующим.
За дополнительной информацией обращайтесь в Interface Ltd.