【RAC】rac中如何指定job的运行实例

一.1  BLOG文档结构图

【RAC】rac中如何指定job的运行实例 

 

一.2  前言部分

 

一.2.1  导读和注意事项

各位技术爱好者,看完本文后,你可以掌握如下的技能,也可以学到一些其它你所不知道的知识,~O(∩_∩)O~:

① 如何指定job的运行实例(重点)

② 代码获取rac所有节点的IP地址

 

  Tips:

       ① 若文章代码格式有错乱,推荐使用QQ、搜狗或360浏览器,也可以下载pdf格式的文档来查看,pdf文档下载地址:http://yunpan.cn/cdEQedhCs2kFz (提取码:ed9b) 

       ② 本篇BLOG中命令的输出部分需要特别关注的地方我都用灰色背景和粉红色字体来表示,比如下边的例子中,thread 1的最大归档日志号为33,thread 2的最大归档日志号为43是需要特别关注的地方;而命令一般使用黄色背景和红色字体标注;对代码或代码输出部分的注释一般采用蓝色字体表示。

 

  List of Archived Logs in backup set 11

  Thrd Seq     Low SCN    Low Time            Next SCN   Next Time

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

  1    32      1621589    2015-05-29 11:09:52 1625242    2015-05-29 11:15:48

  1    33      1625242    2015-05-29 11:15:48 1625293    2015-05-29 11:15:58

  2    42      1613951    2015-05-29 10:41:18 1625245    2015-05-29 11:15:49

  2    43      1625245    2015-05-29 11:15:49 1625253    2015-05-29 11:15:53

 

 

 

 

[ZFXXDB1:root]:/>lsvg -o

T_XDESK_APP1_vg

rootvg

[ZFXXDB1:root]:/>

00:27:22 SQL> alter tablespace idxtbs read write;

 

 

====》2097152*512/1024/1024/1024=1G 

 

 

 

本文如有错误或不完善的地方请大家多多指正,ITPUB留言或QQ皆可,您的批评指正是我写作的最大动力。

 

 

一.2.2  本文简介

记得之前写健康检查脚本的时候需要统计rac的IP地址,要用到一个包utl_inaddr.GET_HOST_ADDRESS,这样的话就得去每个实例去查询,想了想只能是job来完成了,但当时并不知道如何在rac环境中指定相应的实例去运行job,今天又特意研究了一下这个问题终于解决了,小麦苗迫不及待的分享给大家。

 

 

 

 

一.3  相关知识点扫盲(摘自网络)

oracle自从10g开始有2种job,dbms_job和DBMS_SCHEDULER,那么相应的就分2种情况下的指定实例了,先摘抄一点简单的job知识吧。DBMS_SCHEDULER是Oracle 10G中新增的一个包,与老版本的dbms_job包相比,dbms_scheduler有很多新特性。

所谓出于job而胜于job,说的就是Oracle10g后的新特性Scheduler啦。在10g环境中,ORACLE建议使用Scheduler替换普通的job,来管理任务的执行。其实,将Scheduler描述成管理job的工具已经太过片面了,10G版本中新增的Scheduler绝不仅仅是创建任务这么简单。。。。

ORACLE中管理Scheduler是通过DBMS_SCHEDULER包。。。

DBMS_JOB和DBMS_SCHEDULER之间的主要区别如下:

1. DBMS_SCHEDULER可以执行存储的程序、匿名块以及OS可执行文件和脚本(包括linux系统的shell脚本),而DBMS_JOB只可以执行存储的程序或匿名的PL/SQL块。

2. 考虑到增强的组件重用,调度程序的程序单元作为模式对象存储。DBMS_JOB只有一种组件,即作业;而调度程序具有组件层次结构。

3. 可以使用DBMS_SCHEDULER更具描述性地定义作业或进度表间隔。DBMS_ SCHEDULER也具有更详细的作业运行状态以及故障处理和报告功能。

 

一.4  dbms_job下指定实例运行job

一.4.1  相关知识简介(摘自网络)

一个JOB在何级别运行是可以定制的。如果把job定义在db级,job可以运行在任何活动的instance上,并遵循job的调度机制;如果把job定义在instance级别上,job将运行在指定的实例上,如因某种异常导致创建job的实例当机,那job将运行在存活的实例上。 

