#topicpath
----
2つのDBでマルチマスタレプリケーションしてみました。

#contents

* 参考文献 [#y5cddb5f]

- [[Oracle Databaseアドバンスト・レプリケーション・マネージメントAPIリファレンス 10g リリース2(10.2):http://otndnld.oracle.co.jp/document/products/oracle10g/102/doc_cd/server.102/B19220-02/toc.htm]]
- [[Oracle Databaseアドバンスト・レプリケーション 10gリリース2(10.2):http://otndnld.oracle.co.jp/document/products/oracle10g/102/doc_cd/server.102/B19219-02/toc.htm]]

* 環境 [#o3f01dc0]

- Solaris 10 (x64_64)
- Oracle Database 10g R2

* DBの構成 [#n21aed53]

- SDB1 (service_names=SDB1.sugimura.cc)
- SDB2 (service_names=SDB2.sugimura.cc)

2つDBを作成して、この間で互いにレプリケーションしてみます。

Net Services の設定をして、それぞれこの名前でつながるようにしておきます。

* レプリケーション対象 [#b217946c]

- SCOTTスキーマの4つの表
-- DEPT
-- EMP
-- BONUS
-- SALGRADE

入っていなければ、$ORACLE_HOME/rdbms/admin/utlsampl.sql からインストールしておきます。

#pre{{
-bash-3.00$ export ORACLE_SID=SDB1
-bash-3.00$ sqlplus / as sysdba @?/rdbms/admin/utlsampl
-bash-3.00$ export ORACLE_SID=SDB2
-bash-3.00$ sqlplus / as sysdba @?/rdbms/admin/utlsampl
}}

* 方針 [#kd5a8003]

MVIEW も使わず、最も簡単な構成で進めました。

- マスター・サイトの設定
- マスター・グループの設定

基本的にはマニュアルに従うだけです。

* マスター・サイトの設定 [#z8191080]

** SDB1.sugimura.cc の設定 [#yc608ee3]

sdb1.sql を下記のように書いて、sqlplus から流します。

#pre{{
-bash-3.00$ sqlplus /nolog @sdb1.sql
}}

#pre{{
-bash-3.00$ cat sdb1.sql
spool sdb1.log

connect system/oracle@sdb1.sugimura.cc

CREATE USER repadmin IDENTIFIED BY repadmin;
BEGIN
   DBMS_REPCAT_ADMIN.GRANT_ADMIN_ANY_SCHEMA (
      username => 'repadmin');
END;
/

GRANT COMMENT ANY TABLE TO repadmin;
GRANT LOCK ANY TABLE TO repadmin;
GRANT SELECT ANY DICTIONARY TO repadmin;

BEGIN
   DBMS_DEFER_SYS.REGISTER_PROPAGATOR (
      username => 'repadmin');
END;
/

BEGIN
   DBMS_REPCAT_ADMIN.REGISTER_USER_REPGROUP (
      username => 'repadmin',
      privilege_type => 'receiver',
      list_of_gnames => NULL);
END;
/

CONNECT repadmin/repadmin@sdb1.sugimura.cc

BEGIN
   DBMS_DEFER_SYS.SCHEDULE_PURGE (
      next_date => SYSDATE,
      interval => 'SYSDATE + 1/24',
      delay_seconds => 0);
END;
/

spool off
quit
}}

** SDB2.sugimura.cc の設定 [#dd8121f4]

SDB1 とほぼ同じです。

#pre{{
-bash-3.00$ cat sdb2.sql 
spool sdb2.log

conn system/oracle@sdb2.sugimura.cc

CREATE USER repadmin IDENTIFIED BY repadmin;

BEGIN
   DBMS_REPCAT_ADMIN.GRANT_ADMIN_ANY_SCHEMA (
      username => 'repadmin');
END;
/

GRANT COMMENT ANY TABLE TO repadmin;
GRANT LOCK ANY TABLE TO repadmin;
GRANT SELECT ANY DICTIONARY TO repadmin;

BEGIN
   DBMS_DEFER_SYS.REGISTER_PROPAGATOR (
      username => 'repadmin');
END;
/

BEGIN
   DBMS_REPCAT_ADMIN.REGISTER_USER_REPGROUP (
      username => 'repadmin',
      privilege_type => 'receiver',
      list_of_gnames => NULL);
END;
/

CONNECT repadmin/repadmin@sdb2.sugimura.cc

BEGIN
   DBMS_DEFER_SYS.SCHEDULE_PURGE (
      next_date => SYSDATE,
      interval => 'SYSDATE + 1/24',
      delay_seconds => 0);
END;
/

spool off
quit
}}

** スケジュール・リンクの作成 [#i8deca9c]

#pre{{
-bash-3.00$ cat dblink.sql
spool dblink.log

-- dblink: sdb1.sugimura.cc
conn system/oracle@sdb1.sugimura.cc
create public database link sdb2.sugimura.cc using 'sdb2.sugimura.cc';

conn repadmin/repadmin@sdb1.sugimura.cc
create database link sdb2.sugimura.cc connect to repadmin identified by repadmin;

-- dblink: sdb2.sugimura.cc
conn system/oracle@sdb2.sugimura.cc
create public database link sdb1.sugimura.cc using 'sdb1.sugimura.cc';

conn repadmin/repadmin@sdb2.sugimura.cc
create database link sdb1.sugimura.cc connect to repadmin identified by repadmin;

-- schedule: sdb1.sugimura.cc
conn repadmin/repadmin@sdb1.sugimura.cc

BEGIN
   DBMS_DEFER_SYS.SCHEDULE_PUSH (
      destination => 'sdb2.sugimura.cc',
      interval => 'SYSDATE + (1/144)',
      next_date => SYSDATE,
      parallelism => 1,
      execution_seconds => 1500,
      delay_seconds => 1200);
END;
/

-- schedule: sdb2.sugimura.cc
conn repadmin/repadmin@sdb2.sugimura.cc

BEGIN
   DBMS_DEFER_SYS.SCHEDULE_PUSH (
      destination => 'sdb1.sugimura.cc',
      interval => 'SYSDATE + (1/144)',
      next_date => SYSDATE,
      parallelism => 1,
      execution_seconds => 1500,
      delay_seconds => 1200);
END;
/

spool off
quit
}}

* マスター・グループの設定 [#yff2f338]

** マスター・グループの作成 [#vc2f29fb]

マスター・グループを作成したサイトが
「マスター定義サイト」となります。
SDB1 をマスター定義サイトとします。

scott_repg という名前にしました。

#pre{{
conn repadmin/repadmin@SDB1.sugimura.cc

-- repgroup
BEGIN
   DBMS_REPCAT.CREATE_MASTER_REPGROUP (
      gname => 'scott_repg');
END;
/
}}

** オブジェクトをマスター・グループに追加 [#f89bed72]

scott_repg に4つの表を追加します。

#pre{{
conn repadmin/repadmin@SDB1.sugimura.cc

-- object
BEGIN
   DBMS_REPCAT.CREATE_MASTER_REPOBJECT (
      gname => 'scott_repg',
      type => 'TABLE',
      oname => 'dept',
      sname => 'scott',
      use_existing_object => TRUE,
      copy_rows => FALSE);
END;
/

BEGIN
   DBMS_REPCAT.CREATE_MASTER_REPOBJECT (
      gname => 'scott_repg',
      type => 'TABLE',
      oname => 'emp',
      sname => 'scott',
      use_existing_object => TRUE,
      copy_rows => FALSE);
END;
/

BEGIN
   DBMS_REPCAT.CREATE_MASTER_REPOBJECT (
      gname => 'scott_repg',
      type => 'TABLE',
      oname => 'bonus',
      sname => 'scott',
      use_existing_object => TRUE,
      copy_rows => FALSE);
END;
/

BEGIN
   DBMS_REPCAT.CREATE_MASTER_REPOBJECT (
      gname => 'scott_repg',
      type => 'TABLE',
      oname => 'salgrade',
      sname => 'scott',
      use_existing_object => TRUE,
      copy_rows => FALSE);
END;
/
}}

** マスター・サイトの追加 [#td5e6912]

レプリケーション先である SDB2 を追加します。

#pre{{
conn repadmin/repadmin@SDB1.sugimura.cc

-- master site
BEGIN
   DBMS_REPCAT.ADD_MASTER_DATABASE (
      gname => 'scott_repg',
      master => 'sdb2.sugimura.cc',
      use_existing_objects => TRUE,
      copy_rows => FALSE,
      propagation_mode => 'ASYNCHRONOUS');
END;
/
}}

** 追加されたことを確認 [#z67718a4]

dba_repsites で設定を確認します。SDB2 があればOKです。

#pre{{
-bash-3.00$ sqlplus repadmin/repadmin@SDB1.sugimura.cc
...
SQL> 
SQL> col gname format a10
SQL> col dblink format a20
SQL> select gname, dblink, masterdef from dba_repsites;

GNAME      DBLINK               MAS
---------- -------------------- ---
SCOTT_REPG SDB1.SUGIMURA.CC     Y
SCOTT_REPG SDB2.SUGIMURA.CC     N

SQL> 
}}

