Oracle 11.2.0.1 Replication Using GoldenGate

Andy Kerber (@dbakerber), Senior Consultant

This is the fourth post in our four part series on Oracle GoldenGate replication. In this entry, we will add a third master instance into the replication. The third master instance will be Oracle 11.2.0.1, Oracle sid ggdem11.

In our configuration, ggdemo and ggdem11 will have bi-directional replication between both themselves and pgorcl. There will be no direct communication between ggdem11 and ggdemo, so changes will be replicated from ggdem11 to pgorcl, to ggdem, and vice versa.

Please read this blog post very closely as we move from one environment to the other frequently, and have colored coded the sections accordingly.

Note: In the Oracle multi-master setup, I include only basic conflict resolution steps. Conflict detection and resolution is an entire area of discussion of its own, and we will not discuss it in depth here.

In addition, I will not go into great detail about Oracle GoldenGate installation, as you can run the installer and follow the steps.  You will also need to run the GoldenGate shell software (ggsci) from the installation directory.  The Oracle database LD_LIBRARY_PATH will need to be in your path statement in order to run Oracle GoldenGate.

In this discussion, the variable $GGH points to the GoldenGate Home directory on each database server.

Oracle Environment:

Oracle Enterprise Edition x86_64 on Linux.  12.1.0.2, Sid ggdemo on server ggvm (initial target server)

Oracle Enterprise Edition x86_64 on Linux, 12.1.0.2 Sid ggtest on server pgorcl (initial source server)

Oracle Enterprise Edition x86_64 on Linux, 11.2.0.1, Sid ggdem11 on server nggvm.

Replicated source schema: andy

Replicated destination schema: andy

Oracle GoldenGate Version: 12c

Oracle GoldenGate schema: GGADMIN

Normally the ggsci prompt contains the server name and database sid, and a line number in addition to ggsci, and would look something like this:

GGSCI (pgorcl.localdomain as ggadmin@ggtest) 19>

However, if you are not logged into the database, it will just have the server name and line number:

GGSCI (pgorcl.localdomain) 2>

For the purposes of this document, we are just using GGSCI @ server>

Any time the command ‘edit params <name>’ is entered, GGSCI> will open a text editor.  Add the configuration lines that follow the command, and then save and exit the file.

Database Setup

The first step is to make the database changes necessary for replication with the three master instances.

We make the assumption that the reader knows how to create an Oracle 11.2.0.1 database, enable archive logging, and create the schema. Below are the next steps. Note that we do not set the ‘enable_goldengate_replication’ init parameter because it is not available in 11.2.0.1. Run the below steps in the ggdem11 instance only, as they have already been run in the other instances:

SQLPLUS>alter database add supplemental log data 
SQLPLUS>create tablespace ggs_data datafile '/u01/app/oracle/oradata/ggdemo/ggs_data01.dbf' size 1024m autoextend on; 
SQLPLUS>create user ggadmin identified by ggadmin default tablespace ggs_data temporary tablespace temp; 
SQLPLUS>grant connect,resource,create session, alter session to ggadmin; 
SQLPLUS>grant select any dictionary, select any table,create table to ggadmin; 
SQLPLUS>grant alter any table to ggadmin;  
SQLPLUS>grant execute on utl_file to ggadmin; 
SQLPLUS>grant flashback any table to ggadmin; 
SQLPLUS>grant execute on dbms_flashback to ggadmin; 
SQLPLUS>grant insert,update,delete on target.tcustmer to ggadmin; 
SQLPLUS>grant insert,update,delete on target.tcustord to ggadmin; 
SQLPLUS>@marker_setup.sql 
SQLPLUS>@ddl_setup.sql 
SQLPLUS>@role_setup.sql 
SQLPLUS>@ddl_enable.sql 
SQLPLUS>@sequence.sql 
SQLPLUS>grant connect, resource, create session to andy;

 

