Bộ giải pháp tập trung vào khả năng thiết kế chịu lỗi (Fault-Tolerance) và Đảm bảo Nhất quán dữ liệu phân tán (Eventual Consistency).
1. Clean Architecture & CQRS
Câu 1: Entity, DTO, ViewModels & Validation Layers
- Trả lời:
- Entity: Trái tim của hệ thống (Domain), mang Business Rule và Trạng thái dữ liệu.
- DTO: Object vận chuyển dữ liệu không mang logic (chỉ get/set). Giúp API che đi các Field bảo mật của Entity và cắt đứt dependency vòng.
- ViewModels: Giống DTO nhưng phục vụ riêng cho UI hiển thị cụ thể (MVC, Razor).
- Validation 2 lớp:
- Lớp Application (FluentValidation): Validate tính trọn vẹn của dữ liệu Data Request (Ký tự email đúng dải, Phone number ko rỗng, số âm). Trả về 400 Bad Request.
- Lớp Domain (Entity setter/Domain Validaton): Validate Business Rules (Người dưới 18 không mua rượu, Số dư không đủ). Nó bảo vệ Invariant của Entity bằng Exception hoặc Result Wrapper.
Câu 2: MediatR và Bất cập IN-PROCESS Event
- Trả lời:
- MediatR Publish
INotificationtrong cùng một memory process. Nếu một Controller Command gọiPublish(UserCreated), rồi có 5 Handlers khác subscribe $\implies$ Toàn bộ 5 Handler đó CHẠY NGẦM trong cùng Thread Pool của cái Reuqest ban đầu. - Điều này phình thời gian Request API ngút ngàn, và nếu 1 Handler fail, Transaction Db của cái Request gốc không có cách nào Rollback an toàn (Lỗi cục bộ).
- Giải pháp Architect:
- Cắt đứt IN-PROCESS bằng Out-Process Message Broker (MassTransit $\to$ RabbitMQ). Event
UserCreatedbắn ra Queue, các Microservice khác hoặc Background Worker nuốt và xử lý Asynchronously. - Cân nhắc Saga Pattern nếu workflow quá phức tạp đỏi hỏi State Machine đàng hoàng.
- Cắt đứt IN-PROCESS bằng Out-Process Message Broker (MassTransit $\to$ RabbitMQ). Event
- MediatR Publish
Câu 3: Anemic Domain Model vs Encapsulation
- Trả lời: "Mô hình miền thiếu máu" là Entity chỉ chứa properties Public
{ get; set; }và không chứa bất kì function hành vi nào. Toàn bộ tính toán, thay đổi dữ liệu bị đẩy tuốt ra ngoàiOrderService(Service Layer).- Nó phá hoại Encapsulation vì bất cứ Developer DevJunior nào tiêm (inject) Order Repository vào bất kỳ đâu cũng có thể TỰ Ý LẤY
Order.Total += 200vàcontext.SaveChanges()mà không phải thông qua Business Rule của Model đó, dẫn đến data rác, rò rỉ mã lỗi.
- Nó phá hoại Encapsulation vì bất cứ Developer DevJunior nào tiêm (inject) Order Repository vào bất kỳ đâu cũng có thể TỰ Ý LẤY
2. Microservices & Distributed Consistency
Câu 4: CAP Theorem: Tại sao phải chọn P?
- Trả lời: Trong môi trường mạng lưới Phân Tán (Internet/Intranet), Network Partition (Chia cắt mạng) là điều HIỂN NHIÊN. Dây cáp đứt, Switch lỗi, Container node crash. Hệ thống buộc phải dung sai trước việc Không thể kết nối (P).
- Vì vậy thực chất ta đánh đổi C hoặc A.
- Ngân hàng: Chọn CP (Đứt mạng? Khoá sổ ko cho chuyển tiền để tránh sai số $\implies$ Hy sinh A).
- E-Commerce: Chọn AP (Đứt mạng? Catalog cứ hiển thị giá bộ nhớ đệm, sai chút ko sao miễn website vẫn sống $\implies$ Hy sinh C tạm thời thành Eventual C).
Câu 5: Tránh Overselling do Eventual Consistency delay
- Giải pháp Architect:
- Không để Order xử lý độc lập nếu Inventory quan trọng hơn 1 chữ "Stock Out".
- Áp dụng Distributed Saga (Orchestration) hoặc Sách lược Đặt Cọc (Reservation Pattern). Cụ thể:
- Lệnh Checkout tới API Gateway gọi Order API tạo
Pending Order. - Gọi Sync nhanh qua gRPC khoá tạm
Pending Stocktại lô hàng Inventory bằng Cache Redis Lock trong 5 phút. Nhanh và có Time-to-live. - Trả về UI "Đặt hàng thành công tạm tính".
- Async queue phía sau chạy thanh toán thực/xử lý kho. Nếu sập mạng? Lên Scheduled Job trả Lock lại lúc hết hạn 5 phút.
- Lệnh Checkout tới API Gateway gọi Order API tạo
Câu 6: Idempotency trong API Thanh toán
- Giải pháp Architect: Thêm Header
Idempotency-Keydo Front-end quy định lúc Click "Pay". Khóa này đính kèm cùng UUID của cái Bill đó.- API nhận Request, Insert Idempotency Key này vào 1 bảng phụ trên DB (Hoặc Redis), set Status = "Processing".
- Bất kỳ rớt mạng nào sinh Retry lần 2/lần 3 mang khóa cũ chọc vào API $\implies$ DB cản lại 409 Conflict hoặc Redis check Key Exist trả lại kết quả cũ của lần 1.
- Xong giao dịch DB sửa thành Status = "Success" và Payload log. Lần retry sau nhận luôn Status Cũ.
3. Communication & Saga
Câu 7: API Gateway vs Service Mesh & gRPC
- Trả lời:
- Gateway: Đứng ở Bắc-Nam (Hứng traffic User ngoài Internet vào). Trách nhiệm: Routing, Throttling, SSL Termination, Auth.
- Service Mesh: Đứng ở Đông-Tây (Traffic liên kết giao tiếp giữa Mservice 1 sang Mservice 2 bên trong tường lửa Cluster). Trách nhiệm: Mutual TLS bảo mật nội bộ, Retry, Trace, Circuit Breaker vô cực mà Dev ko cần viết code vào app.
- gRPC vs REST: REST = Text Based Payload JSON nặng nề dư băng thông. gRPC = HTTP/2, Protobuf nhị phân nén rất nhỏ, tốc độ Serialize/Deserialize bằng code gen Protoc trên C# nhanh gấp chục lần JSONNewtonsoft/SystemTextJson. Sử dụng gRPC cho liên lạc Nội Bộ Backend $\implies$ tốc độ cận in-process.
Câu 8: Choreography vs Orchestration
- Trả lời:
- Choreography (Múa tập thể): Order bắn Event, Email nhận tự gửi, Payment nhận tự trừ tiền... Không ai quan tâm ai. Dễ làm lúc đầu. Khi 1 luồng đi qua 5 thằng, 1 thằng sập, không ai theo dõi trạng thái chung của Luồng đó nằm ở đâu để Compensate (Khôi phục lệnh hoàn tiền) $\implies$ "Nồi mỳ ý chết chóc".
- Orchestration (Nhạc trưởng): Có 1 Con Cua (State Machine) điều khiển riêng. Ra lệnh cho Payment, nhận reply OK. Lại rẽ nhánh gọi Inventory. Lỗi phát con cua State Machine tự triệu hồi nhánh Hủy Order bọc hậu. Công nghệ lõi: MassTransit StateMachines / Azure Durable Functions.
Câu 9: Giải quyết Dual-Write bằng Outbox Pattern
- Trả lời:
Save() và Pub()đồng thời sẽ fail nếu Broker (RabbitMQ) sập 1 giây đúng lúc DB Save thành công. - Outbox Pattern:
- Bảng Order tạo. Cùng lúc, Bảng Outbox DB ghi nội dung Event chuỗi "Thêm order 123", Status = "Unpublished". Ghi chung 1 UnitOfWork EFCore SQL Transaction. 1 SQL Commit $\implies$ Chắc chắn cả đôi cùng ghi nợ.
- Một Worker Background (CronJob/Dotnet HostedService/Debezium Kafka) 1 giây quét bảng Outbox 1 lần: Nếu chưa Pub $\implies$ Nó gửi gắm sang RabbitMQ an toàn. Nhận ACK từ RabbitMQ $\implies$ Đánh dấu Outbox DB Update Status = "Published". (Giữ tính bền vững Consistent tuyệt đối).