** レプリケーション・サポートを生成 [#e92c5682]

必要なパッケージやトリガーを作るようです。

#pre{{
conn repadmin/repadmin@SDB1.sugimura.cc

BEGIN
    DBMS_REPCAT.GENERATE_REPLICATION_SUPPORT (
      sname => 'scott',
      oname => 'dept',
      type => 'TABLE',
      min_communication => TRUE);
END;
/

BEGIN
    DBMS_REPCAT.GENERATE_REPLICATION_SUPPORT (
      sname => 'scott',
      oname => 'emp',
      type => 'TABLE',
      min_communication => TRUE);
END;

/
BEGIN
    DBMS_REPCAT.GENERATE_REPLICATION_SUPPORT (
      sname => 'scott',
      oname => 'bonus',
      type => 'TABLE',
      min_communication => TRUE);
END;
/

BEGIN
    DBMS_REPCAT.GENERATE_REPLICATION_SUPPORT (
      sname => 'scott',
      oname => 'salgrade',
      type => 'TABLE',
      min_communication => TRUE);
END;
/
}}

** レプリケーション開始前の確認 [#d27f8941]

dba_repcatlog が空になると始められるとのことですが、
このような状態になってしまいました。

#pre{{
SQL> select count(*) from dba_repcatlog where gname = 'SCOTT_REPG';

  COUNT(*)
----------
        19

SQL> 
}}

