Tổng quan Cơ bản 7 phút đọc

System Design .NET — Tổng kết: 5 bài học còn lại

Tổng kết series System Design .NET A -> Z: năm bài học sống lâu hơn case study, checklist kiến trúc .NET production, và đọc gì sau series.

Mục lục
  1. Bài 1 — ước lượng đem lại gì mà vẽ hộp không?
  2. Bài 2 — stack mặc định đúng cho service .NET là gì?
  3. Bài 3 — khi nào việc chậm nên qua queue?
  4. Bài 4 — thiết kế cho lỗi cục bộ ra sao?
  5. Bài 5 — observability thật sự để làm gì?
  6. Năm bài học lắp thành một kiến trúc ra sao?
  7. Checklist kiến trúc .NET production?
  8. Đọc gì sau series?
  9. Bạn nên làm gì ngày mai?
  10. Nếu bài toán của tôi không khớp case study nào?
  11. Đi tiếp đâu từ đây?

Bạn bắt đầu series muốn cách lặp được trả lời "thiết kế X ra sao". Hy vọng bạn kết thúc với nhận thức "ra sao" quan trọng ít hơn "với số nào". Chương cuối ngắn theo thiết kế - năm bài học, một checklist, và danh sách đọc tiếp. Series ở lại; cuộc trò chuyện về codebase của bạn bắt đầu.

Bài 1 — ước lượng đem lại gì mà vẽ hộp không?

Mọi quyết định kiến trúc trong series đều quay về một số từ chương 2. Cache tồn tại vì khuếch đại read; queue tồn tại vì side effect dài; shard tồn tại vì write vượt một node Postgres. Không có số, mọi hộp trên sơ đồ là đoán mò.

Hệ quả gắt: ứng viên hay engineer bỏ qua ước lượng không bảo vệ được kiến trúc của mình. Họ mô tả được, triển khai được, nhưng khi ai đó hỏi "vì sao" họ không có gì. Số là câu trả lời. Luyện trên mọi hệ bạn gặp, ngay cả khi không ai hỏi.

Bài 2 — stack mặc định đúng cho service .NET là gì?

Sau hai mươi sáu chương, câu trả lời tẻ nhạt đúng phần lớn thời gian:

Với tay vào thay thế ngoại lai

Bài 3 — khi nào việc chậm nên qua queue?

Ba dấu hiệu trả lời "có":

Nếu cái nào đúng, chương message queue áp dụng. Ghép queue với consumer idempotent (chương 10) và bạn có service sống sót mọi failure mode tạm.

Hệ quả: HTTP đồng bộ fire-and-forget gần như luôn sai. Cho bạn không retry không bền vững không back-pressure. Số sự cố production do "controller gọi third-party trong đường request" cao đến nản.

Bài 4 — thiết kế cho lỗi cục bộ ra sao?

Mọi thành phần trong kiến trúc sẽ fail lúc nào đó. Câu hỏi là cái nào trong bốn pattern reliability áp dụng:

// Bốn default resilience cho service .NET:
builder.Services.AddHttpClient<IExternalApi>()
    .AddStandardResilienceHandler();  // Polly: retry + circuit breaker + timeout

builder.Services.AddMassTransit(x =>
{
    x.AddSagaStateMachine<OrderSaga, OrderSagaState>()
       .EntityFrameworkRepository();   // Saga + outbox + persistence
    x.UsingRabbitMq();
});

// Cộng: middleware idempotency trên mọi endpoint thay đổi state
// (chương 10), và OpenTelemetry để thấy việc đang xảy ra
// (chương 13).

Bốn dòng đăng ký, bốn pattern sẵn sàng production. Phần lớn service .NET sập 3 giờ sáng thiếu một trong số đó. Cách sửa hiếm khi là kỹ thuật anh hùng; là kỷ luật tẻ dây pattern từ ngày đầu.

Bài 5 — observability thật sự để làm gì?

Ba thứ, theo thứ tự ưu tiên:

  1. Alert triệu chứng - báo oncall khi user không vui.
  2. Điều hướng trace - giải thích vì sao một request chậm.
  3. Planning capacity - số sau back-of-envelope thành số thật trong dashboard.

Không có OpenTelemetry, bạn có hy vọng. Có nó, bạn có phương pháp. Mọi quyết định kiến trúc trong series test được với metric nó sinh; nếu không đo được, không bảo vệ được.

Năm bài học lắp thành một kiến trúc ra sao?

Các bài học không độc lập - chúng xếp tầng thành hình mà mọi service .NET production cuối cùng nhận:

flowchart LR
    Estimate[1. Ước lượng trước thiết kế] --> Stack[2. Stack mặc định:<br/>PG + Redis + RabbitMQ]
    Stack --> Async[3. Queue việc chậm]
    Async --> Reliab[4. Idempotency + outbox<br/>+ handler resilience]
    Reliab --> Obs[5. OpenTelemetry<br/>trace + metric + log]
    Obs --> Iterate[Lặp trên số]
    Iterate --> Estimate

