Event Sourcing và CQRS: kiến trúc sự kiện cho app thương mại

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 đủ.

Event Sourcing and CQRS architecture diagram with command side and query side separation

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).

Event store database showing chronological event log with timestamps and aggregate roots

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 kho
  • OrderCreated event: cập nhật OrderListView cho dashboard quản lý
  • PaymentProcessed event: cập nhật CustomerBalanceView cho hệ thống tài khoản

CQRS read model with optimized query views updated from event stream

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.

Tôi là một lập trình viên IOS. Code chính là IOS nhưng thỉnnh thoảng vẫn đá sang Android hoặc web. Mặc dù không quá thông thạo nhưng tôi sẽ chia sẻ những kiến thức mà mình đã tìm hiểu, áp dụng qua.

Bài viết liên quan

Kubernetes pods resource management: requests vs limits

Kubernetes pods resource management: requests vs limits Trong môi trường container orchestration, việc quản lý tài nguyên một cách hiệu quả không chỉ giúp tối ưu chi phí mà còn…

Xem thêm
docker_twistlock

Docker multi-stage builds: Cách thu nhỏ image xuống 90%

Docker multi-stage builds: Cách thu nhỏ image xuống 90% Một trong những thách thức lớn nhất khi dùng Docker là image size quá lớn. Một image Python đơn giản có…

Xem thêm
Giao diện Jetpack Compose trên thiết bị Android

Jetpack Compose Kotlin: Xây dựng ứng dụng Android hiện đại

Jetpack Compose Kotlin: Xây dựng ứng dụng Android hiện đại Jetpack Compose Kotlin đang cách đẳng cách phát triển giao diện Android bằng cách thay thế XML bằng mã Kotlin…

Xem thêm
0 0 đánh giá
Article Rating
Theo dõi
Thông báo của
guest
0 Comments
Cũ nhất
Mới nhất Được bỏ phiếu nhiều nhất