11 KiB
ADR-006 — Một cụm RDS PostgreSQL chính, schema-per-module, chịu tải ghi/đọc gộp (trừ Payment)
Tên file: adr/ADR-006_chien-luoc-du-lieu-rds-gop-schema-per-module.md
| Status | Proposed (🔴 radar ≥8 — theo decision-radar.md §2/§6, không được chuyển Accepted khi chưa có POC-02 PASS) |
| Date | 2026-09-15 |
| Người quyết | SA + Tech Lead/DBA (dữ liệu — decision-radar.md §5) |
| Người đề xuất | SA (qua skill sa-2-architecture, hoạt động adr) |
| Điểm radar | ~8/10 — 🔴 bắt buộc POC trước Accepted |
| Supersedes | — |
| Superseded by | — |
| Liên quan | ASR-006 · QAS-006 · ARISK-02 · POC-02 · ADR-001 · ADR-002 (Payment tách riêng, độc lập) |
⚠️ ADR bất biến sau khi
Accepted. Muốn đổi quyết định thì viết ADR mới cóSupersedes: ADR-006và đổi trạng thái bản cũ thànhSuperseded by.
1. Bối cảnh
Modular monolith P2 (ADR-001) cần một chiến lược dữ liệu nhất quán cho mọi module ngoài
Payment (đã tách riêng theo ADR-002). ASR-006 ép ra một cụm RDS PostgreSQL Multi-AZ chính,
chia theo schema-per-module — chưa đo tải ghi (checkout) + đọc (catalog) gộp ở tải đỉnh flash
sale. Đây là quyết định đạt ngưỡng radar ≥8 vì chưa có bài đo thật trong ngữ cảnh này (ASM-08).
Ràng buộc đang chi phối:
| Nguồn | Nội dung |
|---|---|
ASR-006 |
1 RDS chính schema-per-module, chịu tải ghi/đọc gộp cho mọi module trừ Payment |
QAS-006 |
p95 write (checkout) ≤300ms, p95 read (catalog) ≤200ms, CPU <75%, connection pool không exhaust |
ADR-001 |
Modular monolith P2 — tiền đề cho việc gộp dữ liệu theo schema thay vì database-per-service |
ADR-002 |
Payment có RDS riêng — không nằm trong phạm vi cụm RDS chính này |
Cái đã biết chắc / cái còn là giả định:
| Điều | 🟢 Đã kiểm chứng / 🔴 Giả định | Bằng chứng |
|---|---|---|
| Payment có RDS riêng, tách biệt hoàn toàn khỏi cụm chính | 🟢 Đã kiểm chứng | ADR-002 |
1 cụm RDS db.r6g.xlarge Multi-AZ đủ chịu tải ghi/đọc gộp cho các module ngoài Payment ở kịch bản A/B |
🔴 Giả định (ASM-08) |
POC-02 — chưa chạy |
| Connection pool chia theo module đủ tránh một module chiếm hết pool | 🔴 Giả định | Chưa có thiết kế connection pool chi tiết — thuộc DAT, hoạt động 5 |
2. Phương án đã cân nhắc
PA-1 — Database-per-service (mỗi module 1 RDS logic riêng)
| Mô tả | Mỗi module (Identity, Catalog, Cart & Order, Seller, Commission, Promotion, Review, Notification, Shipping) có 1 RDS instance/logic DB riêng — theo SAD.md/hồ sơ thầu (P1) |
| Ưu | Cô lập tải hoàn toàn — một module quá tải không ảnh hưởng module khác; dễ scale/tune riêng từng DB |
| Nhược | ~9-10 RDS instance phải patch/backup/monitor độc lập — vi phạm Conway với năng lực team hiện tại (CON-05); tăng chi phí vận hành đáng kể so với 1-2 instance |
| Chi phí đảo ngược | Cao — gộp lại thành 1 cụm sau này cần migrate dữ liệu qua nhiều DB, đồng bộ schema |
PA-2 — 1 cụm RDS chính, schema-per-module (ranh giới logic, chung instance) (chọn)
| Mô tả | 1 cụm RDS PostgreSQL Multi-AZ, mỗi module có schema riêng trong cùng instance (ranh giới logic rõ ràng qua schema + quyền truy cập DB user riêng theo schema) |
| Ưu | Ít thành phần phải vận hành hơn (1 instance thay vì ~9-10) — khớp Conway với team hiện tại; vẫn giữ ranh giới logic rõ ràng qua schema (không phải 1 schema dùng chung hỗn loạn) |
| Nhược | Một module quá tải (VD Catalog bị truy vấn nặng mùa flash sale) có thể ảnh hưởng module khác dùng chung instance (Cart & Order, Commission…) — chưa đo tải gộp thật |
| Chi phí đảo ngược | Trung bình-cao — tách read replica/DB riêng cho từng module sau khi đã gộp là một dự án migration riêng |
PA-3 — 1 cụm RDS, 1 schema chung (không phân tách theo module)
| Mô tả | Tất cả bảng của mọi module nằm chung 1 schema, không phân tách quyền truy cập theo module |
| Ưu | Đơn giản nhất về mặt cấu hình DB ban đầu |
| Nhược | Không có ranh giới logic nào giữa các module — vi phạm D7 ("mỗi thực thể có đúng một chủ sở hữu" cần ranh giới rõ để enforce); dễ phát sinh coupling ngầm (module A viết trực tiếp bảng của module B) làm mất tác dụng modular monolith |
| Chi phí đảo ngược | Cao — tách schema sau khi code đã coupling chéo là công việc tái cấu trúc lớn |
Bảng so sánh
| Tiêu chí | PA-1 (DB-per-service) | PA-2 (1 cụm, schema-per-module) | PA-3 (1 cụm, 1 schema) |
|---|---|---|---|
| Số thành phần phải vận hành | ~9-10 | 1 | 1 |
| Cô lập tải giữa module | ✅ Hoàn toàn | 🟠 Một phần (chung instance) | ❌ Không |
Ranh giới logic rõ ràng (D7) |
✅ | ✅ (qua schema) | ❌ |
Khớp Conway (CON-05) |
❌ | ✅ | ✅ |
3. Quyết định
Chọn PA-2 — 1 cụm RDS PostgreSQL Multi-AZ chính, schema-per-module, cho mọi module ngoại trừ Payment.
Vì sao: Cân bằng giữa khớp Conway (CON-05, ít thành phần vận hành hơn database-per-service)
và vẫn giữ ranh giới logic rõ ràng qua schema (khác PA-3 gộp chung 1 schema mất kiểm soát ranh
giới dữ liệu).
Phạm vi áp dụng: Toàn bộ module ngoại trừ Payment (đã có RDS riêng theo ADR-002).
Điều kiện chuyển Proposed → Accepted
| Điều kiện | Ai xác nhận | Trạng thái hiện tại |
|---|---|---|
POC-02 PASS — p95 write ≤300ms, p95 read ≤200ms, CPU <75%, connection pool không exhaust |
Tech Lead/DBA | 🔴 Chưa chạy (ARISK-02) |
| Thiết kế connection pool theo module (giới hạn để tránh một module chiếm hết pool) | Tech Lead/DBA | Chưa thiết kế — thuộc DAT |
🔴 Bắt buộc theo decision-radar.md §2/§6 — điểm radar ~8 (≥8) đồng nghĩa ADR này không
được chuyển Accepted cho tới khi POC-02 chạy xong và PASS. Nếu POC-02 FAIL: tách read
replica/DB riêng cho Catalog/Search sớm hơn dự kiến, cập nhật TCO (chi phí hạ tầng tăng, tiệm
cận P1 cho phần đó — đã cảnh báo ở TCO §3.3).
4. Phương án bị loại và lý do
| Phương án | Loại vì | Gắn với | Điều kiện nào thì xét lại |
|---|---|---|---|
| PA-1 — Database-per-service | Vi phạm Conway với năng lực team hiện tại; tăng chi phí vận hành đáng kể | CON-05, OPT §4 tiêu chí 5 |
Nếu POC-02 FAIL nghiêm trọng (không thể khắc phục bằng read replica) và team đủ lớn để vận hành nhiều DB — xét lại cho riêng module gây nghẽn (VD tách Catalog) |
| PA-3 — 1 cụm, 1 schema chung | Không có ranh giới logic — vi phạm D7, dễ coupling chéo giữa module |
D7 (design-rules) |
Không xét lại — đây là anti-pattern cho modular monolith, không phải trade-off hợp lý |
5. Hệ quả
Hệ quả tích cực
- Chỉ 1 RDS instance chính phải patch/backup/monitor (ngoài Payment) — khớp năng lực team, giảm chi phí vận hành đáng kể so với database-per-service
- Ranh giới logic rõ ràng qua schema — enforce được
D7(mỗi thực thể có đúng một chủ)
Hệ quả tiêu cực phải sống chung
- Một module quá tải (VD Catalog mùa flash sale) có thể ảnh hưởng module khác dùng chung instance — cần connection pool giới hạn theo module để giảm thiểu
- Nếu
POC-02FAIL, phải tách read replica sớm hơn dự kiến — tăng chi phí hạ tầng ngoài kế hoạch ban đầu
Cái quyết định này khoá lại
| Muốn đổi về sau thì | Tốn |
|---|---|
| Tách một module ra RDS riêng sau khi đã gộp | Migration dữ liệu + đồng bộ song song trong thời gian chuyển đổi — dự án riêng, không miễn phí |
Việc phát sinh
| Việc | Chủ | Hạn | Ghi ở đâu |
|---|---|---|---|
Chạy POC-02 theo tiêu chí đã viết trước |
Tech Lead/DBA | Trước khi Accepted |
ARISK_e-commerce_v1.0.md §6 |
| Thiết kế connection pool giới hạn theo module | SA (hoạt động dat) + DBA |
GĐ2 tiếp theo | DAT_e-commerce |
Kế hoạch tách read replica dự phòng nếu POC-02 FAIL |
Tech Lead/DBA | Khi có kết quả POC-02 |
TDEBT (GĐ3) hoặc cập nhật TCO |
6. Cách kiểm chứng quyết định này được tuân thủ
| Cách kiểm | Công cụ | Chạy ở đâu | FIT |
|---|---|---|---|
POC-02 — tải ghi/đọc gộp |
Load test staging, cấu hình instance thật | Trước Accepted, lặp lại trước mỗi major release |
— (ghi vào ARISK §6) |
| Không có bảng nào bị truy cập chéo schema (module A viết trực tiếp bảng module B) | DB user permission theo schema + code review/lint | CI (schema access lint) | FIT-09 (ứng viên) |
| CPU/connection pool RDS trong ngưỡng ở production | CloudWatch metric + alarm | Production, liên tục | — |
7. Điều kiện xét lại
| Dấu hiệu | Ngưỡng | Ai theo dõi |
|---|---|---|
POC-02 FAIL |
Không đạt tiêu chí PASS đã viết trước | Tech Lead/DBA |
| CPU RDS production vượt 75% thường xuyên | > 3 lần/tuần trong giờ cao điểm | SRE |
| Connection pool exhaust trong production | Bất kỳ lần nào | SRE |
8. Tham chiếu
- POC:
ARISK_e-commerce_v1.0.md §6 POC-02 - Bài đo:
FIT-09(ứng viên GĐ3) - Tài liệu ngoài:
QAS_e-commerce_v1.0.md §A3 QAS-006 - Thảo luận:
ASR_e-commerce_v1.0.md §B2 ASR-006,OPT_e-commerce_v1.0.md §8 ASM-08
9. Review log (không đổi Status)
| Ngày | Người review | Vai trò | Quyết định | Lý do chưa chuyển Accepted |
|---|---|---|---|---|
| 2026-09-15 | Điều phối dự án (thay mặt Tech Lead, chế độ chạy thử) | Tech Lead (ký thay, ngoại lệ DEC-01) |
Reviewed (Proposed giữ nguyên) — nội dung đủ làm cơ sở thiết kế tiếp (icd/dat/sec/inf/fail) |
Radar 8 — bắt buộc POC-02 (tải RDS gộp) PASS trước khi Accepted; chưa chạy |
Đây là ghi nhận review nội dung, không phải "sign" theo nghĩa gate:
Statusgiữ nguyênProposed. Xem00-index/ADL_e-commerce.md(Change Log — Review 2026-09-15) vàADL §8"Việc phải làm" cho điều kiện chuyểnAccepted. Confidence tổng thể của lượt review: 🔴 —AG2chưa ký.