1、目前我们的rac数据库是通过查询语句 select job,instance,what from dba_jobs 可以看到instance=0,这表示该job是db级,可以运行在任何活动的instance上,由job的调度机制决定在哪个实例上运行。也就是说RAC会根据两台服务器的运行状态来调度JOB在不同的节点实例中运行,一个JOB可以在A机,下一次有可能在B机运行; 
2、通过在调度中指定instance 参数,可以指定job只在某个特定实例上运行,但是如果该实例的服务器出现故障时,发现job 在实例A上不再运行,也不会切换到其它实例。如果job建立时没有指定运行在某个实例上,在job当前运行的实例关掉后,却可以切到其他活动的实例上。 
【RAC】rac中如何指定job的运行实例

一.4.1.1  官方文档内容

利用小麦苗提供的工具搜索官方文档,看到如下的内容:

【RAC】rac中如何指定job的运行实例 

一.4.1.2  Working with Oracle Real Application Clusters

DBMS_JOB supports multi-instance execution of jobs. By default jobs can be executed on any instance, but only one single instance will execute the job. In addition, you can force instance binding by binding the job to a particular instance. You implement instance binding by specifying an instance number to the instance affinity parameter. Note, however, that in Oracle Database 10g Release 1 (10.1) instance binding is not recommended. Service affinity is preferred. This concept is implemented in the DBMS_SCHEDULER package.

The following procedures can be used to create, alter or run jobs with instance affinity. Note that not specifying affinity means any instance can run the job.

一、 DBMS_JOB.SUBMIT

To submit a job to the job queue, use the following syntax:

DBMS_JOB.SUBMIT(

   job       OUT    BINARY_INTEGER,

   what      IN     VARCHAR2, NEXT_DATE IN DATE DEFAULTSYSDATE,

   interval  IN     VARCHAR2 DEFAULT 'NULL',

   no_parse  IN     BOOLEAN DEFAULT FALSE,

   instance  IN     BINARY_INTEGER DEFAULT ANY_INSTANCE,

   force     IN     BOOLEAN DEFAULT FALSE);

Use the parameters instance and force to control job and instance affinity. The default value of instance is 0 (zero) to indicate that any instance can execute the job. To run the job on a certain instance, specify theinstance value. Oracle displays error ORA-23319 if the instance value is a negative number or NULL.

The force parameter defaults to false. If force is TRUE, any positive integer is acceptable as the job instance. If force is FALSE, the specified instance must be running, or Oracle displays error number ORA-23428.

 

二、 DBMS_JOB.INSTANCE

To assign a particular instance to execute a job, use the following syntax:

   DBMS_JOB.INSTANCE(  JOB IN BINARY_INTEGER,

     instance                IN BINARY_INTEGER,

     force                   IN BOOLEAN DEFAULT FALSE);

The FORCE parameter in this example defaults to FALSE. If the instance value is 0 (zero), job affinity is altered and any available instance can execute the job despite the value of force. If the INSTANCE value is positive and theFORCE parameter is FALSE, job affinity is altered only if the specified instance is running, or Oracle displays errorORA-23428.

If the force parameter is TRUE, any positive integer is acceptable as the job instance and the job affinity is altered. Oracle displays error ORA-23319 if the instance value is negative or NULL.

说的还是比较详细的。

 

一.4.2  一个测试案例(获取所有节点的IP地址)

代码如下,dbms_network_acl_admin主要是为了解决ORA-24247错误,很多年不做开发,写plsql的能力还是存在的,o(∩_∩)o :

--- ORA-24247, "network access denied by access control list (ACL)"

begin

  dbms_network_acl_admin.drop_acl(acl => 'UTL_INADDR_LHR.xml');

  commit;

end;

/

begin

  dbms_network_acl_admin.create_acl(acl         => 'UTL_INADDR_LHR.xml',

                                    description => 'UTL_INADDR',

                                    principal   => 'MDSYS',

                                    is_grant    => TRUE,

                                    privilege   => 'resolve');

  commit;

 

  dbms_network_acl_admin.add_privilege(acl       => 'UTL_INADDR_LHR.xml',

                                       principal => 'MDSYS',

                                       is_grant  => TRUE,

                                       privilege => 'connect');

  commit;

  

   dbms_network_acl_admin.assign_acl(acl        => 'UTL_INADDR_LHR.xml',

                                     host       => '*');

  commit;

 

