Limiter la CPU des instances Oracle 11g Release 2

Oracle Database 11g Release 2 offre deux nouvelles fonctionalités pour faciliter la mutualisation des instances au sein d’un même serveur; la fonctionnalité dite d' »instance caging » permet de fixer le nombre maximum de processeurs utilisables par une instance. Vous trouverez plusieurs description de son fonctionnement dans la documentation Oracle, dans le white-paper dédié sur OTN et dans plusieurs articles de la blogosphère à commencer par celui de Christian Antognini. La seconde est liée à l’utilisation du paramètre max_utilization_limit de ressource Manager qui fixe une limite supérieure d’utilisation de la CPU pour un groupe d’un plan de ressources.

Créer un plan avec un maximum d’utilisation de la CPU

Le script ci-dessous crée un plan de ressources qui limite à 17% de la CPU le groupe OOPS et 24% de la CPU le groupe OTHER_GROUPS. Il positionne également le plan d’exécution comme le plan actif et authorise SCOTT à utiliser le groupe OOPS :

begin
dbms_resource_manager.clear_pending_area;
dbms_resource_manager.create_pending_area;

dbms_resource_manager.create_plan(
plan => 'LIMITED_CPU',
comment => 'Limited Amount of CPU');

dbms_resource_manager.create_consumer_group(
consumer_group => 'Oops',
comment => 'Oops Consumer Group',
mgmt_mth => 'ROUND-ROBIN');


dbms_resource_manager.create_plan_directive(
plan => 'LIMITED_CPU',
group_or_subplan => 'Oops',
comment => 'Oops - Max to 25% of CPU',
max_utilization_limit => 17);

-- Create resource plan directives
dbms_resource_manager.create_plan_directive(
plan => 'LIMITED_CPU',
group_or_subplan => 'OTHER_GROUPS',
comment => 'Other_groups - Max to an additional 24% of CPU',
max_utilization_limit => 24);

-- Submit the changes
dbms_resource_manager.validate_pending_area;
dbms_resource_manager.submit_pending_area;

end;
/

alter system set resource_manager_plan=LIMITED_CPU;

begin
dbms_resource_manager_privs.grant_switch_consumer_group(
grantee_name => 'SCOTT',
consumer_group => 'OOPS',
grant_option => false);
end;
/

Confirmer le paramétrage

Pour confirmer le paramétrage du gestionnaire de ressources d’Oracle, vous pouvez exécutez quelques unes des requêtes ci-dessous :

col plan format a12
col comments format a25
select plan, comments
from dba_rsrc_plans
where plan='LIMITED_CPU';

PLAN COMMENTS
------------ -------------------------
LIMITED_CPU Limited Amount of CPU


col group_or_subplan format a16
select plan, group_or_subplan, type, mgmt_p1, max_utilization_limit
from dba_rsrc_plan_directives
where plan='LIMITED_CPU';

PLAN GROUP_OR_SUBPLAN TYPE MGMT_P1 MAX_UTILIZATION_LIMIT
------------ ---------------- -------------- ---------- ---------------------
LIMITED_CPU OOPS CONSUMER_GROUP 0 17
LIMITED_CPU OTHER_GROUPS CONSUMER_GROUP 0 24


col consumer_group format a15
col mgmt_method format a15
col status format a6
col mandatory format a6
select consumer_group, mgmt_method, status, mandatory
from dba_rsrc_consumer_groups
where consumer_group in ('OTHER_GROUPS','OOPS');

CONSUMER_GROUP MGMT_METHOD STATUS MANDAT
--------------- --------------- ------ ------
OOPS ROUND-ROBIN NO
OTHER_GROUPS ROUND-ROBIN YES

Utiliser le groupe de ressources et observer les indicateurs clé

Pour illustrer comment se comporte des utilisateurs actifs dans le groupe OOPS limité à 17% d’utilisation de la CPU dans le plan actif, nous allons effectuer un test; d’abord, connectez-vous et notez l’identifiant de session grace à sys_context :

sqlplus scott/tiger

select sys_context('userenv', 'sid') sid
from dual;

SID
-------
125