詳しく見てみます。

#pre{{
SQL> col status format a20
SQL> col sname format a10
SQL> col oname format a10
SQL> select status, sname, oname from dba_repcatlog where gname = 'SCOTT_REPG';

STATUS               SNAME      ONAME
-------------------- ---------- ----------
AWAIT_CALLBACK       SCOTT      DEPT
READY                SCOTT      DEPT
AWAIT_CALLBACK
AWAIT_CALLBACK       SCOTT      DEPT
AWAIT_CALLBACK       SCOTT      BONUS
AWAIT_CALLBACK       SCOTT      SALGRADE
AWAIT_CALLBACK       SCOTT      EMP
AWAIT_CALLBACK       SCOTT_REPG -1
READY                SCOTT_REPG -1
READY                SCOTT      DEPT
READY                SCOTT      EMP

STATUS               SNAME      ONAME
-------------------- ---------- ----------
AWAIT_CALLBACK       SCOTT      EMP
READY                SCOTT      EMP
READY                SCOTT      BONUS
AWAIT_CALLBACK       SCOTT      BONUS
READY                SCOTT      BONUS
READY                SCOTT      SALGRADE
AWAIT_CALLBACK       SCOTT      SALGRADE
READY                SCOTT      SALGRADE

19行が選択されました。

SQL> 
}}

初期化パラメータ job_queue_processes が 0 になっていたのが原因でした。
2サイトあるので、2にして上げ直します。

#pre{{
SQL> select count(*) from dba_repcatlog where gname = 'SCOTT_REPG';

  COUNT(*)
----------
        11

SQL> 
}}

減りましたが0にはなりません。

STATUS が ERROR となっている行がありました。

#pre{{
SQL> select status, message from dba_repcatlog where gname = 'SCOTT_REPG';

STATUS
------------------------------------------
MESSAGE
--------------------------------------------------------------------------------
ERROR
ORA-23416: 表"SCOTT"."BONUS"に主キー制約がありません。

ERROR
ORA-23416: 表"SCOTT"."BONUS"に主キー制約がありません。

ERROR
ORA-23416: 表"SCOTT"."SALGRADE"に主キー制約がありません。


STATUS
------------------------------------------
MESSAGE
--------------------------------------------------------------------------------
ERROR
ORA-23416: 表"SCOTT"."SALGRADE"に主キー制約がありません。


SQL> 
}}

そうですか、というわけで制約を追加します。

#pre{{
SQL> conn scott/tiger@SDB1
接続されました。
SQL> alter table bonus add constraint bonus_pk primary key (ename, job);

表が変更されました。

SQL> alter table salgrade add constraint salgrade_pk primary key (grade);

表が変更されました。

SQL> 
}}

SDB2 でも追加しておいたほうがいいのかなということで、
こちらでも。

#pre{{
SQL> conn scott/tiger@SDB2
接続されました。
SQL> alter table bonus add constraint bonus_pk primary key (ename, job);

表が変更されました。

SQL> alter table salgrade add constraint salgrade_pk primary key (grade);

表が変更されました。

SQL> 
}}

作り直すため、オブジェクトを消します。

#pre{{
conn repadmin/repadmin@SDB1.sugimura.cc

-- drop
BEGIN
   DBMS_REPCAT.DROP_MASTER_REPOBJECT (
      type => 'TABLE',
      oname => 'bonus',
      sname => 'scott');
