Architecture kata · K—04

Enterprise Data Warehouse Migration to BigQuery

Architecture kata · design study on a fictional brief

Sector
Retail data platform
Technologies
BigQuery, Dataform, Debezium, Apache Kafka, Cloud Composer, Cloud Storage, Data Vault 2.0, Quarkus, Great Expectations, Dataplex
Flow: legacy warehouse and BigQuery run in parallel, a service reconciles them nightly, and tables switch one by one.
The design at a glance: the one-page, 30-minute live drawing.

In short

Move a 60 TB SQL Server warehouse and 1,900 ETL packages to BigQuery in 12 months, wave by wave, with every table reconciled.

Read the long-form write-up

Problem

A fashion retailer with 1,200 stores in 40 countries runs an on-premises SQL Server warehouse. It holds 60 TB, 2,800 tables and 1,900 SSIS packages, and a Hadoop cluster sits beside it. The nightly batch takes nine hours and often misses the 07:00 deadline. Hardware support ends in 14 months. The board has approved a move to BigQuery. 600 Power BI reports and 40 downstream systems depend on the warehouse, and month-end finance close cannot slip by a day. The data team has 16 people, half of them SQL Server specialists new to the cloud.

Approach

The key constraint: operations never stop during the move. A big-bang cutover is impossible, so the migration goes table by table in dual-run mode. The legacy platform stays the reference. The new platform produces the same tables from the same cut-off point. A reconciliation service compares row counts, sums and hashes every night. No table switches until the difference is zero for two closed accounting periods.

Architecture

  • Capture and load: Debezium change data capture through Kafka to Cloud Storage as Avro. History is bulk-loaded once per wave.
  • Layers: Dataform keeps staging, core (Data Vault 2.0) and dimensional marts as versioned SQL in Git, with assertions and CI/CD only.
  • Legacy packages: SSIS is not auto-translated. A dependency graph is extracted, dead and duplicate packages are dropped, and flows are split into waves by business domain.
  • Control plane: dependency graph, wave planner, reconciliation service and a per-table cutover switch.
  • Consumers: old table names live on as BigQuery views. A reverse sync to SQL Server serves T-SQL consumers for a transition period.
Architecture: legacy stays the reference while CDC and bulk loads feed BigQuery; a control plane reconciles each table.
Solution overview: the legacy warehouse as reference, CDC and bulk loads into BigQuery layers built by Dataform, and the migration control plane with a compatibility service for old names.Open full size (opens in new tab)

Why these components

Need Choice Why
Data warehouse BigQuery, commercial and allowed by the requirement A board decision: serverless, columnar, EU multi-region. Reservations and byte caps make cost predictable; time travel and snapshots give a way back. Trino on Iceberg was not an option once the board chose BigQuery.
Change capture Debezium on Kafka Connect, Apache Kafka on Strimzi Streams SQL Server change tables by log position, with a watermark per table that reconciliation reads. Datastream is managed but lacks older SQL Server versions and schema history. Redpanda was ruled out over its licence.
Initial bulk load bcp and distcp to Avro in Cloud Storage, then BigQuery load jobs 60 TB once per wave, about two days over Interconnect. BigQuery Data Transfer Service is an alternative, but Hadoop data needs distcp anyway. One method means fewer tools.
Landing Google Cloud Storage, EU, immutable Avro files by table and day. Every BigQuery layer can be rebuilt from landing plus Dataform. A lifecycle rule moves objects to Nearline after 90 days.
Transformation Dataform with SQLX The key to SQL Server specialists being productive in three months: they write SQL, not Java. Assertions per model, Git, and CI/CD only. dbt Core is the portable alternative; Dataform needs no extra infrastructure.
Core model Data Vault 2.0 with hubs, links and satellites A source change touches only a satellite; marts and Power BI models stay put. Loads are idempotent MERGEs by business key and load time. A direct dimensional core would break marts on every source change.
Orchestration Cloud Composer, managed Apache Airflow Nightly DAGs per domain, wave DAGs, watermark checks and the 05:00 target. Airflow is open source, and the DAGs stay portable.
Migration control plane Quarkus services on Cloud Run, Cloud SQL PostgreSQL Dependency graph from SSIS XML, wave planner, reconciliation, a cutover switch per table and the close-owner flag. Commercial SSIS translators carry the packages’ technical debt; dropping dead packages halves the work.
Reconciliation Reconciliation service with Great Expectations Row counts, column sums and a canonical row hash per partition, on both sides. Each difference is classified and its rule goes into the transformation. Great Expectations adds thresholds and a readable report.
Compatibility interface Legacy view schema in BigQuery, reverse sync to the existing SQL Server Forty consumers cannot change on one day. Old names live on as views, and 15 T-SQL consumers get a nightly reverse sync. No new SQL Server licence. Babelfish exists only on AWS, with partial T-SQL.
Catalogue, lineage, policy tags Dataplex and BigQuery policy tags Personal data columns are tagged in staging, access goes through policy tags, and an audit dataset logs reads. OpenMetadata is the open alternative; Dataplex gives BigQuery lineage automatically.
Identity Keycloak with OpenID Connect, Google Cloud IAM groups Keycloak for the migration cockpit and Grafana. BigQuery access goes through IAM groups per domain, never per-user grants.
Observability Prometheus, Grafana, Cloud Monitoring, a Logging sink Reconciliation differences, batch finish time, bytes per domain and legacy view use on one dashboard. Audit logs flow into BigQuery for GDPR Article 30 records.