Ouvrez ensuite une seconde session sous SYS et basculez la session dans le groupe de consommateur OOPS. Vous constaterez que si votre autre session est inactive, les indicateurs relatifs au gestionnaire de ressources ne changent pas:

sqlplus / as sysdba

set lines 80
col sid format 999999
col serial# format 999999
col username format a8
col resource_consumer_group format a25
select sid, serial#, username, resource_consumer_group
from v$session where sid=125;

SID SERIAL# USERNAME RESOURCE_CONSUMER_GROUP
--- ------- -------- -----------------------
125 15 SCOTT OTHER_GROUPS


begin
dbms_resource_manager.switch_consumer_group_for_sess (
session_id => 125,
session_serial => 15,
consumer_group => 'OOPS');
end;
/

set lines 80
col sid format 999999
col serial# format 999999
col username format a8
col resource_consumer_group format a25
select sid, serial#, username, resource_consumer_group
from v$session where sid=125;

SID SERIAL# USERNAME RESOURCE_CONSUMER_GROUP
--- ------- -------- -----------------------
125 15 SCOTT OOPS



set lines 120
COL name FORMAT A25 HEADING 'Resource|Consumer|Group'
COL active_sessions FORMAT 9999 HEADING 'Act|Sess'
COL execution_waiters FORMAT 9999 HEADING 'Exec|Wtrs'
COL requests FORMAT 9999 HEADING 'Reqs'
COL cpu_wait_time FORMAT 9999999 HEADING 'CPU|Wait|Time'
COL cpu_waits FORMAT 9999999 HEADING 'CPU|Waits'
COL consumed_cpu_time FORMAT 9999999 HEADING 'CPU|Time|Used'
COL yields FORMAT 9999 HEADING 'Ylds'
COL queue_length FORMAT 99999 HEADING 'Queue|Len'
COL current_undo_consumption FORMAT 99999 HEADING 'Curr|UNDO|Used'

SELECT
name
,active_sessions
,execution_waiters
,requests
,cpu_wait_time
,cpu_waits
,consumed_cpu_time
,yields
,queue_length
,current_undo_consumption
FROM v$rsrc_consumer_group;


Resource CPU CPU Curr
Consumer Act Exec Wait CPU Time Queue UNDO
Group Sess Wtrs Reqs Time Waits Used Ylds Len Used
------------------------- ----- ----- ----- -------- -------- -------- ----- ------ ------
OOPS 0 0 0 0 0 1 0 0 0
OTHER_GROUPS 1 0 8 0 0 216 0 0 0
_ORACLE_BACKGROUND_GROUP_ 21 0 28 0 0 0 0 0 0



col name format a20
select n.name, s.value
from v$sesstat s,
v$statname n
where s.statistic#=n.statistic#
and name like 'scheduler%'
and s.sid=125
order by value desc;

Resource
Consumer
Group VALUE
-------------------- ----------
scheduler wait time 0

Illustrer max_utilization_limit

Vous allez maintenant pourvoir générer de la CPU dans votre session SCOTT:

declare
x number;
begin
for i in 1..20000000 loop
x:=dbms_random.random;
end loop;
end;
/

Si en parallèle, vous observez l’utilisation CPU de votre système avec la commande top, vous constaterez que votre session utilise environ 17% de la CPU de votre serveur:

top - 02:32:44 up 15:49,  5 users,  load average: 0.39, 0.17, 0.06
Tasks: 198 total, 2 running, 196 sleeping, 0 stopped, 0 zombie
Cpu(s): 23.3%us, 3.4%sy, 0.0%ni, 71.9%id, 1.1%wa, 0.3%hi, 0.0%si, 0.0%s
Mem: 3566424k total, 2308264k used, 1258160k free, 255664k buffers
Swap: 4000144k total, 0k used, 4000144k free, 1588236k cached

