154 lines
6.4 KiB
Markdown
154 lines
6.4 KiB
Markdown
# FAIL — Failure Mode & Resilience Design — <PROJECT>
|
||
|
||
| | |
|
||
|---|---|
|
||
| **Version** | 1.0 |
|
||
| **Date** | YYYY-MM-DD |
|
||
| **Author** | <SA> (skill sa-2-architecture) |
|
||
| **Status** | 🟡 Draft |
|
||
| **Approved by** | Tech Lead: — · SRE: — · QA: — |
|
||
| **Source** | SAD_… v1.0 · ICD_… v1.0 · QAS_… v1.0 |
|
||
| **Scope** | |
|
||
| **Confidence** | 🟡 |
|
||
|
||
## Change Log
|
||
|
||
| Version | Date | Người sửa | Thay đổi | ADR |
|
||
|---|---|---|---|---|
|
||
| 1.0 | | | Bản đầu | — |
|
||
|
||
> 🔴 **Đây là phần phân biệt SA giỏi và SA vẽ sơ đồ**, và là phần bị bỏ nhiều nhất. Phần lớn
|
||
> sự cố production đến từ những ô còn trống trong tài liệu này.
|
||
|
||
---
|
||
|
||
## 1. Bảng phụ thuộc — mọi lời gọi vượt ranh giới process
|
||
|
||
*HTTP, CSDL, cache, hàng đợi, file, hệ thống ngoài. Không sót cái nào.*
|
||
|
||
| ID | Phụ thuộc | Từ `CMP` | `IF-nnn` | Timeout | Retry | Idempotent | Hết retry thì sao | Người dùng thấy gì | `QAS` |
|
||
|---|---|---|---|---|---|---|---|---|---|
|
||
| `FM-01` | CSDL chính | `CMP-01` | — | … ms | 0 | — | trả lỗi 503 | "Hệ thống bận, thử lại sau" | `QAS-002` |
|
||
| `FM-02` | API POS ngoài | `CMP-03` | `IF-005` | … ms | 3 · backoff mũ + jitter | ✅ khoá: … | vào hàng đợi, xử lý sau | "Đã ghi nhận, đang xử lý" | `QAS-007` |
|
||
|
||
🔴 **Retry trên thao tác không idempotent là cách nhân đôi dữ liệu.** Cột "Idempotent" phải
|
||
được điền trước cột "Retry", không phải ngược lại.
|
||
|
||
## 2. Bốn câu hỏi cho mỗi phụ thuộc
|
||
|
||
*Quy tắc `D6`. Không được bỏ câu nào — đặc biệt câu 1 và câu 4.*
|
||
|
||
### `FM-01` — <tên phụ thuộc>
|
||
|
||
| # | Câu hỏi | Trả lời |
|
||
|---|---|---|
|
||
| 1 | **Nó chậm thì sao?** *(nguy hiểm hơn hỏng: giữ tài nguyên, lan ngược lên tầng trên)* | |
|
||
| 2 | **Nó hỏng thì sao?** *(degrade được không, hay chết cả luồng)* | |
|
||
| 3 | **Nó trả sai dữ liệu thì sao?** *(có phát hiện được không, bằng gì)* | |
|
||
| 4 | **Nó hồi phục thì sao?** *(retry storm, thundering herd, cần backpressure không)* | |
|
||
|
||
🔴 **Câu 1 là câu bị bỏ nhiều nhất.** Một phụ thuộc hỏng hẳn thì mạch ngắt nhanh; một phụ
|
||
thuộc trả lời sau 30 giây sẽ giữ hết connection pool và kéo sập cả hệ thống. Timeout luôn phải
|
||
nhỏ hơn nhiều so với timeout của tầng gọi nó.
|
||
|
||
**Ngân sách timeout theo tầng** *(timeout tầng ngoài phải > tổng timeout tầng trong)*
|
||
|
||
| Tầng | Timeout | Ghi chú |
|
||
|---|---|---|
|
||
| Trình duyệt → gateway | … s | |
|
||
| Gateway → service | … s | |
|
||
| Service → CSDL | … ms | |
|
||
| Service → API ngoài | … ms | × số lần retry phải vẫn < timeout tầng trên |
|
||
|
||
### `FM-02` — <tên phụ thuộc>
|
||
|
||
*(cùng cấu trúc)*
|
||
|
||
## 3. Cơ chế chống lan lỗi
|
||
|
||
*Ba cơ chế quyết định một lần cho toàn hệ thống, ghi thành `ADR`.*
|
||
|
||
### 3.1 Circuit breaker
|
||
|
||
| Áp dụng cho | Ngưỡng mở | Thời gian nửa mở | Điều kiện đóng lại | Hành vi khi mở |
|
||
|---|---|---|---|---|
|
||
| `IF-005` | … % lỗi trong … giây | … s | … lần thành công liên tiếp | trả fallback: … |
|
||
|
||
### 3.2 Backoff & jitter
|
||
|
||
| | Quyết định |
|
||
|---|---|
|
||
| Kiểu backoff | mũ / tuyến tính |
|
||
| Có jitter không | **phải có** — không jitter thì mọi client retry cùng lúc |
|
||
| Số lần tối đa | |
|
||
| Tổng thời gian tối đa | |
|
||
|
||
### 3.3 Bulkhead (tách pool tài nguyên)
|
||
|
||
| Nhóm | Pool riêng cho | Kích thước | Vì sao tách |
|
||
|---|---|---|---|
|
||
| | *(ví dụ: gọi API ngoài dùng pool riêng, để nó cạn không ảnh hưởng luồng nội bộ)* | | |
|
||
|
||
## 4. Suy giảm có kiểm soát (graceful degradation)
|
||
|
||
*Khi một phần hỏng, hệ thống làm được gì thay vì chết hẳn.*
|
||
|
||
| Thành phần hỏng | Chức năng mất | Chức năng vẫn chạy | Người dùng thấy gì | Ai quyết mức degrade |
|
||
|---|---|---|---|---|
|
||
| Cache | | | | |
|
||
| API gợi ý | | | | |
|
||
| Hệ thống báo cáo | | | | |
|
||
|
||
🔴 **Mức degrade là quyết định nghiệp vụ, không phải kỹ thuật.** PO phải chốt: thà hiển thị dữ
|
||
liệu cũ 10 phút hay thà báo lỗi? Hai lựa chọn khác nhau ở rủi ro nghiệp vụ, không ở kỹ thuật.
|
||
|
||
## 5. Kịch bản hỏng toàn hệ thống
|
||
|
||
| # | Kịch bản | Phát hiện bằng | Sau bao lâu phát hiện | Hệ quả | Cách xử lý | Runbook |
|
||
|---|---|---|---|---|---|---|
|
||
| 1 | Mất kết nối CSDL chính | | … phút | | | |
|
||
| 2 | Hàng đợi đầy | | | | | |
|
||
| 3 | Rò rỉ bộ nhớ, service khởi động lại liên tục | | | | | |
|
||
| 4 | Hệ thống ngoài trả 200 nhưng dữ liệu sai | | | | | |
|
||
| 5 | Tăng tải đột biến ×10 | | | | | |
|
||
| 6 | Deploy sai, phải rollback | | | | | `INF` §7 |
|
||
|
||
## 6. Dữ liệu trong lúc lỗi
|
||
|
||
| Câu hỏi | Trả lời |
|
||
|---|---|
|
||
| Giao dịch đang dở khi service chết ⇒ trạng thái nào còn lại | |
|
||
| Ai dọn trạng thái nửa vời, sau bao lâu | |
|
||
| Message đã nhận nhưng chưa xử lý xong ⇒ mất hay xử lý lại | |
|
||
| Poison message (xử lý mãi không được) ⇒ đi đâu | DLQ · giữ … · ai xử lý |
|
||
| Có mất dữ liệu nào chấp nhận được không | *(khớp RPO ở `INF` §5)* |
|
||
|
||
## 7. Diễn tập
|
||
|
||
*Failure mode chưa diễn tập là giả thuyết. AG3 yêu cầu ít nhất các `FM` mức cao đã được thử.*
|
||
|
||
| `FM` | Cách diễn tập | Môi trường | Lần gần nhất | Kết quả | Đúng như thiết kế? |
|
||
|---|---|---|---|---|---|
|
||
| `FM-01` | tắt CSDL replica | stg | | | ☐ |
|
||
| `FM-02` | chặn mạng tới API ngoài | stg | | | ☐ |
|
||
|
||
🔴 Diễn tập hay phát hiện: timeout cấu hình khác tài liệu, retry không có jitter, cảnh báo
|
||
không bắn, runbook viết cho hệ thống phiên bản cũ. Đó chính là giá trị của việc diễn tập.
|
||
|
||
## 8. Giả định & Ngoài phạm vi
|
||
|
||
**Giả định:**
|
||
|
||
| ID | Giả định | Cách xác minh | Nếu sai |
|
||
|---|---|---|---|
|
||
| `ASM-nn` | API ngoài giữ đúng SLA đã cam kết | theo dõi thực tế | |
|
||
|
||
**Ngoài phạm vi:**
|
||
|
||
- *(ví dụ: không xử lý trường hợp mất toàn bộ vùng cloud — thuộc DR ở `INF` §5)*
|
||
|
||
## 9. Open Questions
|
||
|
||
| ID | Câu hỏi | Hỏi ai | Từ ngày | Chặn gì | Hệ quả nếu trả lời ngược |
|
||
|---|---|---|---|---|---|
|