Decisions and trade-offs

  • Dual run by waves, not a big bang. With 2,800 tables and 40 consumers, a weekend cutover has no way back. Month-end close cannot absorb one wrong number. Each table must show zero difference over two closed periods before it moves, and rollback is a flag. The cost is running two platforms. A period with a difference extends that wave by one more period.
  • One owner per month-end close. Before each period opens, the cutover switch records which platform owns the close. Only the owner publishes. The other result is a shadow dataset that only the data team can read, and the finance mart moves as one block. The cost: finance may ask for a parallel close first, which adds a period.
  • Data Vault 2.0 core, not a direct dimensional model. ERP, POS and e-commerce systems keep changing during the migration. A source change touches only a satellite, so marts and 600 Power BI models stay stable, and reconciliation stays traceable per source. Users only see dimensional marts. The cost is more tables.
  • Prove equality, never patch the result. Both sides hash the same canonical string with SHA-256. A difference is classified, such as time zone, rounding, NULL handling, collation or late data, and the rule goes into the Dataform model. If the old system turns out to be wrong, finance decides which number stands, and the decision is written down.
  • FinOps from the first sprint. A fixed slot reservation with an autoscale ceiling, no on-demand for users, and a byte cap on every query: 1 TB for users, 10 TB for pipelines. A query over the cap never starts and creates no bill. Labels feed a monthly chargeback report. The cost: users must narrow their queries, and DirectQuery reports push against the cap.
  • SQL skills first, no automatic SSIS translation. The kata assumes about 30% of 1,900 packages are dead or duplicated. I extract the dependency graph, drop them, and write one Dataform model per flow. That halves the work and teaches the team the SQL. Java stays in a three-person streaming core. The cost is a manual rewrite.
Flow: each table runs on both platforms for two closed periods, is reconciled, and is retired once the difference is zero.
Dual-run, reconciliation, cutover and retirement: how equality, the 07:00 deadline and a single close owner are kept.Open full size (opens in new tab)

What I would revisit

  • T-SQL consumers. Which of the 15 really need T-SQL, and for how long? That sets the life of the compatibility database and the scope of the reverse sync.
  • Finance acceptance. Will finance accept the new platform as close owner from wave five, or ask for a parallel close first? That can stretch a wave by one period.
  • Point-of-sale sources. Debezium needs change capture per database. Older SQL Server versions in 40 countries may need a log-shipping replica in between.
  • Hadoop jobs. If they hold Spark or Java logic, not only SQL, wave one needs a rewrite to Beam or BigQuery SQL.

Outcome notes (design assumptions, not measurements)

This is a design exercise, not a completed migration. The output is a four-page diagram set, a one-page whiteboard version and a 16-page Turkish PDF. The three-hour batch target is a requirement, not a result.

Sources

  • Architecture PDF (Turkish, 16 pages).
  • draw.io diagrams (English labels): four-page set and a one-page 30-minute version.

Real projects on this topic

  1. P—01

    Completed

    Featured

    Enterprise Data Warehouse Migration to Google BigQuery

    80 TB warehouse moved from SQL Server and a 15-node Cloudera cluster to BigQuery: $550K annual savings, 75% lower infrastructure cost, 7x faster workflows.

    • Data platform
    • Data quality
    • Analytics-ready data
    • Orchestration
    • Cloud

    Role

    Design and lead · Senior Data Engineering & Data Architecture Group Manager

  2. P—08

    Completed

    Data Governance, Metadata Management and MDM

    Data governance, metadata management and master data management (MDM) across 100+ source systems, with data catalog and lineage tooling.

    • Data governance
    • Data lineage
    • Data quality

    Role

    Implementation · Big Data Management & Data Architecture Manager

Reliable data: projects, katas and publications

About the katas

Write to me about a similar design problem.