20GB高写入生产DynamoDB零停机迁移至PostgreSQL方案咨询
Hey there! Let's break down how to pull off this zero-downtime migration from DynamoDB to PostgreSQL, especially given your production scale (20GB of data, 100-300 writes/sec). I totally get why you might be skeptical about the EMR + Spark Streaming approach—let's unpack its pros, cons, and also cover simpler, more reliable alternatives that fit your use case better.
1. First, Let's Talk About That EMR + Spark Streaming Approach
First off, it is technically feasible—Spark can handle both bulk full-table scans for your existing 20GB dataset and stream DynamoDB Streams to capture real-time writes. That covers the two core requirements for zero downtime: initial sync + ongoing incremental changes.
But here's why it might not be the best fit for you:
- Operational overhead: EMR clusters require tuning (instance types, scaling rules) and monitoring. If you're not already comfortable with Spark and EMR, this adds unnecessary complexity to a high-stakes production migration.
- Latency risks: Spark's micro-batch processing can introduce lag (depending on batch size) between when a write hits DynamoDB and when it lands in PostgreSQL. If your app needs near-instant consistency, this could be a problem.
- Cost: Running an EMR cluster for the full migration (plus a buffer period) can get pricey, especially since you only need it temporarily.
2. Better Alternatives for Your Scale
Option A: DynamoDB Streams + AWS Lambda (Lightweight, Low-Code)
This is my go-to for migrations of your size—it's simpler to set up and maintain than EMR/Spark. Here's the step-by-step:
- Step 1: Bulk sync existing data first
- Write a simple script (Python with
boto3works great) to run a parallelizedscanon your DynamoDB table. Pagination is key here—track theLastEvaluatedKeyso you can resume if the script fails. - Batch the scan results and use PostgreSQL's
COPYcommand for bulk inserts—this is way faster than individualINSERTstatements and minimizes load on both systems. Run this in off-peak hours if possible, though even at your QPS, a well-optimized scan won't cause significant contention.
- Write a simple script (Python with
- Step 2: Set up incremental sync with Streams + Lambda
- Enable DynamoDB Streams on your table (pick
NEW_AND_OLD_IMAGESto capture full item state). - Create a Lambda function that triggers on stream records. Map the DynamoDB item structure to your PostgreSQL schema, then run
INSERT,UPDATE, orDELETEas needed. - Add idempotency: Store processed stream
sequenceNumbervalues in a small PostgreSQL table (or even a tiny DynamoDB table) to avoid reprocessing records if Lambda retries.
- Enable DynamoDB Streams on your table (pick
- Step 3: Cut over to PostgreSQL
- Once the bulk sync is done and Lambda is caught up (check that the stream iterator is near the latest record), switch your app to write directly to PostgreSQL. Keep Lambda running for 24-48 hours as a safety buffer, then disable it.
Option B: AWS Database Migration Service (DMS) – Fully Managed, Hands-Off
If you want to avoid writing any custom code, DMS is the way to go. It's purpose-built for zero-downtime migrations and supports DynamoDB → PostgreSQL natively:
- DMS handles both the initial full load (via DynamoDB scans) and ongoing replication (via DynamoDB Streams) automatically.
- You just need to set up a replication instance, configure source (DynamoDB) and target (PostgreSQL) endpoints, and define schema mapping rules (critical for translating DynamoDB's flexible schema to PostgreSQL's relational model).
- It's fully managed, so DMS takes care of error retries, monitoring, and scaling. For your 20GB dataset and QPS, a medium-sized replication instance will handle it easily.
- Pro tip: Test the schema mapping in staging first—DynamoDB's nested attributes might need to be flattened or stored as JSON in PostgreSQL, depending on your app's needs.
3. Critical Best Practices to Avoid Headaches
No matter which method you choose, these steps are non-negotiable for a smooth migration:
- Test everything in staging first: Migrate a copy of your production data to a staging PostgreSQL instance. Validate data consistency (use checksums or row counts), test your app against the new database, and work out any kinks before touching production.
- Prioritize idempotency: Every part of your incremental sync must be able to handle duplicate records without causing issues. Use unique identifiers (like DynamoDB's
sequenceNumberor item keys) to track what's been processed. - Monitor like a hawk: Set up alerts for DynamoDB write latency, replication lag, and PostgreSQL CPU/memory usage. If you see lag spiking, pause app traffic temporarily (or adjust your sync batch size) to catch up.
- Have a rollback plan: Keep your app configured to switch back to DynamoDB quickly if something goes wrong. Don't make any irreversible changes until you're 100% confident the migration is successful.
内容的提问来源于stack exchange,提问作者Anand Prem

