Change Data Capture (CDC) trong Microservices
Làm thế nào để đồng bộ dữ liệu giữa các services trong kiến trúc Microservcies
Vấn đề
Trong kiến trúc microservices, mỗi service sẽ quản lý cơ sở dữ liệu riêng. Tuy nhiên, khi một tính năng yêu cầu liên kết dữ liệu giữa nhiều service, cách triển khai sẽ trở nên phức tạp hơn.
Ví dụ, trong hệ thống e-commerce đã đề cập ở bài viết về Saga pattern, giả sử trang User Profile cần hiển thị toàn bộ đơn hàng mà người dùng đã đặt, kèm trạng thái của từng sản phẩm và chi tiết của sản phầm. Khi đó, dữ liệu phải được lấy từ ba service: User, Order và Product.
Bài toán đặt ra là:
Làm thế nào để đồng bộ dữ liệu giữa các service mà không cần truy cập trực tiếp database của service khác và không phải gọi API quá nhiều?
Làm sao để dữ liệu được cập nhật gần như real-time — tức là khi dữ liệu ở một service thay đổi, các service liên quan cũng tự động nhận được bản cập nhật mới nhất?
Giải pháp: Change Data Capture (CDC)
CDC là kỹ thuật giúp ghi nhận các thay đổi (thêm mới, xóa, cập nhật hoặc thay đổi cấu trúc của bảng) trong cơ sở dữ liệu và truyền chúng tới các hệ thống khác (target system) trong thời gian thực thông qua các thông điệp.
Làm thế nào để capture sự thay đổi?

