
Event Sourcing và CQRS: kiến trúc sự kiện cho app thương mại
Event Sourcing (ES) là một mô hình lưu trữ dữ liệu trong đó trạng thái của một thực thể được xác định bởi một chuỗi các sự kiện (event) chứ không phải bởi trạng thái hiện tại trên bảng. Kết hợp với CQRS (Command Query Responsibility Segregation), ES tách biệt rõ ràng phần ghi (commands) và phần đọc (queries), mang lại kiến trúc linh hoạt và mạnh mẽ. Kết hợp với React và Node.js, phần này giúp bạn xây dựng hệ thống thương mại với lịch sử giao dịch đầy đủ.

Nguyên tắc cơ bản của Event Sourcing
Trong một hệ thống truyền thống, chúng ta thường lưu trữ trạng thái hiện tại của một thực thể — ví dụ như số dư tài khoản ngân hàng. Khi có giao dịch mới, chúng ta cập nhật số dư trực tiếp. Với Event Sourcing, thay vì lưu số dư, chúng ta lưu lại một chuỗi các sự kiện — như Deposited(1000), Withdrew(300), Deposited(500). Trạng thái hiện tại (số dư) được tính toán bằng cách “phát lại” (replay) toàn bộ các sự kiện từ đầu.
| Phương pháp | Lưu trữ | Đọc dữ liệu | Ưu điểm | Nhược điểm |
|---|---|---|---|---|
| Event Sourcing | Dãy sự kiện từ đầu | Phát lại toàn bộ event | Lịch sử đầy đủ, audit trail | Chậm khi event nhiều, phức tạp |
| Stateful (truyền thống) | Trạng thái hiện tại | Đọc trực tiếp từ bảng | Đơn giản, nhanh | Mất lịch sử, khó audit |
Lợi ích chính của Event Sourcing
- Lịch sử giao dịch đầy đủ: Mọi thay đổi đều được lưu lại như một event, giúp bạn dễ dàng audit và truy ngược.
- Khả năng replay dữ liệu: Bạn có thể phát lại toàn bộ sự kiện để tính toán lại trạng thái ở bất kỳ thời điểm nào.
- Hỗ trợ CQRS tự nhiên: Event Souring cung cấp một luồng dữ liệu thống nhất cho cả phần ghi và đọc.
- Mở rộng (scalable) cho hệ thống sự kiện phi đồng bộ (event-driven).

CQRS: tách biệt lệnh và truy vấn
CQRS tách rời hai mô hình dữ liệu: một cho việc ghi (Write Model) và một cho việc đọc (Read Model). Write Model xử lý các lệnh (commands) và sinh ra các sự kiện, trong khi Read Model nghe các sự kiện này để cập nhật các view đọc được tối ưu cho từng nhu cầu. Với kiến trúc này, bạn có thể dùng cơ sở dữ liệu khác nhau cho ghi và đọc — ví dụ như dùng PostgreSQL cho ghi và Redis cho đọng nhanh.
Fluent Validation và .NET trên nền tảng CQRS
Trong các hệ thống thương mại thực tế (ví dụ: nền tảng thương mại điện tử), các lệnh (commands) thường được xác thực (validate) bằng Fluent Validation trước khi được gửi đến aggregate. Khi sự kiện được sinh ra, các handler trong Read Model sẽ cập nhật các bảng view được tối ưu cho truy vấn.
CreateOrderCommand: kiểm tra thông tin khách hàng, tồn khoOrderCreatedevent: cập nhậtOrderListViewcho dashboard quản lýPaymentProcessedevent: cập nhậtCustomerBalanceViewcho hệ thống tài khoản

Event Store: lựa chọn công nghệ lưu trữ sự kiện
Có nhiều công nghệ hỗ trợ Event Sourcing, từ các giải pháp chuyên biệt như EventStoreDB cho đến các cơ sở dữ liệu quan hệ (PostgreSQL, SQL Server) với cột JSON. Dưới đây là so sánh nhanh:
| Công nghệ | Loại | Tail lag | Durable | Chú thích |
|---|---|---|---|---|
| EventStoreDB | Chuyên biệt | ~0ms | Có | Tối ưu cho ES, hỗ trợ subscription |
| PostgreSQL (JSONB) | Quan hệ | Medium | Có | Dễ tích hợp, transaction mạnh |
| AWS DynamoDB Streams | NoSQL | ~1s | Có | Serverless, auto-scaling |
| RabbitMQ / Kafka | Message queue | Variable | Có | Good cho event-driven, không persist lâu dài |
Với EventStoreDB, bạn có thể đăng ký (subscribe) vào event stream để xử lý async. RabbitMQ phù hợp cho hệ thống microservice, trong khi Kafka tốt cho phân tích dữ liệu lớn. Lựa chọn công nghệ còn phụ thuộc vào yêu cầu về độ bền (durability), tốc độ (tail lag) và khả năng mở rộng.
Nguyên tắc thiết kế Aggregate trong Event Sourcing
Một Aggregate (trong DDD) là một thực thể và các thực thể con của nó, được điều khiển bởi một root duy nhất. Trong Event Sourcing, Aggregate là nơi chứa logic nghiệp vụ (business logic) và quyết định sinh ra sự kiện nào. Để tránh aggregate trở nên quá lớn, bạn nên chia nhỏ thành các aggregate nhỏ (có kích thước cố định), mỗi aggregate chịu trách nhiệm cho một trần bài toán (bounded context) nhất định.
Mot nhiên được sinh ra trong quá trình tái tạo trạng thái từ event store, các aggregate được tải bằng cách áp dụng (apply) sự kiện cho trạng thái nội bộ. Điều này yêu cầu thiết kế method apply trên từng loại event.
Kết luận: khi nào nên dùng Event Sourcing + CQRS
Event Sourcing và CQRS phụ thích hợp để xây dựng hệ thống thương mại phức tạp với nhu cầu audit, audit trail, và khả năng replay dữ liệu lại. Tuy nhiên, chúng không phải là giải pháp phù hợp cho mọi trường hợp — đặc biệt là các ứng dụng đơn giản với ít thay đổi trạng thái. Bạn nên cân nhắc áp dụng khi:
- Hệ thống cần lịch sử giao dịch đầy đủ để audit
- Yêu cầu mở rộng (scale) phần đọng và ghi độc lập
- Nghiệp vụ phức tạp với nhiều quy tắc nghiệp vụ (business rules)
Tham khảo thêm: Martin Fowler – Event Sourcing, Microsoft Azure – CQRS pattern.
