Khi app đang chạy nhiều instance, không thể đổi schema và code cùng lúc — phải để schema cũ và mới song song tồn tại trong lúc deploy cuốn chiếu. Đó là expand → migrate → contract.
Ví dụ đổi cột username → handle:
1. Expand (mở rộng): thêm cột mới handle (nullable, không phá cột cũ). Schema tương thích ngược — code cũ vẫn chạy.
2. Dual-write: deploy code ghi vào cả hai cột, đọc cột cũ. Backfill dữ liệu cũ sang handle theo batch.
3. Migrate read: deploy code đọc từ handle. Giờ cả hai cột đồng bộ.
4. Contract (thu hẹp): ngừng ghi cột cũ; sau khi chắc chắn không còn ai đọc → drop username.
Vì sao chia nhỏ: mỗi bước deploy phải tương thích với phiên bản code liền trước và liền sau (rolling deploy có cả hai version chạy song song).
Lưu ý:
- Tránh thao tác DDL khóa bảng lâu (thêm cột NOT NULL có default trên bảng lớn) — dùng công cụ online như pt-online-schema-change/gh-ost.
- Áp dụng cả khi tách bảng, đổi kiểu dữ liệu, hay tách service.
With many app instances running, you can't change schema and code at once — the old and new schema must coexist during a rolling deploy. That's expand → migrate → contract.
Example: rename username → handle:
1. Expand: add the new column handle (nullable, leave the old one). Backward-compatible — old code still works.
2. Dual-write: deploy code that writes both columns, reads the old one. Backfill old rows into handle in batches.
3. Migrate read: deploy code that reads from handle. Both columns now stay in sync.
4. Contract: stop writing the old column; once sure nobody reads it → drop username.
Why split it up: each deploy step must be compatible with the immediately previous and next code version (a rolling deploy runs both at once).
Notes:
- Avoid long table-locking DDL (adding a NOT NULL default on a huge table) — use online tools like pt-online-schema-change/gh-ost.
- Applies equally to splitting tables, changing column types, or splitting a service.