Trong cơ sở dữ liệu, mọi thao tác đều được ghi lại vào transaction log. Transaction log (còn gọi là write-ahead log hoặc database log) là một tệp hoặc vùng lưu trữ trong hệ quản trị cơ sở dữ liệu, dùng để ghi nhận toàn bộ thay đổi dữ liệu trước khi chúng được áp dụng chính thức vào bảng.
Với phương pháp log-based, các công cụ CDC sẽ theo dõi transaction log này, và khi phát hiện có thay đổi, chúng sẽ phát sinh sự kiện và gửi các message tới các hệ thống liên quan.
Làm thế nào để gửi các message đi và nhận chúng?
Các thông điệp sẽ được gửi vào message queue để các service liên quan có thể lắng nghe và xử lý khi có thay đổi.
Một công cụ CDC phổ biến là Debezium (https://debezium.io). Debezium theo dõi các thay đổi trong transaction log, và khi phát hiện update, nó sẽ gửi thông điệp vào các Kafka topic tương ứng.
Các service liên quan sẽ consume từ những topic này để nhận dữ liệu thay đổi và xử lý theo nhu cầu của service đó. Đảm bảo cho data có tính nhất quán, cập nhật kịp thời.
Ví dụ trong bài toán E-commerce
Giả sử chúng ta có hệ thống như sau và một số chức năng cơ bản.
User Service: lưu thông tin người dùng (id, tên, email, địa chỉ, v.v.).
Order Service: lưu thông tin đơn hàng (id đơn hàng, id user, danh sách sản phẩm, trạng thái đơn hàng).
Inventory Service: lưu thông tin tồn kho của từng sản phẩm (id sản phẩm, số lượng tồn).
Product Service: lưu thông tin sản phẩm (id sản phẩm, tên, giá, mô tả, ảnh).
Yêu cầu tính năng:
Trong User Profile Page, cần hiển thị tất cả đơn hàng của user kèm trạng thái sản phẩm trong đơn.
Trong Product Detail Page, hiển thị số người đã mua sản phẩm này.
Dữ liệu phải real-time khi một service thay đổi, các service khác cũng phải cập nhật.
Mỗi service có database riêng
Cách triển khai:
Cài Debezium Connector cho từng DB để đọc transaction log.
Debezium publish các sự kiện thay đổi lên Kafka topic tương ứng.
user-db-connector→ topicuser-eventsorder-db-connector→ topicorder-eventsCho cả 2 tables: order và order item
inventory-db-connector→ topicinventory-eventsproduct-db-connector→ topicproduct-events
User service ( Liệt kệ order detail của user)
Lắng nghe ở topic
order-eventsvà build bảng dữ liệu order_snapshot và orders_item_snapshot để khi user mở profile có thể query nhanh mà không gọi API chéo nhiều lần. Đồng thời cũng lắng nghe ở topicproduct-eventslấy thông tin về product.Mỗi khi cần liệt kê order detail của môt user, user service chỉ cần join table từ bảng chính (user_profiles) và join với các bảng snapshot trong user service database. Không cần gọi tới các service khác để lấy thêm thông tin.
Data ở user service sẽ trông như thế này
-- Bảng chính: user_profiles user_id | name | email | created_at --------+-------------+-----------------------+--------------------- U001 | Nguyễn An | an.nguyen@example.com | 2024-02-10 U002 | Trần Bình | binh.tran@example.com | 2024-05-21 --- Bảng orders_snapshot order_id | user_id | total_amount | status | order_date ---------+---------+--------------+------------+----------------- O101 | U001 | 500000 | DELIVERED | 2024-08-01 O102 | U001 | 350000 | PENDING | 2024-08-12 O103 | U002 | 200000 | DELIVERED | 2024-08-08 --- Bảng orders_item_snapshot +---------------+-----------+------------+----------+ | order_item_id | order_id | product_id | quantity | +---------------+-----------+------------+----------+ | 1001 | 101 | 1 | 2 | | 1002 | 101 | 2 | 3 | | 1003 | 102 | 1 | 1 | | 1004 | 102 | 3 | 5 | | 1005 | 103 | 4 | 4 | +---------------+-----------+------------+----------+ --- bảng product_snapshot +------------+---------+--------+-------------------+-------------+ | product_id | name | price | image_url | description | +------------+---------+--------+-------------------+-------------+ | 1 | Áo thun | 150000 | /img/ao.jpg | Áo cotton | | 2 | Jeans | 350000 | /img/jeans.jpg | Quần jeans | +------------+---------+--------+-------------------+-------------+Product service ( Đếm số người đã mua hàng)
Lắng nghe ở topic
order-eventskhi một order hoàn thành, cập nhật số người mua cho từng sản phẩmTưng tự như order detail ở user service, product service chỉ cần lấy data ở database của riêng nó, không cần gọi thêm service khác để lấy thêm data.
Data flow:
+--------------------+
| Order DB |
+--------------------+
|
| CDC (Debezium Connector)
v
[Kafka: order-events]
|
+--------------+--------------+
| |
[User Service] [Product Service]
(update user_orders_cache) (update buyers_count)
+--------------------+
| Product DB |
+--------------------+
|
| CDC (Debezium Connector)
v
[Kafka: product-events]
|
[User Service]
Ưu điểm của CDC
Qua ví dụ trên chúng ta có thể thấy CDC có một số ưu điểm sau:
Đồng bộ hoá dữ liệu giữa các service một cách dễ dàng mà không làm tăng workload khi cần truy cập data.
Tách biệt giữa các service, các service không cần truy cập database của nhau.
Gần như real-time sync, mỗi thay đổi data ở một service có thể gần như lập tức được cập nhật ở service khác, đảm báo tính nhất quán của dữ liệu.
Nhược điểm của CDC
Và đương nhiên, không có solution nào là hoàn hảo, chúng ta phải đánh đổi một số thứ sau:
Cần thêm không gian để lưu trữ các bảng snapshoot giữa các services.
Cần thiết lập và duy trì CDC tools
Event có thể bị mất, trùng hoặc thay đổi thứ tự khi truyền giữa các service, cần cơ chế để xử lý ở phần này ( ví du sử dung idempotent key)
Kết luận
CDC là một cơ chế mạnh mẽ có thể dễ dàng tích hợp với các microservices để theo dõi sự thay đổi dữ liệu trong thời gian thực. CDC giúp các microservices hoạt động hiệu quả và linh hoạt hơn, cho phép chúng cung cấp kết quả tốt hơn. Bằng cách sử dụng CDC cùng microservices, bạn có thể tận dụng dữ liệu thời gian thực và quá trình ra quyết định để tối ưu hoá quy trình và nâng cao trải nghiệm khách hàng.
Nếu bạn có thắc mắc gì đừng ngần ngại đặt câu hỏi ở phần comment. Đừng quên subscribe để luôn cập nhật những bài viết mới nhất từ blog của mình.
Đọc thêm:
https://www.infoq.com/presentations/cdc-microservices/
https://learn.microsoft.com/en-us/sql/relational-databases/track-changes/about-change-data-capture-sql-server?view=sql-server-ver17
https://medium.com/%40bijit211987/change-data-capture-with-microservices-79fa90aaf0b3




mình thấy thêm phương pháp này làm hệ thông phức tạp, quản lý nhiều hơn, chứ vấn đề thì Saga pattern cũng giải quyết được rồi
Bạn có thể cung cấp code ví dụ không?