ITPub博客

首页 > Linux操作系统 > Linux操作系统 > 基于事件驱动的Oracle作业调度

基于事件驱动的Oracle作业调度

原创 Linux操作系统 作者:realkid4 时间:2012-01-29 21:43:43 0 删除 编辑

 

对很多系统而言,作业调度Scheduler是不可缺少的部分。大数据量集中批量处理、OLAP数据聚集都需要利用业务空闲时段(如夜间)进行处理。Oracle自身提供了较为可靠的运行作业调度器机制,为我们提供了现成的Scheduler组件。

 

调度作业有两种大类型:基于时间(Time-Based)和基于事件(Event-Based)。基于时间的调度作业顾名思义,就是设置特定的时间调度规则。依据时间规则在特定的时间点触发执行代码程序。例如:每天夜间22:00执行数据聚合操作,生成聚合数据。在Oracle中,大部分的作业都是这种类型。比如从10G出现的统计信息收集作业,就是规定在工作日夜间22:00开始进行的基于时间作业。

 

基于事件的作业调度则是依据特定的事件场景。比如:在应用程序发生故障的时候,启动数据清理程序,将中间数据结果还原。这样的作业,调度时间是不确定的,依据具体的业务和程序场景。而且,基于事件作业执行的过程中,要具有作业的特性,也就是作业执行代码执行和触发作业程序之间是异步执行关系。

 

Oracle中,我们可以方便的时候dbms_scheduler包进行基于时间作业的定义。同样,我们可以借助Oracle消息队列的特性,来实现Event Based作业类型。

 

1、 原理和环境准备

 

为了更好说明问题,笔者选择Oracle 10R2作为实验环境,并且构建一个新的用户schema环境。

 

 

SQL> show user;

User is "SYS"

 

SQL> select * from v$version;

 

BANNER

----------------------------------------------------------------

Oracle Database 10g Enterprise Edition Release 10.2.0.1.0 - Prod

PL/SQL Release 10.2.0.1.0 - Production

CORE    10.2.0.1.0    Production

 

TNS for 32-bit Windows: Version 10.2.0.1.0 - Production

NLSRTL Version 10.2.0.1.0 Production

 

 

创建一个新用户testuser,并授予相应的系统和角色权限。

 

 

SQL> create user testuser identified by testuser ;

User created

 

SQL> alter user testuser quota unlimited on users;

User altered

 

SQL> grant connect to testuser;

Grant succeeded

 

SQL> grant create table to testuser;

Grant succeeded

 

SQL> grant create sequence to testuser;

Grant succeeded

 

SQL> grant create type to testuser;

Grant succeeded

 

SQL> GRANT AQ_ADMINISTRATOR_ROLE TO testuser;

Grant succeeded

 

SQL> GRANT CREATE JOB TO testuser;

Grant succeeded

 

 

只有设置了AQ_ADMINISTRATOR_ROLE角色,才能使用Oracle的Advanced Queue组件功能。

 

原理上:我们要利用Oracle的Advanced Queue组件的功能。要求在特定的Event发生时,我们需要向队列中传入一个标记对象。Scheduler会根据特定的标记对象标识来调用特定的作业Job代码程序。这样就实现了基本的Event Based Job。

 

2、日志插入作业

 

我们希望实现一个功能,就是在特定事件发生的时候,会向数据表中插入一条记录。

 

首先,我们准备代码数据表。

 

 

SQL> conn testuser/testuser@ots;

Connected to Oracle Database 10g Enterprise Edition Release 10.2.0.1.0

Connected as testuser

 

 

SQL> create sequence seq_test;

Sequence created

 

SQL> create table test_log (id number not null, comments varchar2(100), created date);

Table created

 

SQL> alter table test_log add constraint pk_test primary key (id);

Table altered

 

 

我们创建了日志数据表。当触发事件的时候,直接向该数据表中插入一条记录。

 

3、配置调度作业

 

首先,需要定义一个类型type,用于向AQ中触发作业。该type相当于事件发生的信息单元。

 

 

SQL> create or replace type t_event_que_payload as object (event_name varchar2(30));

  2  /

Type created

 

 

创建事件表,用来记录消息队列AQ中消息信息。

 

 

SQL> exec dbms_aqadm.create_queue_table(queue_table => 'event_queue_table',queue_payload_type => 't_event_que_payload',multiple_consumers => true,comment => 'Test Event Queue');

 

PL/SQL procedure successfully completed

 

 

使用dbms_aqadm方法create_queue_table中,两个最重要的参数:queue_table是创建消息表的名称,queue_payload_type则是规定了队列中存放对象的type类型。

 

执行后,的确创建了数据表event_queue_table。

 

 

SQL> desc event_queue_table;

Name              Type                Nullable Default Comments

----------------- ------------------- -------- ------- --------

Q_NAME            VARCHAR2(30)        Y                        

MSGID             RAW(16)                                      

CORRID            VARCHAR2(128)       Y                        

PRIORITY          NUMBER              Y         