END;
/

BEGIN
   DBMS_REPCAT.DROP_MASTER_REPOBJECT (
      type => 'TABLE',
      oname => 'salgrade',
      sname => 'scott');
END;
/
}}

オブジェクトを消したらログも消します。

#pre{{
SQL> exec dbms_repcat.purge_master_log( id=>NULL, source=>NULL, gname=>'SCOTT_REPG');

PL/SQLプロシージャが正常に完了しました。

SQL> 
SQL> select count(*) from dba_repcatlog where gname = 'SCOTT_REPG';

  COUNT(*)
----------
         0

SQL> 
}}

まっさらにしたので、また作り直します。

#pre{{
-- create
BEGIN
   DBMS_REPCAT.CREATE_MASTER_REPOBJECT (
      gname => 'scott_repg',
      type => 'TABLE',
      oname => 'bonus',
      sname => 'scott',
      use_existing_object => TRUE,
      copy_rows => FALSE);
END;
/

BEGIN
   DBMS_REPCAT.CREATE_MASTER_REPOBJECT (
      gname => 'scott_repg',
      type => 'TABLE',
      oname => 'salgrade',
      sname => 'scott',
      use_existing_object => TRUE,
      copy_rows => FALSE);
END;
/

-- support
BEGIN
    DBMS_REPCAT.GENERATE_REPLICATION_SUPPORT (
      sname => 'scott',
      oname => 'bonus',
      type => 'TABLE',
      min_communication => TRUE);
END;
/

BEGIN
    DBMS_REPCAT.GENERATE_REPLICATION_SUPPORT (
      sname => 'scott',
      oname => 'salgrade',
      type => 'TABLE',
      min_communication => TRUE);
END;
/
}}

再度 dba_repcatlog を確認してみます。

#pre{{
SQL> select count(*) from dba_repcatlog where gname = 'SCOTT_REPG';

  COUNT(*)
----------
         0

SQL> 
}}

ようやくこれで準備完了です。

** レプリケーションを開始 [#cbedd19a]

#pre{{
conn repadmin/repadmin@SDB1.sugimura.cc

BEGIN
   DBMS_REPCAT.RESUME_MASTER_ACTIVITY (
      gname => 'scott_repg');
END;
/
}}

* 動作確認 [#yff29ef6]

** SDB1 → SDB2 [#c87dda40]

DEPT表に1行追加してみます。

#pre{{
SQL> conn scott/tiger@sdb1
接続されました。
SQL> insert into dept values (50, 'WORK1', 'TOKYO');

1行が作成されました。

SQL> commit;

コミットが完了しました。

SQL> 
}}

しばらくしてから SDB2 で見てみます。

#pre{{
SQL> conn scott/tiger@sdb2
接続されました。
SQL> set lines 1000  
SQL> select * from dept; 

    DEPTNO DNAME                                      LOC
---------- ------------------------------------------ ---------------------------------------
        10 ACCOUNTING                                 NEW YORK
        20 RESEARCH                                   DALLAS
        30 SALES                                      CHICAGO
        40 OPERATIONS                                 BOSTON
        50 WORK1                                      TOKYO

SQL> 
}}

SDB1 で追加した行が SDB2 に反映されました。

** SDB2 → SDB1 [#z150d0c3]

今度は SALGRADE 表から1行消してみます。

#pre{{
SQL> conn scott/tiger@sdb2
接続されました。
SQL> select * from salgrade;

     GRADE      LOSAL      HISAL
---------- ---------- ----------
         1        700       1200
         2       1201       1400
         3       1401       2000
         4       2001       3000
         5       3001       9999

SQL> delete from salgrade where grade = 3;

1行が削除されました。

SQL> commit;

コミットが完了しました。

SQL> select * from salgrade;

     GRADE      LOSAL      HISAL
---------- ---------- ----------
         1        700       1200
         2       1201       1400
         4       2001       3000
         5       3001       9999

SQL> 
}}

SDB1 で確認してみます。

#pre{{
SQL> conn scott/tiger@sdb1
接続されました。
SQL> select * from salgrade;

     GRADE      LOSAL      HISAL
---------- ---------- ----------
         1        700       1200
         2       1201       1400
         4       2001       3000
         5       3001       9999

SQL> 
}}

ちゃんと反映されています。

* 管理 [#u12abeb6]

マスター・サイトの追加や削除など、
管理については別ページにしました。

- [[技術文書/Oracle/マルチマスタレプリケーションの管理]]

----
#comment

トップ   差分 履歴 リロード   一覧 検索 最終更新   ヘルプ   最終更新のRSS