Next, in all instances, we create a new user, ggoper. While we do not use ggoper in this blog, should you need to do maintenance in an Oracle instance without that change being replicated, you will do so with the ggoper user. Keep in mind that with three master instances, you cannot use the same user (ggadmin) for both replication and maintenance.

SQLPLUS> create user ggoper identified by ggoper;

SQLPLUS> grant dba, select any dictionary, unlimited tablespace, create session to ggoper;

Note that in Oracle 11.2.0.1, integrated extract and replicat are not available. So we cannot use them for either the source extract or target replicat data on the 11.2.0.1 instance. However we can, and do, use integrated extract for the extract from Oracle 12.1.0.2 (ggtest).

For each extract process you have created on the oracle instances, edit the parameter file and change the line that reads:

TRANLOGOPTIONS excludeuser ggadmin

 

to read:

TRANLOGOPTIONS excludeuser ggoper

 

The reason for this modification is to allow the changes to cascade to the additional instance. In order to properly manage conflicts, a user who can make changes that are not replicated to other environments is required. With bi-directional replication, the ggadmin user can be used for both maintenance and replication. But with three or more master instances, changes will need to cascade from the first instance to the second, then to the third, so activities by ggadmin need to be replicated. Thus we created the ggoper user to make changes that are not replicated to other environments.

Replication Setup

Set up 1-Way Replication and Verify

1 – Configure Extract on the New Instance (ggdem11)

The first step, after installing GoldenGate in each environment, is to start ggsci and create the subdirectories.

./ggsci
GGSCI >create subdirs

Configure the port settings by editing the params file for the manager, and adding the line to set the port number in ggsci.  Do this on all servers.

GGSCI@nggvm > edit params mgr
port 7809
GGSCI@nggvm> start mgr

 

Next, set up your globals file.

GGSCI@nggvm> Edit params ./GLOBALS
CHECKPOINTTABLE ggcheckpoint

 

After editing the global parameters, make sure that the lines are in a file called GLOBALS in the $GGH directory.  I have run into issues where it was created as globals.prm in the params directory. But, the settings need to be in the GLOBALS file in the $GGH directory.

Note that while the last line is not strictly necessary, it makes debugging much easier.

Log into the database through GGSCI and create the checkpoint table.

GGSCI@nggvm > dblogin userid ggadmin 
 Password: 
 Successfully logged into database. 
 GGSCI@nggvm > add checkpointtable ggadmin.ggcheckpoint

 

Note: Normally at this point we would add the trandata to the source schema. However, it was added to the instance on pgorcl in part one of this blog, so we do not need to complete this step. The command would be add trandata andy.* after logging into the database through ggsci.

Find the current scn from sqlplus in ggdemo pgorcl server:

SQLPLUS> column current_scn format 99999999999

SQLPLUS> select current_scn from v$database;

 

Use datapump to export the data and import it into the destination (target) database:

SQLPLUS> create directory dumpdir as '/home/oracle/dump' ;

oracle@pgorcl$ expdp system/password directory=dumpdir full=y schemas=scott parallel=4 dumpfile=ora112_%u.dmp flashback_scn=&SCN_FROM_ABOVE

scp ora112*.dmp ggvm:/home/oracle/dump

 

(on nggvm)

sqlplus / as sysdba

SQLPLUS> create directory dumpdir as '/home/oracle/dump' ;

impdp@nggvm impdp system/password directory=dumpdir dumpfile=ora112_%u.dmp  parallel=4

In the new environment only, add the transaction data. This has already been added to the other environments:

GGSCI@nggvm > add trandata andy.* cols *

 

In ggsci, on the source server, configure the combined extract process:

GGSCI@pgorcl > dblogin userid ggadmin 
Password: 
Successfully logged into database.

GGSCI@pgorcl > add extract andy1, integrated tranlog, begin now