PID USER PR NI VIRT RES SHR S %CPU %MEM TIME COMMAND
10827 oracle 20 0 665m 21m 20m S 33 0.6 0:22.94 oracle
1740 root 20 0 7992 5456 2212 S 10 0.2 0:06.28 devkit-power-da
1472 root 20 0 114m 40m 13m S 7 1.2 17:29.74 Xorg
5259 arkzoyd 20 0 47516 13m 9728 S 2 0.4 0:47.15 gnome-terminal
1988 arkzoyd 20 0 3168 912 732 S 1 0.0 0:20.47 syndaemon
2009 arkzoyd 20 0 155m 42m 7992 S 1 1.2 2:00.56 compiz.real

Pour cet exemple, j’ai utilisé mon laptop et Ubuntu Karmic Koala; Il s’agit d’un bi*core, d’où le fait que le process utilise ~34% d’un core. Vous noterez qu’il y a de petites variations mais que le seuil semble assez bien respecté; vous noterez également que la CPU controlée ne l’est que pour le groupe OOPS et que logiquement, mon laptop consomme plus que 17% de CPU

Vous pouvez observer l’utilisation de ressource manager depuis votre session connectée SYS:

set lines 120
COL name FORMAT A25 HEADING 'Resource|Consumer|Group'
COL active_sessions FORMAT 9999 HEADING 'Act|Sess'
COL execution_waiters FORMAT 9999 HEADING 'Exec|Wtrs'
COL requests FORMAT 9999 HEADING 'Reqs'
COL cpu_wait_time FORMAT 9999999 HEADING 'CPU|Wait|Time'
COL cpu_waits FORMAT 9999999 HEADING 'CPU|Waits'
COL consumed_cpu_time FORMAT 9999999 HEADING 'CPU|Time|Used'
COL yields FORMAT 9999 HEADING 'Ylds'
COL queue_length FORMAT 99999 HEADING 'Queue|Len'
COL current_undo_consumption FORMAT 99999 HEADING 'Curr|UNDO|Used'

SELECT
name
,active_sessions
,execution_waiters
,requests
,cpu_wait_time
,cpu_waits
,consumed_cpu_time
,yields
,queue_length
,current_undo_consumption
FROM v$rsrc_consumer_group;


Resource CPU CPU Curr
Consumer Act Exec Wait CPU Time Queue UNDO
Group Sess Wtrs Reqs Time Waits Used Ylds Len Used
------------------------- ----- ----- ----- -------- -------- -------- ----- ------ ------
OOPS 0 0 0 58467 92 31664 92 0 0
OTHER_GROUPS 1 0 9 0 0 246 0 0 0
_ORACLE_BACKGROUND_GROUP_ 21 0 29 0 0 0 0 0 0


col name format a20
select n.name, s.value
from v$sesstat s,
v$statname n
where s.statistic#=n.statistic#
and name like 'scheduler%'
and s.sid=125
order by value desc;

Group VALUE
-------------------- ----------
scheduler wait time 5987


select begin_time, consumer_group_name, cpu_consumed_time, cpu_wait_time
from v$rsrcmgrmetric_history
where consumer_group_name='OOPS'
order by begin_time;
CPU
Wait
BEGIN_TIM CONSUMER_GROUP_NAME CPU_CONSUMED_TIME Time
--------- ------------------------------ ----------------- --------
21-FEB-10 OOPS 0 0
21-FEB-10 OOPS 0 0
21-FEB-10 OOPS 0 0
21-FEB-10 OOPS 9082 16314
21-FEB-10 OOPS 20354 38386
21-FEB-10 OOPS 2227 3767
21-FEB-10 OOPS 0 0

Désactiver et supprimer le plan

Pour terminer votre test et laisser la base de données dans l’état dans lequel vous l’avez trouvée, lancez le script ci-dessous:

alter system set resource_manager_plan='';

begin
DBMS_RESOURCE_MANAGER.CLEAR_PENDING_AREA;
DBMS_RESOURCE_MANAGER.CREATE_PENDING_AREA;

DBMS_RESOURCE_MANAGER.DELETE_PLAN (
plan => 'LIMITED_CPU');
DBMS_RESOURCE_MANAGER.DELETE_CONSUMER_GROUP (
consumer_group=>'OOPS');

DBMS_RESOURCE_MANAGER.VALIDATE_PENDING_AREA;
DBMS_RESOURCE_MANAGER.SUBMIT_PENDING_AREA;
end;
/