Data Migration and Consistency Questions
Plan and execute data migrations while preserving correctness and availability. Topics include zero downtime migration techniques, schema evolution patterns, backward and forward compatibility, dual writes and shadow writes, incremental and bulk migration strategies, data validation and reconciliation, canary migrations, rollbacks and fallback plans, and how to minimize user impact during transitions. Understand trade offs between consistency and speed of migration and techniques to detect and correct drift after migration.
MediumSystem Design
19 practiced
Design a migration strategy to move 50 million user records from a single monolithic relational database into a sharded cluster without taking the application offline. The system requires strong read-after-write guarantees for profile updates. Outline architecture components, cutover steps, data consistency strategies, and how you would coordinate the cutover with minimal risk.
Sample Answer
Requirements & constraints:- 50M user rows, zero downtime migration, strong read-after-write (RAW) for profile updates, move from monolith RDBMS to sharded cluster.High-level architecture:- Dual-write proxy (write splitter) between app and databases- Change Data Capture (CDC) pipeline (Debezium/Kafka Connect) to capture source DB changes- Transformation/validation workers to rewrite keys, apply hashing/modulo sharding rules- Sharded target DB cluster (consistent hashing or range shards) with a routing layer (middleware or client shard map)- Sidecar cache (per-user) for fast RAW reads (optional), and a verification/consistency serviceCutover plan (phased):1. Prep: design shard key, capacity plan, schema compatibility, set up target cluster and routing service, run dry runs with subset of data.2. Backfill: run CDC snapshot + bulk loader to populate target shards while source remains authoritative. Use throttling to avoid DB impact.3. Dual-read validation: enable reads from target for a small percentage via canary routing; compare results to source (checksum, row counts).4. Dual-write: introduce write-splitter so all writes go to both source and target (idempotent, versioned). Continue reading from source.5. Strong RAW guarantee: route read-after-write for recently updated profiles to target using write-token or per-request sticky read: after a successful write, client receives a token (or use request routing based on user ID) that directs subsequent reads to target until CDC plumbing confirmed catch-up.6. Cutover: once lag is within SLA and validation passes, flip routing to target for reads globally; keep dual-writes for a soak period.7. Decommission: after soak and final reconciliation, stop writes to source and retire.Data consistency strategies:- Use monotonic version/timestamp on profile rows; merge-resolve by higher timestamp to handle eventual arrival ordering.- Idempotent bulk loads and CDC application with transaction ordering (use binlog offsets).- For RAW: leverage write routing token or sticky routing by user ID so reads go to the side that has the latest write; alternatively, synchronous write to target first then async to source during final cutover window.- Continuous verification: background reconciler compares hashes and reports mismatches for manual triage.Risk mitigation & coordination:- Run dry runs, staging migration with representative data.- Throttle and monitor: apply back-pressure, monitor CDC lag, application errors, latency, and mismatch metrics.- Feature flags and incremental rollout (canary by user cohorts, shards, or regions).- Rollback plan: disable dual-write, switch reads back to source instantly if severe issues.- Communication: schedule with stakeholders, maintain runbook, assign owners for DB, app, network, and rollback triggers.Trade-offs:- Dual-write increases write path complexity but minimizes downtime.- Strong RAW via sticky routing adds routing complexity; alternative is synchronous writes to target but increases write latency.This approach provides zero-downtime, RAW guarantees per user, and controlled risk via phased validation, monitoring, and rollback capabilities.
HardTechnical
21 practiced
Write pseudocode for an asynchronous backfill worker that populates a computed column (e.g., full_search_document) for existing rows. The application must continue writing to the table. Ensure your algorithm is idempotent, handles retries, supports concurrency, and converges to a consistent state.
Sample Answer
Approach: run a distributed, idempotent worker that scans rows in chunks, computes the value, and writes it using an atomic conditional update that ensures idempotency and concurrency safety. Use a backfill helper column (backfill_version or backfill_tid) and optimistic concurrency (row_version or updated_at) so writes from concurrent workers and app writes do not conflict. Workers retry transient errors with exponential backoff and mark completion when all rows satisfy computed predicate.Key points:- Idempotent writes: computed value written conditionally; repeated attempts don't change outcome.- Concurrency: SELECT ... FOR UPDATE SKIP LOCKED to avoid collisions across workers; optimistic check on row_version prevents overwriting app updates.- Retries: exponential backoff for transient failures; limited attempts to avoid infinite loops.- Convergence: backfill_version (or timestamp) marks rows as up-to-date; job completes when no candidates remain.- Alternatives/tradeoffs: stronger locking (pessimistic) vs optimistic updates; using background queue vs scheduler; compute-side dedupe if compute is expensive.
python
# pseudocode (Python-like)
WORKER_ID = uuid()
BATCH_SIZE = 100
MAX_RETRIES = 5
# compute_full_document(row) -> string
# db.execute(query, params) executes transactional SQL
while True:
# 1) claim a batch of candidate rows atomically
# candidate: rows where full_search_document IS NULL OR needs recompute (stale)
rows = db.fetch(
"SELECT id, row_version, source_columns FROM table WHERE (full_search_document IS NULL OR backfill_version < ?) AND backfill_owner IS NULL LIMIT ? FOR UPDATE SKIP LOCKED",
[TARGET_BACKFILL_VERSION, BATCH_SIZE]
)
if not rows:
break
for r in rows:
retries = 0
while retries < MAX_RETRIES:
try:
new_doc = compute_full_document(r.source_columns)
# atomic conditional update: only apply if row_version unchanged and backfill_version < target
updated = db.execute(
"UPDATE table SET full_search_document = ?, backfill_version = ?, backfill_owner = NULL, updated_at = now() WHERE id = ? AND row_version = ? AND backfill_version < ?",
[new_doc, TARGET_BACKFILL_VERSION, r.id, r.row_version, TARGET_BACKFILL_VERSION]
)
if updated == 1:
# success: row converged
break
else:
# someone else changed row (app write or other worker). reload row and decide:
r = db.fetch_one("SELECT id,row_version,source_columns,backfill_version FROM table WHERE id = ?", [r.id])
if r.backfill_version >= TARGET_BACKFILL_VERSION and r.full_search_document is not NULL:
# already converged
break
# otherwise recompute with new data and retry
retries += 1
except TransientDBError:
sleep(exp_backoff(retries))
retries += 1
if retries >= MAX_RETRIES:
log.warning("failed to backfill row", r.id)
# termination: ensure no remaining candidates
# run periodically until zero rows match (full_search_document IS NULL OR backfill_version < TARGET_BACKFILL_VERSION)EasyBehavioral
21 practiced
Tell me about a time you helped design or deliver a data migration (any scale). Use the STAR method: Situation, Task, Action, Result. Focus on how you translated business requirements into technical constraints, managed risk, and handled a complication during execution.
Sample Answer
Situation: As a Solutions Architect at my previous employer I led the technical design for migrating a mid-market retail client’s legacy on-premises order management system (OMS) to a cloud-native SaaS platform. The client needed zero-downtime cutover during peak business hours and strict data consistency for orders, inventory, and customer records.Task: My task was to translate the business needs (near-zero downtime, transactional integrity, regulatory retention, and rollback capability) into a technical migration plan, identify constraints, manage risks, and oversee execution with engineering and client stakeholders.Action:- Translated requirements into constraints: enforced ACID-level consistency for orders, max 30-minute cutover SLA, encrypted-at-rest/transit for PII, and retention for 7 years. These became non-functional requirements driving design choices.- Designed a phased migration: staged extracts, schema mapping, canonical data model, dual-write adapter for live sync, and an event-driven CDC pipeline (Debezium → Kafka → transformation layer → target API).- Managed risk by defining checkpoints: reconciliation jobs, row-level checksums, replayable change logs, automated backout scripts, and a dark-run phase where traffic was mirrored to the new system.- Coordinated cross-functional rehearsals — dry runs in a staging environment under simulated peak load; refined throttling, idempotency, and time-to-recover targets.- During execution we hit a complication: a subset of historical orders used an undocumented custom status field that failed validation in the SaaS schema. I quickly convened a stakeholder war room, authorized a two-hour hold, and implemented a transformation rule in the ETL layer to normalize the field and flag uncertain records for manual review. I also expanded reconciliation checks to capture similar schema drift.Result: Migration completed within the SLA window with zero customer-facing downtime. Reconciliation showed 99.995% automated accuracy; the remaining 0.005% were triaged and resolved within 48 hours. The client reported improved order processing latency by 40% and reduced operational overhead. The documented mapping, rollback procedures, and rehearsal playbooks I produced were adopted as a repeatable migration template across other accounts.This project reinforced translating business SLAs into concrete technical constraints, the value of iterative rehearsals to surface hidden data issues, and building automated safeguards to manage migration risk.
HardSystem Design
25 practiced
Architect a zero-downtime migration for a petabyte-scale dataset being moved into a cloud-native database that will serve 100k QPS. Include components for initial bulk transfer, continuous change capture, cutover strategy, reconciliation, and cost/operational trade-offs. Assume multi-region read replicas exist.
Sample Answer
Requirements & constraints:- Petabyte-scale source, target is cloud-native DB supporting 100k QPS with multi-region read replicas- Zero-downtime migration, minimal data loss (RPO≈0), low cutover latency, cost/ops constraintsHigh-level approach:1) Initial bulk transfer (parallel, network-optimized)- Export snapshot in sharded, compressed files (e.g., Parquet/Avro) partitioned by natural key ranges or time.- Use parallel, multi-threaded transfer (ranged exports + multipart upload to cloud object storage). Use WAN acceleration (eg. Direct Connect/Cloud Interconnect + TCP tuning, and tools like AWS Snowball Edge if initial ingest bandwidth insufficient).- Load into target via bulk loader that preserves primary keys and timestamps. Apply schema transformation during load where needed.- Verify checksums per shard (manifest with file-level hashes).2) Continuous change capture (CDC)- Deploy log-based CDC from source (Debezium or vendor CDC) writing an ordered, idempotent change stream to a durable broker (Kafka or cloud-native streaming with ordering guarantees).- Stream processors apply CDC to target in transactional/sequential batches. Use at-least-once with idempotent upserts and monotonic timestamps to ensure convergence.3) Cutover strategy- Dual-write period (optional): instrument application to write to both systems for a validation window; send reads to source or read-replicas until validated.- Progressive traffic shift by region: shift a small % of traffic to new DB read replicas, monitor latency/error metrics, incrementally increase (canary -> 5% -> 25% -> 100%).- Ensure global sequence numbers or monotonic tokens to reconcile in-flight transactions.4) Reconciliation & validation- Continuous reconciler: background jobs compare sampled rows using hashes and row counts per shard; full reconciliation using parallelized compare-by-range.- Use change stream tail to replay any lag. Reconcile high-value keys first.- Automated alerting and human-in-loop rollback gates if divergence above thresholds.5) Rollback & rollback limits- Maintain source writable until cutover completion. For catastrophic divergence, redirect traffic back to source and continue CDC back-fill.Scalability, performance & cost trade-offs- Bulk import via object storage + bulk loader: fast and cost-efficient; expensive if using accelerated appliances but saves time.- CDC via Kafka adds operational overhead and cost but provides durability, replay, and ordering. Serverless streaming reduces ops cost but may increase per-GB price.- Dual-write improves confidence but increases application complexity and latency.- Canary progressive cutover minimizes risk vs. “big bang” which is faster but riskier.- Storage: keep short-term full snapshots for safety (cost vs. recovery speed).Operational considerations- Idempotent writes, conflict resolution rules, schema evolution plan.- Capacity planning: provision target DB for peak 100k QPS with autoscaling for initial ingest bursts.- Observability: end-to-end tracing, latency SLI, reconciliation metrics, and runbooks for rollback/cutover.- Security: encryption in transit/at rest, IAM, network isolation during migration.Result- Parallel bulk + durable CDC + staged cutover achieves zero-downtime migration with bounded risk and clear rollback paths; trade-offs tuned between speed, cost, and operational complexity depending on business priorities.
MediumTechnical
18 practiced
You need to migrate parent (accounts) and child (transactions) tables in batches. Describe an algorithm to migrate in batches while preserving referential integrity and minimizing locking, including how you handle concurrent writes and foreign-key constraints during the migration.
Sample Answer
Requirements & constraints:- Migrate Accounts (parent) and Transactions (child) in batches- Preserve FK integrity- Minimize locking and downtime- Handle concurrent writes during migrationAlgorithm (high-level steps):1. Prep: add migration metadata columns (e.g., migrated_at, source_id) to target if needed. Ensure both systems have a stable unique business key on Accounts (e.g., account_number) to map records without relying on surrogate IDs.2. Phase 1 — Read-only-ish cut for schema-safe changes: - Add nullable FK column in Transactions on target that references the target Accounts key (can be deferred or initially without FK). - Deploy triggers or change-capture (CDC) to capture concurrent writes on both tables into a delta log (insert/update/delete).3. Phase 2 — Batch copy parents then children: - Iterate over Accounts in batches by business key range or created_at. For each batch: a. Copy Accounts batch to target using upsert by business key. Use small transactions to limit locks. b. Mark accounts as copied in migration metadata. c. Copy Transactions whose parent account is in that batch to target using upsert by natural/composite key. While copying, map source account_id -> target account_id using business key lookup. - Keep batch size tuned to avoid long-running transactions.4. Phase 3 — Reconcile deltas: - Apply CDC/delta log in order to both Accounts and Transactions until delta volume is minimal. Repeat until converged.5. Phase 4 — Swap & enforce constraints: - When delta is negligible, quiesce writes briefly (maintenance window) or route writes to a queue. Apply final delta. - Add/enable strict FK constraints on target (or switch routing so target becomes primary). If using DB-level FK, add in a single short transaction.6. Rollback & validation: - Run record counts, checksums, and spot-check joins. Keep ability to roll back by switching application routing.Handling concurrent writes:- Use CDC (Debezium/DB log shipping) or DB triggers to capture changes during migration; apply them in order to target.- For low-latency, apply deltas continuously while copying batches; prioritize ordering guarantees (txn id / timestamp).- To avoid lost updates, use idempotent upserts with last-write-wins based on timestamp or version numbers.FK constraints strategy to minimize locking:- Initially avoid/enforce FK only in application-level or via nullable columns; don't add global FK before data is present.- After copying related parent batch, copy its children immediately so local FK can be validated per-batch (you can add per-batch FK checks via queries).- Delay adding global DB FK until final cutover to avoid long table locks; add during short maintenance window or use online DDL where supported.Trade-offs:- Using CDC increases complexity but minimizes downtime.- Short quiesce window reduces risk of inconsistent state at cutover.- If strict zero-downtime required, consider dual-write during cutover with a reconciliation phase and feature-flag switch.This approach preserves referential integrity by ensuring parents exist before their children per batch, minimizes locks by using small transactions and CDC, and handles concurrent writes by capturing and replaying deltas with idempotent upserts.
Unlock Full Question Bank
Get access to hundreds of Data Migration and Consistency interview questions and detailed answers.
Sign in to ContinueJoin thousands of developers preparing for their dream job.