Edit params andy1
extract andy1
USERID ggadmin, PASSWORD ggadmin
TRANLOGOPTIONS IntegratedParams (max_sga_size 256), excludeuser ggoper
EXTTRAIL ./dirdat/an
LOGALLSUPCOLS
UPDATERECORDFORMAT COMPACT
DDL INCLUDE MAPPED OBJNAME ANDY.*
TABLE ANDY.*;
GGSCI@pgorcl> add exttrail ./dirdat/an, extract andy1, megabytes 10

GGSCI@pgorcl> dblogin userid ggadmin, password ggadmin
Successfully logged into database.

GGSCI@pgorcl> register extract andy1 database

GGSCI@pgorcl> add extract andypump, exttrailsource ./dirdat/an begin now

GGSCI@pgorcl> add rmttrail ./dirdat/ra extract andypump

 

Next, create the pump process:

GGSCI@pgorcl > edit params andypump

extract andypump
userid ggadmin, password ggadmin
rmthost nggvm, mgrport 7809
rmttrail ./dirdat/an
table andy.*;

 

Start the processes and tail the ggserr.log file on the source server in the GoldenGate home directory ($GGH). Watch for any errors, and resolve as required. If no errors occur, the extract process should be configured properly.

GGSCI@pgorcl > start extract andypump

GGSCI@pgorcl > start extract andy1

 

2 – Configure Replicat on the Destination DB

Connect to the destination database server and start ggsci:

./ggsci

GGSCI@nggvm> add replicat andy1 exttrail ./dirdat/an

GGSCI@nggvm> edit params andy1   # note the extended conflict resolution.

replicat andy1
 assumetargetdefs
 userid ggadmin, password ggadmin
 handlecollisions
 discardfile ./dirrpt/andy.dsc, purge
 map andy.*, target andy.*
 RESOLVECONFLICT (UPDATEROWEXISTS, (DEFAULT, USEMAX (last_updt_dt_tm))),
 RESOLVECONFLICT (DELETEROWEXISTS, (DEFAULT, IGNORE)),
 RESOLVECONFLICT (UPDATEROWMISSING, (DEFAULT, OVERWRITE)),
 RESOLVECONFLICT (DELETEROWMISSING, (DEFAULT, DISCARD)),
 MAPEXCEPTION
 (TARGET ggadmin.EXCEPTIONS, EXCEPTIONSONLY, INSERTALLRECORDS, COLMAP
 (
 excp_date = @DATENOW(),
 rep_name = @GETENV ('GGENVIRONMENT', 'GROUPNAME'),
 table_name = @GETENV ('GGHEADER', 'TABLENAME'),
 errno = @GETENV ('LASTERR', 'DBERRNUM'),
 errtype = @GETENV ('LASTERR', 'ERRTYPE'),
 optype = @GETENV ('LASTERR', 'OPTYPE'),
 transind = @GETENV ('GGHEADER', 'TRANSACTIONINDICATOR'),
 transimgind = @GETENV ('GGHEADER', 'BEFOREAFTERINDICATOR'),
 committimestamp = @GETENV ('GGHEADER', 'COMMITTIMESTAMP'),
 reccsn = @GETENV ('TRANSACTION', 'CSN'),
 recseqno = @GETENV ('RECORD', 'FILESEQNO'),
 recrba = @GETENV ('RECORD', 'FILERBA'),
 rectranspos = @GETENV ('RECORD', 'RSN'),
 reclength = @GETENV ('GGHEADAER', 'RECORDLENGTH'),
 logrba = @GETENV ('GGHEADER', 'LOGRBA'),
 logposition = @GETENV ('GGHEADER', 'LOGPOSITION'),
 grouptype = @GETENV ('GGENVIRONMENT', 'GROUPTYPE'),
 filename = @GETENV ('GGFILEHEADER', 'FILENAME'),
 fileno = @GETENV ('GGFILEHEADER', 'FILESEQNO'),
 srcrowid = @GETENV ('TRANSACTION', 'CSN'),
 srcdbcharset = @GETENV ('GGFILEHEADER', 'DBCHARSET'),
 replag = @GETENV ('LAG', 'SEC'),
 cnt_cdr_conflicts = @GETENV ('DELTASTATS','TABLE', @GETENV ('GGHEADER', 'TABLENAME'),'CDR_CONFLICTS'), cnt_cdr_resolutions = @GETENV ('DELTASTATS','TABLE', @GETENV ('GGHEADER', 'TABLENAME'),'CDR_RESOLUTIONS_SUCCEEDED'),
 cnt_cdr_failed = @GETENV ('DELTASTATS','TABLE', @GETENV ('GGHEADER', 'TABLENAME'),'CDR_RESOLUTIONS_FAILED')
 )
 );