end;

/

 

drop table t_ipaddress_lhr; 

create table t_ipaddress_lhr(INST_ID number, host_name varchar2(255), host_ip  varchar2(255) );

 

create or replace view vh_ipaddress_lhr as 

SELECT a.HOST_ID || ': ' || a.HOST_ADDRESS host_ip1,

       a.HOST_ADDRESS host_ip2,

  a.HOST_ID host_name2

        FROM v$diag_alert_ext a

       WHERE a.COMPONENT_ID = 'rdbms'

         AND upper(a.FILENAME) =

             (SELECT upper(substr(d.VALUE, 1, (length(d.VALUE) - 5)) ||

                           'alert' || substr(d.VALUE, -6, 1) || 'log.xml')

                FROM v$parameter d

               WHERE d.NAME = 'background_dump_dest')

         and a.INDX =

             (SELECT max(b.INDX)

                FROM v$diag_alert_ext b

               WHERE b.COMPONENT_ID = 'rdbms'

                 and upper(b.FILENAME) =

                     (SELECT upper(substr(d.VALUE, 1, (length(d.VALUE) - 5)) ||

                                   'alert' || substr(d.VALUE, -6, 1) ||

                                   'log.xml')

                        FROM v$parameter d

                       WHERE d.NAME = 'background_dump_dest'));  

/

 

create or replace procedure ph_ip_lhr as

 

  V_SQL VARCHAR2(4000);

begin

 

  insert into t_ipaddress_lhr

    (inst_id, host_name)

    SELECT v.INSTANCE_NUMBER, v.HOST_NAME FROM v$instance v;

  commit;

 

  V_SQL := 'update t_ipaddress_lhr t

     set t.host_ip = utl_inaddr.GET_HOST_ADDRESS

   where t.inst_id = userenv(''instance'')';

 

  EXECUTE IMMEDIATE V_SQL;

 

  commit;

 

exception

  when others then

 

    V_SQL := 'update t_ipaddress_lhr t

       set t.host_ip =

           (SELECT v.host_ip2 FROM vh_ipaddress_lhr v)

     where t.inst_id = userenv(''instance'')';

    EXECUTE IMMEDIATE V_SQL;

    commit;

 

end ph_ip_lhr;

/

 

DECLARE

  X NUMBER;

begin

 

  for cur in (select b.JOB

                from dba_jobs b

               where b.WHAT = 'ph_ip_lhr;') loop

 

    sys.dbms_ijob.remove(cur.JOB);

    COMMIT;

  end loop;

 

  for cur in (select b.INST_ID from gv$instance b) loop

 

    SYS.DBMS_JOB.SUBMIT(job       => X,

                        what      => 'ph_ip_lhr;',

                        next_date => SYSDATE+cur.inst_id/8640,

                        INTERVAL  => 'null',

                        no_parse  => FALSE,

                        instance  => cur.inst_id);

    COMMIT;

  end loop;

END;

/

 

 

查看结果:

SELECT * FROM t_ipaddress_lhr;

【RAC】rac中如何指定job的运行实例 

 

一.5  DBMS_SCHEDULER下指定实例运行job

 

一.5.1  相关知识简介

一.5.1.1  JobClasses

JobClasses相当于创建了一个job组,DBA可以将那些具有相同特性的job,统统放到相同的JobClasses

中,然后通过对JobClass应用ORACLE中的"资源使用计划"特性,就可以对这些job执行过程中所需要的资源分配情况进行管理。

1、创建JobClasses

使用DBMS_SCHEDULER包的CREATE_JOB_CLASS过程创建JobClasses,该过程支持的参数如下,用plsql developer的命令行查看:

16:45:22 SQL> desc dbms_scheduler.create_job_class;

Parameter               Type           Mode Default?

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

JOB_CLASS_NAME          VARCHAR2       IN           

RESOURCE_CONSUMER_GROUP VARCHAR2       IN   Y       

SERVICE                 VARCHAR2       IN   Y       

LOGGING_LEVEL           BINARY_INTEGER IN   Y       

LOG_HISTORY             BINARY_INTEGER IN   Y       

COMMENTS                VARCHAR2       IN   Y

 

