Backend · Database

Database Migration: Chiến Lược Không Downtime

Database Migration - Chiến lược không downtime

Database migration là thay đổi rủi ro cao nhất trong software development. Một migration script sai có thể corrupt data, lock tables hàng giờ, hoặc tệ hơn — mất dữ liệu không thể khôi phục. GitHub outage 2023 bắt nguồn từ schema migration lock table 3 giờ ảnh hưởng hàng triệu developers. GitLab từng downtime 6 giờ vì failed database migration. Chi phí trung bình 1 giờ downtime cho enterprise: $300,000+ (Gartner 2024). Bài viết này chia sẻ chiến lược zero-downtime migration từ kinh nghiệm thực tế tại BanhCuonFlow — nơi production database chạy 24/7 phục vụ doanh nghiệp.

Tại Sao Migration Nguy Hiểm?

Table locks: ALTER TABLE trên PostgreSQL có thể acquire ACCESS EXCLUSIVE lock trên bảng triệu records. Mọi query (SELECT, INSERT, UPDATE) phải chờ lock release → application timeout, users nhận 500 error. Một migration thêm column với DEFAULT value trên bảng 10 triệu rows có thể lock table 30+ phút.

Data loss: DROP COLUMN không có backup = mất dữ liệu vĩnh viễn. ALTER TYPE không backward-compatible → data truncation hoặc conversion errors. Sai regular expression trong data migration script → corrupt hàng nghìn records trước khi phát hiện.

Inconsistency & Rollback: Migration thành công nửa chừng rồi fail → database ở trạng thái "nửa cũ nửa mới." Application code expect schema mới nhưng DB còn schema cũ → runtime errors. Sau khi DROP COLUMN, không rollback được bằng migration — cần restore từ backup, mất data mới.

Expand-Contract Pattern (Zero Downtime)

Thay vì rename column trực tiếp (breaking change), dùng 3 deployment phases:

Phase 1: Expand

Thêm column mới (ví dụ: full_name), giữ column cũ (name). Application code đọc từ column cũ (backward compatible), ghi vào cả hai columns. Deploy code change trước, migration sau. Zero risk — fail thì rollback code, DB không thay đổi gì breaking.

Phase 2: Migrate Data

Backfill data từ column cũ sang mới bằng batch update — không update tất cả 1 lần (tránh long-running transaction). Ví dụ: UPDATE users SET full_name = name WHERE full_name IS NULL LIMIT 1000 — chạy loop đến khi hết. Verify data consistency: count, spot-check, compare checksums. Sau verify: switch application code sang đọc từ column mới.

Phase 3: Contract

Sau khi confirm 100% data đã migrate và application chỉ dùng column mới: drop column cũ. Mỗi phase là 1 deployment riêng — rollback bất kỳ lúc nào mà không downtime. Total: 3 deploys thay vì 1, nhưng zero risk. BanhCuonFlow dùng expand-contract cho mọi schema change trên production.

PostgreSQL-Specific: Tránh Lock Pitfalls

PostgreSQL có nhiều subtleties khi migration. ADD COLUMN với DEFAULT value (PG < 11): rewrite toàn bộ table — lock hàng phút trên bảng lớn. PG 11+ đã fix cho non-volatile defaults, nhưng vẫn cần cẩn thận. CREATE INDEX: default mode acquire SHARE lock, block tất cả writes. Giải pháp: CREATE INDEX CONCURRENTLY — không lock, nhưng chậm hơn 2-3x và có thể fail (cần retry nếu fail). ALTER TYPE: luôn tốn ACCESS EXCLUSIVE lock. Thay vào: thêm column mới với type mới, migrate data, drop column cũ (expand-contract). SET NOT NULL: PG cần scan toàn bộ table để verify. Dùng CHECK constraint trước (ALTER TABLE ADD CONSTRAINT ... NOT VALID), validate sau (VALIDATE CONSTRAINT) — validate chỉ cần SHARE UPDATE EXCLUSIVE lock, không block writes.

EF Core Migrations: BanhCuonFlow Workflow

BanhCuonFlow dùng EF Core Code-First migrations. Quy trình: modify entity class → dotnet ef migrations add [Name] → review generated SQL (luôn check SQL, không tin generated code mù quáng) → apply staging → run integration tests → apply production. Quy tắc BanhCuonFlow: Migration file phải idempotent (chạy lại không lỗi). Luôn backup trước khi apply production. Không sửa migration file đã apply trên bất kỳ environment nào. Naming convention: YYYYMMDD_DescriptiveNameInEnglish.

So Sánh Migration Tools

EF Core Migrations

.NET ecosystem. Code-first, auto-generate từ C# entity models. Tích hợp sâu với ORM, model-based diffing. Nhược: khó kiểm soát exact SQL generated. Phù hợp: .NET projects, BanhCuonFlow.

Flyway

SQL-based, version control cho DB schema. Java native nhưng multi-platform. Bạn viết SQL thuần, full control. Convention: V1__init.sql, V2__add_column.sql. Phù hợp: teams cần full SQL control.

Liquibase

XML/YAML/JSON changeset format. Rollback built-in (auto-generate reverse SQL), DB diff tool (compare 2 schemas). Enterprise features: audit trail, policy checks. Phù hợp: enterprise multi-DB environments.

Prisma Migrate

Schema-first, TypeScript ecosystem. Auto-generate SQL từ Prisma schema file. Shadow database cho safe migration preview. Phù hợp: Node.js/TypeScript, rapid development, greenfield projects.

Rollback Strategy

① Forward-only migrations: Mỗi migration chỉ đi tới. Nếu cần "rollback," viết migration mới undo changes. Ưu: audit trail rõ, đơn giản, mọi change đều tracked. BanhCuonFlow dùng approach này.

② Point-in-time recovery (PITR): PostgreSQL WAL (Write-Ahead Logging) cho phép restore DB về bất kỳ thời điểm nào — chính xác đến giây. BanhCuonFlow config: WAL archiving liên tục + daily base backup = PITR window 7 ngày. Khi migration catastrophic → restore DB về thời điểm trước migration trong vài phút.

③ Blue-Green Database: Maintain 2 databases: Blue (đang live) và Green (apply migration mới). Test trên Green, nếu OK → switch traffic. Nếu fail → switch lại Blue. Complexity cao (cần data sync), cost gấp đôi, nhưng zero downtime guaranteed. Phù hợp enterprise critical systems.

Database trong BanhCuonFlow

PostgreSQL + EF Core, zero-downtime migrations, WAL backup, PITR recovery. Production-grade database architecture.