GGSCI@nggvm> dblogin userid ggadmin
 password:

GGSCI@nggvm> add trandata andy.*

GGSCI@nggvm> start replicat andy1

 

At this point, replication should be working to nggvm. Log into the ggdem11 instance and make a change at pgorcl (ggtest) then verify that the change is transmitted to ggdem11.

 

SQLPLUJS@GGTEST> select count(1) from andy.emp;

  COUNT(1) 
 ---------- 
         13

SQLPLUS@GGDEM11> select count(1) from andy.emp;

  COUNT(1) 
 ---------- 
         13 
  

SQLPLUS@GGTEST>

delete from andy.emp where empno=7900;

1 row deleted.

SQLPLUJS@GGTEST> commit; 
 Commit complete.
SQLPLUS@GGDE11> select count(1) from andy.emp;

  COUNT(1) 
 ---------- 
         12

 

One way replication is now working.

3 – Make the required changes for multi-master replication

Note that GoldenGate will automatically suppress triggers for replicated objects.

On the ggdem11 instance, create the exception table:

SQLPLUS@ggdem11>    CREATE TABLE "GGADMIN"."EXCEPTIONS" 
    (    "EXCP_DATE" TIMESTAMP (6) DEFAULT systimestamp, 
     "REP_NAME" VARCHAR2(10), 
     "TABLE_NAME" VARCHAR2(56), 
     "ERRNO" NUMBER, 
     "ERRTYPE" VARCHAR2(6), 
     "OPTYPE" VARCHAR2(24), 
     "TRANSIND" VARCHAR2(12), 
     "TRANSIMGIND" VARCHAR2(8), 
     "COMMITTIMESTAMP" VARCHAR2(26), 
     "RECCSN" NUMBER, 
     "RECSEQNO" NUMBER, 
     "RECRBA" NUMBER, 
     "RECTRANSPOS" NUMBER, 
     "RECLENGTH" NUMBER, 
     "LOGRBA" NUMBER, 
     "LOGPOSITION" NUMBER, 
     "GROUPTYPE" VARCHAR2(12), 
     "FILENAME" VARCHAR2(50), 
     "FILENO" NUMBER, 
     "SRCROWID" VARCHAR2(40), 
     "SRCDBCHARSET" VARCHAR2(40), 
     "REPLAG" NUMBER, 
     "CNT_CDR_CONFLICTS" NUMBER, 
     "CNT_CDR_RESOLUTIONS" NUMBER, 
     "CNT_CDR_FAILED" NUMBER
    ) SEGMENT CREATION IMMEDIATE 
   PCTFREE 10 PCTUSED 40 INITRANS 1 MAXTRANS 255 
  NOCOMPRESS LOGGING
   STORAGE(INITIAL 65536 NEXT 1048576 MINEXTENTS 1 MAXEXTENTS 2147483645
   PCTINCREASE 0 FREELISTS 1 FREELIST GROUPS 1
   BUFFER_POOL DEFAULT FLASH_CACHE DEFAULT CELL_FLASH_CACHE DEFAULT)
   TABLESPACE "GGS_DATA" ;

 

In ggsci on nggvm, create the extract process:

GGSCI#nggvm> add extract andy2 tranlog begin now

EXTRACT added.

GGSCI@nggvm> add exttrail ./dirdat/ea extract andy2

EXTTRAIL added.

GGSCI@nggvm> edit params andy2