Vòng đóng vì observability nuôi vòng ước lượng tiếp: metric thật thay đoán, kiến trúc điều chỉnh, chu kỳ tiếp tục. Service chạy vòng này vài năm rốt cuộc thiết kế tốt thật - không nhờ lựa chọn anh hùng nào, mà nhờ kỷ luật đều.

Checklist kiến trúc .NET production?

Cắt ra dán lên tường:

Trước khi ship service mới, kiểm tra:

[ ] Ước lượng QPS đỉnh, storage 1 năm, budget latency p99, trên giấy.
[ ] PostgreSQL với read replica dây trong EF Core.
[ ] Redis cache với TTL rõ và IDistributedCache.
[ ] Ít nhất một đường async qua queue (RabbitMQ / Service Bus).
[ ] Middleware idempotency trên mọi endpoint thay đổi state.
[ ] Outbox pattern cho write + publish.
[ ] Resilience handler HttpClient trên mọi call ngoài.
[ ] Trace + metric OpenTelemetry, export sang backend.
[ ] Middleware rate limiter trên endpoint public.
[ ] Auth qua cookie hoặc JWT, không bao giờ localStorage.
[ ] Sitemap, dashboard observability, và runbook cho alert đầu.
[ ] Load test ở 2x đỉnh ước lượng trước launch.

Mười hai mục. Phần lớn sự cố production tôi đã debug trace về một checkbox thiếu. Danh sách là phần tẻ của system design; làm chủ nó là cái phân biệt "chạy trên máy tôi" với "chạy trên Black Friday".

Đọc gì sau series?

Bạn nên làm gì ngày mai?

Năm thói quen nhỏ biến series thành kỹ năng vĩnh viễn:

  1. Trích một số bất cứ khi đề xuất thành phần. "Cần Kafka vì 10K event/giây" không phải "cần Kafka vì nó tốt cho event".
  2. Thêm observability trước tính năng. Dây OpenTelemetry ngày đầu của service mới. Chương observability mất 30 phút dây.
  3. Hỏi queue. Mỗi khi ai đề xuất queue, hỏi "ngăn failure mode nào?". Đôi khi câu trả lời là không và call đồng bộ đúng.
  4. Review PR qua lăng kính system design. "Idempotency của endpoint này ở đâu?" "Nếu Redis down thì sao?". Câu hỏi đẩy team về phía pattern.
  5. Đọc lại một chương mỗi tuần trong sáu tuần. Nhận biết quan trọng hơn nhớ; đọc lại có giãn cách thắng đọc một mạch anh hùng.

Nếu bài toán của tôi không khớp case study nào?

Bạn sẽ, thi thoảng, thiết kế gì đó không khớp chín cái nào. Vậy ổn. Case study là hình phổ biến, không phải duy nhất. Khi bài toán thật mới, nước đi đúng là mô tả nó tốt - ước lượng tải, gọi tên mô hình nhất quán, xác định failure mode - dùng từ vựng chương 1. Đó là cách pattern mới vào cuộc trò chuyện.

Đi tiếp đâu từ đây?

Cảm ơn bạn đã đọc series. Bộ từ vựng là của bạn; các kiến trúc là của bạn để remix. Bây giờ mở một codebase production đó và tìm một pattern bạn nhận ra.

Câu hỏi thường gặp

Kỹ năng nào khó nhất và quan trọng nhất?
Kiềm chế. Phần lớn sự cố .NET production đến từ hệ over-engineer nơi ai đó dùng tới Kafka, Cassandra, hay microservice trước khi ước lượng QPS biện minh được. Chương bạn đọc lại nhiều nhất là back-of-envelope vì đó là kỷ luật nói không với phức tạp sớm.
Đọc gì sau series này?
Ba sách và một site. Designing Data-Intensive Applications của Martin Kleppmann là tiếp nối kinh điển - xử lý quán, replication, stream processing sâu hơn nhiều. Site Reliability Engineering (Google, miễn phí online) lo nửa vận hành. Release It! của Michael Nygard xử lý failure mode. Cộng highscalability.com cho case study hệ production thật.
Có chủ đề thiết kế nào series bỏ?
Vài cái đáng nhắc: chương riêng cho chiến lược CDN, multi-region active-active, hạ tầng phục vụ ML, database time-series, và kiến trúc bảo mật. Nguyên tắc chuyển; chi tiết cài đặt khác. Coi series là bảng chữ cái, không phải từ điển.
Bài học lớn nhất là gì?
System design là ra quyết định dưới bất định. Số từ chương 2, mô hình nhất quán từ chương 3, pattern từ chương 10-12 - tất cả là công cụ biện minh lựa chọn. Bản thân lựa chọn hiếm khi khó; bảo vệ nó dưới áp lực mới khó. Series dạy bộ từ vựng cho bạn làm cả hai.