#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