(篇幅原因,有省略……

 

 

下面需要创建队列对象,单独执行出队列名称和队列数据表名称。

 

 

SQL> exec dbms_aqadm.create_queue(queue_name => 'event_queue',queue_table => 'event_queue_table');

PL/SQL procedure successfully completed

 

 

SQL> select name, queue_table, qid, queue_type,user_comment from user_queues;

 

NAME                           QUEUE_TABLE                           QID QUEUE_TYPE           USER_COMMENT

------------------------------ ------------------------------ ---------- -------------------- --------------------------------------------------------------------------------

EVENT_QUEUE                    EVENT_QUEUE_TABLE                  111623 NORMAL_QUEUE        

AQ$_EVENT_QUEUE_TABLE_E        EVENT_QUEUE_TABLE                  111622 EXCEPTION_QUEUE      exception queue

 

 

 

 

注意,为了队列AQ,Oracle要创建出多个数据表,用于进行不同的消息存储。同时,处于性能等多方面的考量,很多这样的数据表是采用IOT(Index-Organized Table)结构的。

 

 

SQL> select table_name, tablespace_name, iot_name,iot_type from user_tables;

 

TABLE_NAME                     TABLESPACE_NAME         IOT_NAME  IOT_TYPE

------------------------------ ------------------------------ ------------------------------ ------------

TEST_LOG                       USERS                                                        

EVENT_QUEUE_TABLE              USERS                                                         

AQ$_EVENT_QUEUE_TABLE_S        USERS                                                        

SYS_IOT_OVER_111613            USERS         AQ$_EVENT_QUEUE_TABLE_G        IOT_OVERFLOW

AQ$_EVENT_QUEUE_TABLE_I                                              IOT

AQ$_EVENT_QUEUE_TABLE_G                                              IOT

AQ$_EVENT_QUEUE_TABLE_H                                              IOT

AQ$_EVENT_QUEUE_TABLE_T                                              IOT

 

8 rows selected

 

 

最后,启动创建出的AQ队列event_queue。

 

 

SQL> EXEC DBMS_AQADM.start_queue (queue_name => 'event_queue');

PL/SQL procedure successfully completed

 

 

注意,此时队列状态开启为可用。

 

 

SQL> select name, queue_table, qid, queue_type,ENQUEUE_ENABLED, DEQUEUE_ENABLED from user_queues;

 

NAME                   QUEUE_TABLE          QID QUEUE_TYPE           ENQUEUE_ENABLED DEQUEUE_ENABLED

----------------------- ---------------------------------------- --------------- ---------------

EVENT_QUEUE             EVENT_QUEUE_TABLE   111623 NORMAL_QUEUE           YES             YES

AQ$_EVENT_QUEUE_TABLE_E  EVENT_QUEUE_TABLE  111622 EXCEPTION_QUEUE        NO              NO

 

 

队列创建到此结束。下面创建作业,使用dbms_scheduler方法。

 

 

SQL> begin

  2     dbms_scheduler.create_job(job_name => 'event_based_job',

  3                               job_type => 'PLSQL_BLOCK',

  4                               job_action => 'begin

  5                                 insert into test_log values (seq_test.nextval, ''TT'', sysdate);

  6                                 commit;

  7                               end;

  8                               ',

  9                               start_date=>systimestamp,

 10                               event_condition => 'tab.user_data.event_name = ''test_signal''',

 11                               queue_spec => 'event_queue',

 12                               enabled => TRUE);

 13  end;

 14  /

 

PL/SQL procedure successfully completed

 

SQL> select job_name, job_creator from user_scheduler_jobs;

 

JOB_NAME                       JOB_CREATOR

------------------------------ ------------------------------

EVENT_BASED_JOB                TESTUSER

 

 

注意包方法的几个主要参数。Job_name定义了新增加job的名称。Job_action定义了当这个Job被触发的时候,需要执行哪段代码。Event_condition规定了调度数据对象值为test_signal的时候才会执行这个作业。Queue_spec制定了监视事件的队列名称。

 

4、测试作业情况

 

我们模拟向队列中插入事件消息对象的场景。

 

 

SQL> DECLARE

  2    l_enqueue_options    DBMS_AQ.enqueue_options_t;

  3    l_message_properties DBMS_AQ.message_properties_t;

  4    l_message_handle     RAW(16);

  5    l_queue_msg          t_event_que_payload;

  6  BEGIN

  7    l_queue_msg := t_event_que_payload('test_signal'); --创建事件event消息对象;

  8 

  9    DBMS_AQ.enqueue(queue_name         => 'event_queue',

 10                    enqueue_options    => l_enqueue_options,

 11                    message_properties => l_message_properties,

 12                    payload            => l_queue_msg,

 13                    msgid              => l_message_handle);

 14    COMMIT;

 15  END;

 16  /

 

PL/SQL procedure successfully completed

 

 

在实际使用的时候,只需要向AQ队列中插入消息体。Oracle就可以根据消息的内容调用特定的作业。观察结果:

 

--作业效果;

SQL> select * from test_log;

 

        ID COMMENTS   CREATED

---------- ---------- -----------

         1 TT         2012/1/29 1

 

--作业执行记录;

SQL> col job_name for a20;

SQL> select log_date, job_name, job_class, status from user_scheduler_job_log;

 

LOG_DATE             JOB_NAME             JOB_CLASS                      STATUS

-------------------- -------------------- ------------------------------ ----------

29-1月 -12 01.43.47. EVENT_BASED_JOB      DEFAULT_JOB_CLASS              SUCCEEDED

484000 下午 +08:00                                                      

 

 

 

5、结论

 

event_based作业类型,在实际中出现的机率并不是很高。主要是一些数据现场恢复和清理工作。使用Oracle的AQ和调度器机制,我们可以方便的将这种类型作业加以实现。

来自 “ ITPUB博客 ” ,链接:http://blog.itpub.net/17203031/viewspace-715226/,如需转载,请注明出处,否则将追究法律责任。

请登录后发表评论 登录
全部评论
求道~

注册时间:2010-11-30

  • 博文量
    545
  • 访问量
    7568865