ADR-0002. CDC (Debezium) làm seam tích hợp - Kafka chỉ producer
| Trường | Giá trị |
|---|---|
| Status | Accepted |
| Ngày | 2026-03-15 |
| Người quyết định | Phat Nguyen |
| Thay thế | - |
Bối cảnh
- Commerce là nguồn dữ liệu gốc cho catalog/tenant. Nhiều dịch vụ cần dữ liệu của nó: search (đánh chỉ mục products/merchants/categories), inventory (khởi tạo locations + items), pricing (khởi tạo fares), taxation (cấp phát nhóm thuế), invoice (suy ra
TaxInfo). - Việc phát Kafka ở tầng ứng dụng sẽ buộc commerce phải biết mọi hợp đồng phía hạ nguồn, phát một topic cho mỗi dạng thay đổi, và giữ cho code phát sự kiện luôn đồng bộ với mọi thay đổi dữ liệu catalog trên nhiều dịch vụ - gắn kết cao và dễ bỏ sót một đường ghi.
- Postgres vốn đã ghi lại mọi thay đổi trong WAL. Debezium có thể nắm bắt thay đổi đó một cách tổng quát.
Quyết định
Dùng CDC (Debezium) làm seam tích hợp chính. Nghĩa vụ duy nhất của commerce là ghi đúng vào Postgres; Debezium đọc WAL và publish một topic cho mỗi bảng (CDCKafkaTopics / CdcTables trong @nx/core, ví dụ public.Merchant, public.ProductVariant).
- Các consumer phía hạ nguồn (search/inventory/pricing/taxation/invoice) tự lo phần đấu nối CDC consumer của riêng mình.
ApplicationKafkaComponentcủa commerce chỉ ràng buộc một producer - và trên thực tế không gọi.send()ở bất cứ đâu trongsrc/. Có khai báo một khóa ràng buộcAPPLICATION_KAFKA_CONSUMERnhưng không có consumer nào được đấu nối.- CDC consumer duy nhất mà chính commerce chạy là
ApplicationCdcComponent(từ@nx/search, vai trò WORKER) để đồng bộ DB của chính nó vào Typesense. - Thông tin thuế của merchant là ví dụ điển hình cho mẫu hình này: ghi vào
Merchant.metadata.tax, được CDC nắm bắt, rồi được@nx/invoiceupsert vàoTaxInfo(nguồn đọc chuẩn ở phía hạ nguồn).
Hệ quả
| Ưu | Nhược |
|---|---|
| Không cần code phát sự kiện riêng cho từng consumer trong commerce; consumer mới gắn vào mà không phải sửa commerce | Consumer gắn chặt với schema của bảng - đổi tên cột sẽ gây phá vỡ |
| Không có rủi ro "quên phát sự kiện trên đường ghi này" | CDC thêm Debezium/Kafka Connect thành phụ thuộc vận hành |
| Thứ tự WAL + replay theo offset cho phép phân phối bền, có thể phát lại | Nhất quán sau cùng; consumer phải idempotent theo từng PK |
| Producer được giữ lại để dùng về sau mà không ép phải dùng ngay | Một producer đã ràng buộc nhưng nhàn rỗi có thể gây nhầm lẫn cho người mới (đã ghi chú ở đây) |
Phương án đã cân nhắc
| Tùy chọn | Ưu | Nhược | Vì sao bị từ chối |
|---|---|---|---|
| Phát Kafka ở tầng ứng dụng theo từng thay đổi | Payload tường minh, được chọn lọc | Gắn kết cao; phải cài đặt cho mọi đường ghi trong mọi dịch vụ | Dễ vỡ; phá vỡ tính đơn giản của nguồn dữ liệu gốc |
| Phát tán HTTP đồng bộ trên mỗi thay đổi dữ liệu | Tức thì | Gắn kết chặt lúc chạy; lỗi lan tỏa dây chuyền; ghi chậm | Phạm vi ảnh hưởng không chấp nhận được |
| Bảng outbox + relay | Đảm bảo tính giao dịch | Phát minh lại thứ mà Debezium đã cung cấp miễn phí trên WAL | Debezium đã bao quát rồi |
Tham khảo
packages/core/src/common/cdc/tables.ts(CdcTables)packages/core/src/common/kafka/topics.ts(CDCKafkaTopics)src/components/kafka/component.ts(producer được ràng buộc, không gọi.send())src/common/keys.ts(APPLICATION_KAFKA_CONSUMERđược khai báo, không dùng)src/services/merchant.service.ts(tax →metadata.tax→ CDC →TaxInfo)