extract andy2
USERID ggadmin, PASSWORD ggadmin
TRANLOGOPTIONS excludeuser ggoper
EXTTRAIL ./dirdat/ea
LOGALLSUPCOLS
DDL INCLUDE MAPPED OBJNAME ANDY.*
TABLE ANDY.*;

GGSCI#nggvm> add extract andypump exttrailsource ./dirdat/ea

GGSCI@nggvm> add rmttrail ./dirdat/ra extract andypump, megabytes 10

GGSCI@nggvm> edit params andypump

EXTRACT andypump
USERID ggadmin, PASSWORD ggadmin
RMTHOST pgorcl, MGRPORT 7809
RMTTRAIL ./dirdat/ra
PASSTHRU
TABLE andy.*;

GGSCI@nggvm> start extract andypump

GGSCI@nggvm> start extract andy2

 

On the source server, add the replicat:

GGSCI@pgorcl> add replicat andy2 exttrail ./dirdat/at

GGSCI@pgorcl> edit params andy2

replicat andy2
userid ggadmin, password ggadmin
assumetargetdefs
handlecollisions
discardfile ./dirrpt/andy.dsc, purge
map andy.*, target andy.*
RESOLVECONFLICT (UPDATEROWEXISTS, (DEFAULT, USEMAX (last_updt_dt_tm))),
RESOLVECONFLICT (DELETEROWEXISTS, (DEFAULT, IGNORE)),
RESOLVECONFLICT (UPDATEROWMISSING, (DEFAULT, OVERWRITE)),
RESOLVECONFLICT (DELETEROWMISSING, (DEFAULT, DISCARD)),
MAPEXCEPTION
(TARGET ggadmin.EXCEPTIONS, EXCEPTIONSONLY, INSERTALLRECORDS, COLMAP
(
excp_date = @DATENOW(),
rep_name = @GETENV ('GGENVIRONMENT', 'GROUPNAME'),
table_name = @GETENV ('GGHEADER', 'TABLENAME'),
errno = @GETENV ('LASTERR', 'DBERRNUM'),
errtype = @GETENV ('LASTERR', 'ERRTYPE'),
optype = @GETENV ('LASTERR', 'OPTYPE'),
transind = @GETENV ('GGHEADER', 'TRANSACTIONINDICATOR'),
transimgind = @GETENV ('GGHEADER', 'BEFOREAFTERINDICATOR'),
committimestamp = @GETENV ('GGHEADER', 'COMMITTIMESTAMP'),
reccsn = @GETENV ('TRANSACTION', 'CSN'),
recseqno = @GETENV ('RECORD', 'FILESEQNO'),
recrba = @GETENV ('RECORD', 'FILERBA'),
rectranspos = @GETENV ('RECORD', 'RSN'),
reclength = @GETENV ('GGHEADAER', 'RECORDLENGTH'),
logrba = @GETENV ('GGHEADER', 'LOGRBA'),
logposition = @GETENV ('GGHEADER', 'LOGPOSITION'),
grouptype = @GETENV ('GGENVIRONMENT', 'GROUPTYPE'),
filename = @GETENV ('GGFILEHEADER', 'FILENAME'),
fileno = @GETENV ('GGFILEHEADER', 'FILESEQNO'),
srcrowid = @GETENV ('TRANSACTION', 'CSN'),
srcdbcharset = @GETENV ('GGFILEHEADER', 'DBCHARSET'),
replag = @GETENV ('LAG', 'SEC'),
cnt_cdr_conflicts = @GETENV ('DELTASTATS','TABLE', @GETENV ('GGHEADER', 'TABLENAME'),'CDR_CONFLICTS'), cnt_cdr_resolutions = @GETENV ('DELTASTATS','TABLE', @GETENV ('GGHEADER', 'TABLENAME'),'CDR_RESOLUTIONS_SUCCEEDED'),
cnt_cdr_failed = @GETENV ('DELTASTATS','TABLE', @GETENV ('GGHEADER', 'TABLENAME'),'CDR_RESOLUTIONS_FAILED')
)
);