其中:

v JOB_CLASS_NAME:要创建的JobClass的名称,注意指定的长度不要超过30个字符,也不要与现有JobClass同名;

v RESOURCE_CONSUMER_GROUP:指定创建的JobClass所在的RCG;

提示:啥是ResourceConsumerGroup

你可以将其理解成一个资源分配的方式,处于相同RCG组中的用户、会话、或者对象共用一组资源,

这组资源中可供分配的资源按照DBA指定的方式分配给RCG。如果设计合理,通过这种方式,可以更有效的利用服务器的资源。

v SERVICE:指定创建的JobClass所在Service,本选项常见于RAC环境,我们都知道RAC环境由多

实例+数据库组成,此处所指定的Service实际就是指JobClass会在哪个实例上运行。

注意:本参数与RESOURCE_CONSUMER_GROUP参数相互冲突,同一个JobClass只同设置两个参

数中的一个值。

v  LOGGING_LEVEL:指定日志记录的级别,有下列三种级别,是DBMS_SCHEDULER包中的三个常量:

① DBMS_SCHEDULER.LOGGING_OFF:关闭日志记录功能;

② DBMS_SCHEDULER.LOGGING_RUNS:对该JobClass下所有任务的运行信息进行记录;

③ DBMS_SCHEDULER.LOGGING_FULL:记录该JobClass下任务的所有相关信息,不仅有任务运行情况,甚至连任务的创建、修改等也均将记入日志。

一、 官方文档对service的解释

【RAC】rac中如何指定job的运行实例 

service

This attribute specifies the database service that the jobs in this class have affinity to. In an Oracle RAC environment, this means that the jobs in this class only run on those database instances that are assigned to the specific service.

Note that a service can be mapped to a resource consumer group, so you can also control resources allocated to jobs by specifying a service. SeeDBMS_RESOURCE_MANAGER.SET_CONSUMER_GROUP_MAPPING for details. If both theresource_consumer_group and service attributes are specified, and if the service is mapped to a resource consumer group, the resource_consumer_group attribute takes precedence.

If no service is specified, the job class belongs to the default service, which means it has no service affinity and any one of the database instances within the cluster might run the job. If the service that a job class belongs to is dropped, the job class will then belong to the default service.

If the specified service does not exist when creating the job class, then an error occurs.

 

 

 

一.5.1.2  创建service

基于RAC环境中使用的应用程序,有时候希望某个特定的应用程序仅仅运行在RAC的子节点,或者说为某些应用程序分配一个首要节点。对此,Oracle 可以使用services来实现。

这个具体可以参考官方文档:Oracle® Database PL/SQL Packages and Types Reference 11gRelease 2 (11.2) E40758-03

 

 

 

 

一.5.2  一个测试案例(获取所有节点的IP地址)

 

--- ORA-24247, "network access denied by access control list (ACL)"

begin

  dbms_network_acl_admin.drop_acl(acl => 'UTL_INADDR_LHR.xml');

  commit;

end;

/

begin

  dbms_network_acl_admin.create_acl(acl         => 'UTL_INADDR_LHR.xml',

                                    description => 'UTL_INADDR',

                                    principal   => 'MDSYS',

                                    is_grant    => TRUE,

                                    privilege   => 'resolve');

  commit;

 

  dbms_network_acl_admin.add_privilege(acl       => 'UTL_INADDR_LHR.xml',

                                       principal => 'MDSYS',

                                       is_grant  => TRUE,

                                       privilege => 'connect');

  commit;

  

   dbms_network_acl_admin.assign_acl(acl        => 'UTL_INADDR_LHR.xml',

                                     host       => '*');

  commit;

 

end;

/

 

drop table t_ipaddress_lhr; 

create table t_ipaddress_lhr(INST_ID number, host_name varchar2(255), host_ip  varchar2(255) );

 

create or replace view vh_ipaddress_lhr as 

