Hai lựa chọn chính: API composition hoặc CQRS read model.
API composition — một thành phần (gateway/BFF/service tổng hợp) gọi từng service rồi ghép kết quả.
ts
const [order, user, payment] = await Promise.all([
orderApi.get(orderId),
userApi.get(userId),
paymentApi.getByOrder(orderId),
])- Ưu: đơn giản, dữ liệu luôn mới, không cần hạ tầng thêm.
- Nhược: latency = chặng chậm nhất (nếu gọi song song); một service lỗi là cả màn hình hỏng nếu không có fallback; không lọc/sắp xếp/phân trang được trên trường của service khác. Muốn "lọc đơn theo tên khách + sắp theo ngày giao" thì composition phải kéo về rồi lọc trong bộ nhớ — không chấp nhận được ở dữ liệu lớn.
CQRS read model — dựng sẵn một bảng/index đọc riêng, cập nhật bằng event từ các service nguồn.
- Ưu: một truy vấn duy nhất, lọc/sắp/phân trang thoải mái, latency thấp và ổn định, không phụ thuộc service nguồn đang sống.
- Nhược: eventually consistent (trễ replication), phải xử lý event trùng và sai thứ tự, thêm một bản sao dữ liệu phải vận hành và rebuild được.
Chọn thế nào: mặc định dùng composition. Chuyển sang read model khi truy vấn cần lọc/sắp xuyên service, khi tần suất đọc rất cao, hoặc khi số chặng phải gọi tăng lên khiến latency không kiểm soát được.