Xử lý Outbox Pattern trong Microservices: Đảm bảo tính nhất quán giữa Database và Message Broker
Cơn ác mộng phân tán: DB lưu thành công nhưng Message Broker sập Hãy xem xét đoạn code tưởng chừng rất bình thường sau: Nếu bước 1 thành công nhưng bước 2 bị fail do Kafka cluster rớt mạng hoặc serve…
☰ Mục lục bài viết (4 phần) Mở / Đóng mục lục
Cơn ác mộng phân tán: DB lưu thành công nhưng Message Broker sập#
Hãy xem xét đoạn code tưởng chừng rất bình thường sau:
await db.transaction(async (trx) => {
await orderService.createOrder(trx, orderData); // 1. Lưu đơn hàng vào DB
});
// 2. Gửi message thông báo sang Kafka để trừ tiền
await kafkaProducer.send('order_events', { event: 'ORDER_CREATED', orderId });
Nếu bước 1 thành công nhưng bước 2 bị fail do Kafka cluster rớt mạng hoặc server bị crash đột ngột? Đơn hàng đã được lưu nhưng không ai trừ tiền hay gửi hàng, hệ thống rơi vào trạng thái dữ liệu bất nhất (Data Inconsistency).
Nếu đảo ngược lại (gửi Kafka trước rồi lưu DB sau)? Nếu lưu DB fail, bạn lại phát đi một event giả mạo!
Giải pháp chuẩn mực: Transactional Outbox Pattern#
Ý tưởng cốt lõi: Thay vì gửi trực tiếp sang Kafka, hãy ghi sự kiện cần phát vào một bảng tạm có tên là outbox_events nằm TRONG CÙNG TRANSACTION của database chính!
-- Bảng Outbox nằm chung trong cơ sở dữ liệu
CREATE TABLE outbox_events (
id UUID PRIMARY KEY,
aggregate_type VARCHAR(255) NOT NULL,
aggregate_id VARCHAR(255) NOT NULL,
event_type VARCHAR(255) NOT NULL,
payload JSONB NOT NULL,
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
processed_at TIMESTAMPTZ
);
Vì cùng nằm trong 1 Transaction của PostgreSQL, hoặc cả đơn hàng và event cùng được lưu, hoặc cả hai cùng bị rollback!
Làm thế nào để đẩy dữ liệu từ Outbox sang Kafka?#
Có 2 cách:
- Polling Publisher (Đơn giản): Dùng một worker chạy ngầm định kỳ query
SELECT ... FROM outbox_events WHERE processed_at IS NULL LIMIT 100rồi đẩy sang Kafka. - Change Data Capture (CDC - Đỉnh cao): Sử dụng công cụ Debezium đọc trực tiếp WAL (Write-Ahead Log) của PostgreSQL và tự động stream vào Kafka mà không cần chạm vào bảng.
Góc thảo luận#
Hệ thống microservices của bạn giải quyết bài toán giao dịch phân tán (Distributed Transaction) bằng cách nào? Bạn chuộng dùng Outbox Pattern hay Saga Pattern?
Xem thêm nội dung liên quan:
Thảo luận
1 phản hồi
Tham gia thảo luận
Bài liên quan trong #Backend & Microservices
-
Áp dụng Model Context Protocol (MCP) của Anthropic để kết nối AI với Postgres và Docker
Hoàng Nam (Tech Lead) · 💬 1 -
So sánh mô hình Embedding đa ngữ: OpenAI text-embedding-3 vs BGE-M3 vs Cohere
Minh Trí (AI Engineer) · 💬 1 -
Xây dựng Voice AI Agent thời gian thực với WebRTC và Whisper Live: Độ trễ dưới 500ms
Lan Anh (Senior Frontend) · 💬 1 -
Cấu hình Rate Limiting ở tầng Nginx và API Gateway: Chống DDOS Layer 7 hiệu quả
Đức Huy (DevOps Specialist) · 💬 1 -
Tokenization tiếng Việt của các LLM: Tại sao chi phí tiếng Việt đắt gấp 3 lần tiếng Anh?
Minh Trí (AI Engineer) · 💬 1