SELECT a.HOST_ID || ': ' || a.HOST_ADDRESS host_ip1,

       a.HOST_ADDRESS host_ip2,

  a.HOST_ID host_name2

        FROM v$diag_alert_ext a

       WHERE a.COMPONENT_ID = 'rdbms'

         AND upper(a.FILENAME) =

             (SELECT upper(substr(d.VALUE, 1, (length(d.VALUE) - 5)) ||

                           'alert' || substr(d.VALUE, -6, 1) || 'log.xml')

                FROM v$parameter d

               WHERE d.NAME = 'background_dump_dest')

         and a.INDX =

             (SELECT max(b.INDX)

                FROM v$diag_alert_ext b

               WHERE b.COMPONENT_ID = 'rdbms'

                 and upper(b.FILENAME) =

                     (SELECT upper(substr(d.VALUE, 1, (length(d.VALUE) - 5)) ||

                                   'alert' || substr(d.VALUE, -6, 1) ||

                                   'log.xml')

                        FROM v$parameter d

                       WHERE d.NAME = 'background_dump_dest'));  

/

 

create or replace procedure ph_ip_lhr as

 

  V_SQL VARCHAR2(4000);

begin

 

  insert into t_ipaddress_lhr

    (inst_id, host_name)

    SELECT v.INSTANCE_NUMBER, v.HOST_NAME FROM v$instance v;

  commit;

 

  V_SQL := 'update t_ipaddress_lhr t

     set t.host_ip = utl_inaddr.GET_HOST_ADDRESS

   where t.inst_id = userenv(''instance'')';

 

  EXECUTE IMMEDIATE V_SQL;

 

  commit;

 

exception

  when others then

 

    V_SQL := 'update t_ipaddress_lhr t

       set t.host_ip =

           (SELECT v.host_ip2 FROM vh_ipaddress_lhr v)

     where t.inst_id = userenv(''instance'')';

    EXECUTE IMMEDIATE V_SQL;

    commit;

 

end ph_ip_lhr;

/

 

begin

 

  for cur in (select v.INST_ID,

                     v.INSTANCE_NAME,

                     'INST_LHR_' || v.inst_id service_name,

                     'LHR_RAC' || v.INST_ID || '_JOB_CLASS' job_class_name,

                     'RAC_LHR_' || V.INST_ID JOB_NAME

                from gv$instance v) loop

    begin

      dbms_service.stop_service(service_name  => cur.service_name,

                                instance_name => cur.instance_name);

      dbms_service.delete_service(service_name => cur.service_name);

    exception

      when others then

        null;

    end;

    begin

      dbms_scheduler.drop_job_class(job_class_name => cur.job_class_name,

                                    force          => true);

    exception

      when others then

        null;

    end;

    begin

      dbms_scheduler.drop_job(job_name => CUR.JOB_NAME, force => TRUE);

    exception

      when others then

        null;

    end;

  end loop;

 

  for cur in (select v.INST_ID,

                     v.INSTANCE_NAME,

                     'INST_LHR_' || v.inst_id service_name,

                     'LHR_RAC' || v.INST_ID || '_JOB_CLASS' job_class_name,

                     'RAC_LHR_' || V.INST_ID JOB_NAME

                from gv$instance v) loop

 

    dbms_service.create_service(service_name => cur.service_name,

                                network_name => cur.service_name);

    dbms_service.start_service(service_name  => cur.service_name,

                               instance_name => cur.instance_name);

 

    dbms_scheduler.create_job_class(job_class_name => cur.job_class_name,

                                    service        => cur.service_name);

 

    DBMS_SCHEDULER.create_job(job_name        => 'RAC_LHR_' || CUR.INST_ID,

                              job_type        => 'STORED_PROCEDURE',

                              job_action      => 'ph_ip_lhr',

                              repeat_interval => NULL, --'FREQ=MINUTELY;INTERVAL=1'

                              job_class       => cur.job_class_name,

                              end_date        => NULL,

                              enabled         => TRUE);

 

  end loop;

end;

/

 

查看结果:

SELECT * FROM t_ipaddress_lhr;

【RAC】rac中如何指定job的运行实例 

 

一.6  总结

简单点:

① dbms_job下指定实例运行job的方法是执行SYS.DBMS_JOB.SUBMIT包创建job的时候指定instance参数,很简单

② DBMS_SCHEDULER下指定实例运行job稍微有点复杂,创建service,创建job_class,然后创建job才可以,具体参考案例的代码。


上一篇:一步一步搭建 oracle 11gR2 rac+dg之grid安装(四)


下一篇:【DB宝44】Oracle rac集群中的IP类型简介