AWS DMS for Data Engineers
Full load and CDC, preparing sources, table mappings, landing CDC as Parquet in S3 and merging it into lake tables, tuning, validation and monitoring.
1. What AWS DMS Is
AWS Database Migration Service copies data from a source database to a target, either once (full load), continuously (CDC, change data capture from the transaction log), or both. Data engineers use it to land operational databases in S3 or Redshift and keep them in sync, and to migrate databases to AWS.
| Component | Role |
|---|---|
| Replication instance / DMS Serverless | Compute that runs replication tasks (Serverless scales capacity automatically) |
| Source endpoint | Oracle, SQL Server, MySQL, PostgreSQL, MariaDB, Db2, MongoDB, SAP ASE, S3 and more |
| Target endpoint | RDS/Aurora, Redshift, S3, DynamoDB, Kinesis, MSK/Kafka, OpenSearch, DocumentDB and more |
| Replication task | What to copy (table mappings), how (full load, CDC, or both) and task settings |
| DMS Schema Conversion / SCT | Converts schemas and code between engines (e.g. Oracle → PostgreSQL) |
2. Preparing the Source for CDC
| Source | Requirement |
|---|---|
| MySQL / MariaDB / Aurora MySQL | Binary logging on with binlog_format = ROW and binlog_row_image = FULL; keep binlogs long enough (CALL mysql.rds_set_configuration('binlog retention hours', 24) on RDS) |
| PostgreSQL / Aurora PostgreSQL | Logical replication (rds.logical_replication = 1), a user with replication rights; tables need primary keys for updates and deletes |
| Oracle | ARCHIVELOG mode, supplemental logging (database and table level); LogMiner or Binary Reader |
| SQL Server | MS-CDC or MS-Replication enabled for the tables; full recovery model |
Without the right logging settings, a CDC task starts but captures nothing or misses columns: check this first when CDC "silently" fails.
3. Table Mappings
{
"rules": [
{
"rule-type": "selection", "rule-id": "1", "rule-name": "include-sales",
"object-locator": { "schema-name": "SALES", "table-name": "%" },
"rule-action": "include"
},
{
"rule-type": "selection", "rule-id": "2", "rule-name": "exclude-temp",
"object-locator": { "schema-name": "SALES", "table-name": "TMP_%" },
"rule-action": "exclude"
},
{
"rule-type": "transformation", "rule-id": "3", "rule-name": "lowercase-tables",
"rule-target": "table",
"object-locator": { "schema-name": "SALES", "table-name": "%" },
"rule-action": "convert-lowercase"
},
{
"rule-type": "transformation", "rule-id": "4", "rule-name": "drop-pii",
"rule-target": "column",
"object-locator": { "schema-name": "SALES", "table-name": "CUSTOMERS", "column-name": "PAN_NUMBER" },
"rule-action": "remove-column"
}
]
}
4. Landing CDC in S3
aws dms create-endpoint --endpoint-identifier s3-raw-target --endpoint-type target --engine-name s3 \
--s3-settings '{
"BucketName": "acme-lake-prod",
"BucketFolder": "raw/dms",
"ServiceAccessRoleArn": "arn:aws:iam::111122223333:role/dms-s3-access",
"DataFormat": "parquet",
"ParquetVersion": "parquet-2-0",
"TimestampColumnName": "dms_commit_ts",
"IncludeOpForFullLoad": true,
"DatePartitionEnabled": true,
"DatePartitionSequence": "YYYYMMDD",
"EncryptionMode": "SSE_KMS",
"ServerSideEncryptionKmsKeyId": "arn:aws:kms:ap-south-1:111122223333:key/1111-2222"
}'
aws dms create-replication-task --replication-task-identifier orders-to-s3 \
--source-endpoint-arn <source-arn> --target-endpoint-arn <target-arn> \
--replication-instance-arn <instance-arn> \
--migration-type full-load-and-cdc \
--table-mappings file://table-mappings.json
Each output row carries an Op column (I insert, U update, D delete) and the commit timestamp. Downstream, keep the latest change per key and MERGE it into an Iceberg, Delta or Hudi table:
from pyspark.sql import functions as F, Window
changes = spark.read.parquet("s3://acme-lake-prod/raw/dms/SALES/ORDERS/")
latest = (changes
.withColumn("rn", F.row_number().over(
Window.partitionBy("order_id").orderBy(F.col("dms_commit_ts").desc())))
.filter("rn = 1").drop("rn"))
latest.createOrReplaceTempView("order_changes")
spark.sql("""
MERGE INTO glue_catalog.silver.orders t
USING order_changes s ON t.order_id = s.order_id
WHEN MATCHED AND s.Op = 'D' THEN DELETE
WHEN MATCHED THEN UPDATE SET *
WHEN NOT MATCHED AND s.Op <> 'D' THEN INSERT *
""")
Full-load files have no Op value unless IncludeOpForFullLoad is true; enable it so one MERGE handles both phases.
5. Tuning, Validation & Monitoring
| Topic | Guidance |
|---|---|
| Large tables | Parallel full load by ranges or partitions (table-settings rules); more full-load subtasks |
| LOBs | Limited LOB mode with a size cap is much faster than full LOB mode; choose based on real column sizes |
| Validation | Enable DMS data validation to compare source and target rows; still reconcile counts and sums yourself |
| Latency | Monitor CDCLatencySource and CDCLatencyTarget; high source latency points at the source or network, high target latency at the target |
| Restarts | Tasks resume CDC from a checkpoint; a task can also start CDC from a specific log position or time |
| Sizing | Memory matters for many tables and transactions; DMS Serverless removes instance sizing |
6. Common Interview Questions
| Question | Short answer |
|---|---|
| How does DMS capture changes? | It reads the source transaction log (binlog, WAL logical decoding, redo logs, MS-CDC) and applies or writes inserts, updates and deletes in commit order |
| Full load vs CDC vs full load + CDC? | One-time copy; ongoing changes only from a point; or a copy followed seamlessly by ongoing changes |
| How do you build a lake table from DMS output? | Land Parquet with Op and commit timestamp columns, keep the latest change per key, and MERGE into Iceberg/Delta/Hudi |
| Why might CDC capture nothing? | Source logging not configured (binlog format, logical replication, supplemental logging) or insufficient log retention or permissions |
| How do you migrate a large Oracle database with minimal downtime? | Convert schema (SCT/DMS Schema Conversion), full load + CDC, validate, keep CDC running, then a short cutover |