
Introduction
This blog post describes the steps to migrate from Oracle RDS to Exadata Database Service using Oracle Zero Downtime Migration (ZDM) logical online method, which leverages Oracle Data Pump for data export and import and uses Amazon S3 Object Storage to store the Data Pump dump files. Additionally, it uses Oracle GoldenGate to keep the source and target databases in sync and achieve minimal downtime migration.
The same steps apply if migrating to another co-managed Oracle Database Cloud Service, like Base Database Service or Exadata Exascale Cloud Service.
The Environment
- Source Database: Oracle RDS.
- Target Database: Exadata Database Service.
- Intermediate Storage Location: Amazon S3 Object Storage bucket.
- Oracle ZDM: installed on an AWS EC2 VM instance with RHEL 8.
- Oracle GoldenGate: installed on Podman container on an AWS EC2 VM instance with RHEL 8.
Step 1: Download and Install Oracle ZDM
Download and install the Oracle ZDM software on an AWS EC2 VM instance following the steps in Setting Up Zero Downtime Migration Software or Part 1/5: Zero Downtime Migration (ZDM) – Introduction & Installation.
Step 2: Get your Access and Secret Keys for the S3 Bucket
You will need to provide ZDM access to the S3 to be able to upload the Data Pump export file to the object storage bucket.
Follow the AWS documentation or the example in Steps 1 and 2 in this blog post to get your Access Key ID and Secret Access Key. These should look like this:
Access key ID: AKIA2PCQOXHEFKTB6SU2
Secret access key: 7MymZxpyL3NDJeNpMrfuDE8FJ1fp70BNpsP2Le9b
Step 3: Enable your RDS Instance to Access the S3 Bucket
Review the conditions and follow the steps in the AWS documentation to allow your RDS instance to access the S3 bucket.
Step 4: Install Oracle GoldenGate on Podman
Follow the steps as described in the “Oracle GoldenGate on Podman” section in this document to download and install Oracle GoldenGate on Podman container on an EC2 VM instance.
Step 5: Configure the Source RDS Database for GoldenGate
For optimal Data Pump performance during online logical migrations, it is recommended to set the STREAMS_POOL_SIZE database parameter to a minimum of 2GB. See the documentation for the recommendation of 1GB STREAMS_POOL_SIZE per integrated extract + an additional 25 percent.
Set the following parameters in your RDS parameter group:
STREAMS_POOL_SIZE=2147483648 --(=2GB)
ENABLE_GOLDENGATE_REPLICATION=true
Execute the following commands:
EXEC rdsadmin.rdsadmin_util.alter_supplemental_logging(p_action => 'ADD');
EXEC rdsadmin.rdsadmin_util.force_logging(p_enable => true);
EXEC rdsadmin.rdsadmin_util.set_configuration('archivelog retention hours',24);
CREATE TABLESPACE administrator;
CREATE USER ggadmin IDENTIFIED BY "your_password" DEFAULT TABLESPACE ADMINISTRATOR TEMPORARY TABLESPACE TEMP;
ALTER USER ggadmin QUOTA UNLIMITED ON administrator;
GRANT CREATE SESSION, ALTER SESSION TO ggadmin;
GRANT RESOURCE TO ggadmin;
GRANT SELECT ANY DICTIONARY TO ggadmin;
GRANT FLASHBACK ANY TABLE TO ggadmin;
GRANT SELECT ANY TABLE TO ggadmin;
--Check the RDS_MASTER_ROLE:
SELECT * FROM sys.dba_role_privs WHERE granted_role = 'RDS_MASTER_ROLE';
GRANTEE GRANTED_ROLE ADM DEL DEF COM INH
-------------------- --------------- --- --- --- --- ---
SYS RDS_MASTER_ROLE YES NO YES NO NO
ADMIN RDS_MASTER_ROLE NO NO YES NO NO
--In this case, “SYS” and “ADMIN”. Use these two values in the following GRANT commands:
GRANT SELECT_CATALOG_ROLE TO SYS WITH ADMIN OPTION;
GRANT SELECT_CATALOG_ROLE TO ADMIN WITH ADMIN OPTION;
EXEC rdsadmin.rdsadmin_util.grant_sys_object ('DBA_CLUSTERS', 'GGADMIN');
GRANT EXECUTE ON DBMS_FLASHBACK TO ggadmin;
GRANT SELECT ON SYS.V_$DATABASE TO ggadmin;
GRANT ALTER ANY TABLE TO ggadmin;
EXEC rdsadmin.rdsadmin_dbms_goldengate_auth.grant_admin_privilege (grantee => 'ggadmin', privilege_type=> 'capture', grant_select_privileges => true, do_grants=> TRUE);
grant connect, resource to ggadmin;
grant unlimited tablespace to ggadmin;
grant create view to ggadmin;
grant create table to ggadmin;
See the RDS documentation for Setting up a source database for use with Oracle GoldenGate on Amazon RDS.
Step 6: Prepare the Target Exadata VM Cluster Nodes
Copy the SSH public key for zdmuser from the ZDM host (as created in Part 1, post task 1) to the .ssh/authorized_keys file on the target database host for the user you want to use for login, in this case, opc. Copy the SSH public key to all Exadata VM Cluster nodes:
#on ZDM host as zdmuser
[zdmuser@zdmhost ~]$ cat .ssh/id_rsa.pub
#on the target database host as user opc
[opc@exavm1 ~]$ vi .ssh/authorized_keys
#insert the public key and save the changes
[opc@exavm2 ~]$ vi .ssh/authorized_keys
#insert the public key and save the changes
Step 7: Configure the Target Exadata Database for GoldenGate
As SYS user:
-- in the CDB
alter system set streams_pool_size = 2G;
alter system set ENABLE_GOLDENGATE_REPLICATION=TRUE scope=both;
-- in the PDB
alter session set container=pdb01;
create user ggadmin identified by "your_password" default tablespace users temporary
grant connect, resource to ggadmin;
grant unlimited tablespace to ggadmin;
grant select any dictionary to ggadmin;
grant create view to ggadmin;
grant select any table to ggadmin;
grant insert any table to ggadmin;
grant update any table to ggadmin;
grant delete any table to ggadmin;
grant execute on dbms_lock to ggadmin;
-- 19c
exec dbms_goldengate_auth.grant_admin_privilege('ggadmin');
-- 23ai
grant OGG_APPLY to ggadmin;
Step 8: Prepare the DZM Service Host
Add the target database server’s hostnames and IP addresses to the /etc/hosts file. As root user:
[root@zdmhost ~]# vi /etc/hosts
#add the following entries
10.10.0.1 exavm1
10.10.0.2 exavm2
Verify that TTY is disabled for the SSH privileged user. If TTY is disabled, the following command returns the date from the remote host without any errors:
[zdmuser@zdmhost ~]$ ssh -i /home/zdmuser/.ssh/id_rsa opc@exavm1 "/usr/bin/sudo /bin/sh -c date"
Thu Oct 2 09:25:17 GMT 2025
[zdmuser@zdmhost ~]$ ssh -i /home/zdmuser/.ssh/id_rsa opc@exavm2 "/usr/bin/sudo /bin/sh -c date"
Thu Oct 2 09:25:29 GMT 2025
Step 9: Create the ZDM Response File
Create a new response file on the ZDM host. Here is an example with the minimum parameters required. As zdmuser:
[zdmuser@zdmhost ~]$ vi logical_online.rsp
# migration method
MIGRATION_METHOD=ONLINE_LOGICAL
DATA_TRANSFER_MEDIUM=AMAZONS3
# AWS RDS Oracle
SOURCEDATABASE_ENVIRONMENT_NAME=AMAZON
SOURCEDATABASE_ENVIRONMENT_DBTYPE=RDS_ORACLE
SOURCEDATABASE_ADMINUSERNAME=admin
SOURCEDATABASE_CONNECTIONDETAILS_HOST=orards2.cvi2oskioo1c.us-east-1.rds.amazonaws.com
SOURCEDATABASE_CONNECTIONDETAILS_SERVICENAME=ORCL
SOURCEDATABASE_CONNECTIONDETAILS_PORT=1521
SOURCEDATABASE_GGADMINUSERNAME=ggadmin
# data pump
DATAPUMPSETTINGS_EXPORTDIRECTORYOBJECT_NAME=DATA_PUMP_DIR
DATAPUMPSETTINGS_JOBMODE=SCHEMA
DATAPUMPSETTINGS_METADATAREMAPS-1=type:REMAP_TABLESPACE,oldValue:USERS,newValue:DATA
INCLUDEOBJECTS-1=owner:HR
DATAPUMPSETTINGS_IMPORTDIRECTORYOBJECT_NAME=DATA_PUMP_DIR
DATAPUMPSETTINGS_IMPORTDIRECTORYOBJECT_PATH=/u02/app/oracle/product/19.0.0.0/dbhome_1/rdbms/log/39035FC9A0DD562BE063240181AC869C
# target db
TARGETDATABASE_OCID=ocid1.database.oc1.iad.xxx
TARGETDATABASE_CONNECTIONDETAILS_SERVICENAME=pdb01.client.odb1.oraclevcn.com
TARGETDATABASE_CONNECTIONDETAILS_HOST=exavm1
TARGETDATABASE_CONNECTIONDETAILS_PORT=1521
TARGETDATABASE_ADMINUSERNAME=SYSTEM
TARGETDATABASE_GGADMINUSERNAME=ggadmin
# oci cli
OCIAUTHENTICATIONDETAILS_USERPRINCIPAL_USERID=ocid1.user.oc1..xxx
OCIAUTHENTICATIONDETAILS_USERPRINCIPAL_TENANTID=ocid1.tenancy.oc1..xxx
OCIAUTHENTICATIONDETAILS_USERPRINCIPAL_FINGERPRINT=43:05:e5:1f:63:8a:29:f3:02:67:ff:56:57:e3:bc:33
OCIAUTHENTICATIONDETAILS_USERPRINCIPAL_PRIVATEKEYFILE=/home/zdmuser/.oci/oci_api_key.pem
OCIAUTHENTICATIONDETAILS_REGIONID=us-ashburn-1
# s3 credentials
DUMPTRANSFERDETAILS_S3BUCKET_NAME=s3zdm
DUMPTRANSFERDETAILS_S3BUCKET_REGION=us-east-1
DUMPTRANSFERDETAILS_S3BUCKET_ACCESSKEY=AKIA2PCQOXHEFKTB6SU2
# GoldenGate
GOLDENGATEHUB_ADMINUSERNAME=oggadmin
GOLDENGATEHUB_SOURCEDEPLOYMENTNAME=Local
GOLDENGATEHUB_TARGETDEPLOYMENTNAME=Local
# Private IP of the VM where Podman is running
GOLDENGATEHUB_URL=https://172.31.45.112
GOLDENGATEHUB_ALLOWSELFSIGNEDCERTIFICATE=TRUE
Step 10: Evaluate the Migration
On the ZDM host, as zdmuser:
[zdmuser@zdmhost ~]$ $ZDMHOME/bin/zdmcli migrate database -rsp logical_online.rsp -eval
You will interactively be asked to enter the passwords for the RDS and Exadata Database admin users.
Check the job status. On the ZDM host, as zdmuser:
[zdmuser@zdmhost ~]$ $ZDMHOME/bin/zdmcli query job -jobid 1
Job ID: 1
Job Type: "EVAL"
Current status: SUCCEEDED
ZDM_VALIDATE_TGT ...................... COMPLETED
ZDM_VALIDATE_SRC ...................... COMPLETED
ZDM_SETUP_SRC ......................... COMPLETED
ZDM_PRE_MIGRATION_ADVISOR ............. COMPLETED
ZDM_VALIDATE_GG_HUB ................... COMPLETED
ZDM_VALIDATE_DATAPUMP_SETTINGS_SRC .... COMPLETED
ZDM_VALIDATE_DATAPUMP_SETTINGS_TGT .... COMPLETED
ZDM_PREPARE_DATAPUMP_SRC .............. COMPLETED
ZDM_DATAPUMP_ESTIMATE_SRC ............. COMPLETED
ZDM_CLEANUP_SRC ....................... COMPLETED
Step 11: Start the Migration
Execute the same command for evaluation, but this time without the -eval parameter. Add the -pauseafter ZDM_MONITOR_GG_LAG parameter to pause the migration right after the source and target databases are kept in sync. Later, when you are ready to switch over your application, you can resume the job by using the zdmcli resume job command.
On the ZDM host, as zdmuser:
[zdmuser@zdmhost ~]$ $ZDMHOME/bin/zdmcli migrate database -rsp logical_online.rsp -pauseafter ZDM_MONITOR_GG_LAG
Check the job status. On the ZDM host, as zdmuser:
[zdmuser@zdmhost ~]$ $ZDMHOME/bin/zdmcli query job -jobid 2
Job ID: 2
Job Type: "MIGRATE"
Current status: PAUSED
ZDM_VALIDATE_TGT ...................... COMPLETED
ZDM_VALIDATE_SRC ...................... COMPLETED
ZDM_SETUP_SRC ......................... COMPLETED
ZDM_PRE_MIGRATION_ADVISOR ............. COMPLETED
ZDM_VALIDATE_GG_HUB ................... COMPLETED
ZDM_VALIDATE_DATAPUMP_SETTINGS_SRC .... COMPLETED
ZDM_VALIDATE_DATAPUMP_SETTINGS_TGT .... COMPLETED
ZDM_PREPARE_DATAPUMP_SRC .............. COMPLETED
ZDM_DATAPUMP_ESTIMATE_SRC ............. COMPLETED
ZDM_PREPARE_GG_HUB .................... COMPLETED
ZDM_ADD_HEARTBEAT_SRC ................. COMPLETED
ZDM_ADD_SCHEMA_TRANDATA_SRC ........... COMPLETED
ZDM_CREATE_GG_EXTRACT_SRC ............. COMPLETED
ZDM_PREPARE_DATAPUMP_TGT .............. COMPLETED
ZDM_DATAPUMP_EXPORT_SRC ............... COMPLETED
ZDM_TRANSFER_DUMPS_SRC ................ COMPLETED
ZDM_DATAPUMP_IMPORT_TGT ............... COMPLETED
ZDM_POST_DATAPUMP_SRC ................. COMPLETED
ZDM_POST_DATAPUMP_TGT ................. COMPLETED
ZDM_ADD_HEARTBEAT_TGT ................. COMPLETED
ZDM_ADD_CHECKPOINT_TGT ................ COMPLETED
ZDM_CREATE_GG_REPLICAT_TGT ............ COMPLETED
ZDM_START_GG_REPLICAT_TGT ............. COMPLETED
ZDM_MONITOR_GG_LAG .................... COMPLETED
ZDM_PREPARE_SWITCHOVER_APP ............ PENDING
ZDM_ADVANCE_SEQUENCES ................. PENDING
ZDM_REFRESH_MVIEW_TGT ................. PENDING
ZDM_SWITCHOVER_APP .................... PENDING
ZDM_POST_SWITCHOVER_TGT ............... PENDING
ZDM_RM_GG_EXTRACT_SRC ................. PENDING
ZDM_RM_GG_REPLICAT_TGT ................ PENDING
ZDM_DELETE_SCHEMA_TRANDATA_SRC ........ PENDING
ZDM_RM_HEARTBEAT_SRC .................. PENDING
ZDM_RM_CHECKPOINT_TGT ................. PENDING
ZDM_RM_HEARTBEAT_TGT .................. PENDING
ZDM_CLEAN_GG_HUB ...................... PENDING
ZDM_POST_ACTIONS ...................... PENDING
ZDM_CLEANUP_SRC ....................... PENDING
Step 12: Complete the Migration
Resume the ZDM job to complete the migration:
[zdmuser@zdmhost ~]$ $ZDMHOME/bin/zdmcli resume job -jobid 2
Check the status:
[zdmuser@zdmhost ~]$ $ZDMHOME/bin/zdmcli query job -jobid 2
Job ID: 2
Job Type: "MIGRATE"
Current status: SUCCEEDED
ZDM_VALIDATE_TGT ...................... COMPLETED
ZDM_VALIDATE_SRC ...................... COMPLETED
ZDM_SETUP_SRC ......................... COMPLETED
ZDM_PRE_MIGRATION_ADVISOR ............. COMPLETED
ZDM_VALIDATE_GG_HUB ................... COMPLETED
ZDM_VALIDATE_DATAPUMP_SETTINGS_SRC .... COMPLETED
ZDM_VALIDATE_DATAPUMP_SETTINGS_TGT .... COMPLETED
ZDM_PREPARE_DATAPUMP_SRC .............. COMPLETED
ZDM_DATAPUMP_ESTIMATE_SRC ............. COMPLETED
ZDM_PREPARE_GG_HUB .................... COMPLETED
ZDM_ADD_HEARTBEAT_SRC ................. COMPLETED
ZDM_ADD_SCHEMA_TRANDATA_SRC ........... COMPLETED
ZDM_CREATE_GG_EXTRACT_SRC ............. COMPLETED
ZDM_PREPARE_DATAPUMP_TGT .............. COMPLETED
ZDM_DATAPUMP_EXPORT_SRC ............... COMPLETED
ZDM_TRANSFER_DUMPS_SRC ................ COMPLETED
ZDM_DATAPUMP_IMPORT_TGT ............... COMPLETED
ZDM_POST_DATAPUMP_SRC ................. COMPLETED
ZDM_POST_DATAPUMP_TGT ................. COMPLETED
ZDM_ADD_HEARTBEAT_TGT ................. COMPLETED
ZDM_ADD_CHECKPOINT_TGT ................ COMPLETED
ZDM_CREATE_GG_REPLICAT_TGT ............ COMPLETED
ZDM_START_GG_REPLICAT_TGT ............. COMPLETED
ZDM_MONITOR_GG_LAG .................... COMPLETED
ZDM_PREPARE_SWITCHOVER_APP ............ COMPLETED
ZDM_ADVANCE_SEQUENCES ................. COMPLETED
ZDM_REFRESH_MVIEW_TGT ................. COMPLETED
ZDM_SWITCHOVER_APP .................... COMPLETED
ZDM_POST_SWITCHOVER_TGT ............... COMPLETED
ZDM_RM_GG_EXTRACT_SRC ................. COMPLETED
ZDM_RM_GG_REPLICAT_TGT ................ COMPLETED
ZDM_DELETE_SCHEMA_TRANDATA_SRC ........ COMPLETED
ZDM_RM_HEARTBEAT_SRC .................. COMPLETED
ZDM_RM_CHECKPOINT_TGT ................. COMPLETED
ZDM_RM_HEARTBEAT_TGT .................. COMPLETED
ZDM_CLEAN_GG_HUB ...................... COMPLETED
ZDM_POST_ACTIONS ...................... COMPLETED
ZDM_CLEANUP_SRC ....................... COMPLETED
Troubleshooting
In case of any issues, check the following log files:
- ZDM Server Log: $ZDM_BASE/crsdata/<zdm_service_node>/rhp/rhpserver.log.0
- Target server logs:
<oracle_base>/zdm/zdm_<tgt_db_name>_<job_id>/zdm/log
Further Reading
- Oracle Zero Downtime Migration – product page
- ZDM Logical Offline Migration from Oracle RDS to Autonomous Database
- ZDM Logical Online Migration from Oracle RDS to Autonomous Database
- ZDM Logical Offline Migration from Oracle RDS to Exadata Database Service
- ZDM Logical Online Migration from Oracle RDS to Exadata Database Service (this blog post)
- Various blog posts related to ZDM migrations and Multicloud