GGSCI@pgorcl> Start replicat andy2

 

Now run an update on each of the three instances, as described above, and verify that all changes cascade to all the database instances.

If you have been following along from the start, here is what we have running on the various database servers:

Server pgorcl: Oracle 12.1.0.2, Golden Gate Version 12c, oracle sid ggtest

Running in ggsci:
GGSCI (pgorcl.localdomain) 37> info all

Program     Status     Group       Lag at Chkpt Time Since Chkpt

MANAGER     RUNNING
EXTRACT     RUNNING     ANDY1       00:00:11     00:00:08 # Extract to ggdem11 (nggvm)
EXTRACT     RUNNING     ANDYPUMP   00:00:00     00:00:00 # Pump process to ggdem11 (nggvm)
EXTRACT     RUNNING     EXTORAPG   00:00:00     00:00:03 # Extract for postgres (pgsql)
EXTRACT     RUNNING     INTEXTAN   00:00:12     00:00:07 # Integrated extract for ggdemo (ggvm)
EXTRACT     RUNNING     MYSQLORA   00:00:00     00:00:02 # Extract for mysql (mysql1)
EXTRACT     RUNNING     PUMPINT     00:00:00     00:00:05 # Integrated pump extract for ggdemo (ggvm)
REPLICAT   RUNNING     ANDY2       00:00:00     00:07:33 # Replicat from ggdem11 (nggvm)
REPLICAT   RUNNING     RPINTAN2   00:00:12     00:30:21 # Integrated Replicat from ggdemo (ggvm)

 

Server ggvm: Oracle 12.1.0.2, Golden Gate version 12c

Program     Status     Group       Lag at Chkpt Time Since Chkpt

MANAGER     RUNNING
EXTRACT     RUNNING     INEXTAN2   00:00:04     00:00:02 #integrated extract for ggtest (pgorcl)
EXTRACT     RUNNING     PUMPINT2   00:00:00     00:35:30 #Integrated pump process for ggtest (pgorcl)
REPLICAT   RUNNING     REPINTAN    02:17:47     00:00:08 #Replication from ggtest (pgorcl)

 

Server nggvm: Oracle 11.2.0.1, Golden Gate version 12c

GGSCI (nggvm) 4> info all

Program     Status     Group       Lag at Chkpt Time Since Chkpt

MANAGER     RUNNING
EXTRACT     RUNNING     ANDY2       00:00:16     00:00:15 # Extract to ggtest (pgorcl)
EXTRACT     RUNNING     ANDYPUMP   00:22:40     00:16:27 # pump process to ggtest (pgorcl)
REPLICAT   RUNNING     ANDY1       01:44:22     00:00:15 # Replication from ggtest (pgorcl)

 

Server pgsql, postgres Version 9.6, Golden Gate version 12c
GGSCI (pgsql.localdomain) 1> info all

Program     Status     Group       Lag at Chkpt Time Since Chkpt

MANAGER     RUNNING
REPLICAT   RUNNING     REPORAPG   00:00:00     00:00:02 # replicat process from ggtest (pgorcl)

 

Server mysql, MySql Version 5.7, Golden Gate version 12c

GGSCI (mysql1.localdomain) 1> info all

Program     Status     Group       Lag at Chkpt Time Since Chkpt

MANAGER     RUNNING
REPLICAT   RUNNING     ORAMYSQL   00:00:00     00:00:02 # Replicat from ggtest (pgorcl)

 

In this series of four blogs, we have covered the steps for setting up Oracle single master and multi-master replication, including multi-master replication among three master instances. We also discussed and configured one-way replication from Oracle to MySQL, and Oracle to PostgreSQL.

Please note: this blog contains code examples provided for your reference. All sample code is provided for illustrative purposes only. Use of information appearing in this blog is solely at your own risk. Please read our full disclaimer for details.

Table of Contents

Related Posts