Trong nhiều thập kỷ, cron job đã là lựa chọn mặc định cho các tác vụ tự động hóa theo lịch trình trong các hệ thống backend: chạy mỗi giờ, mỗi ngày, mỗi 15 phút. Nhưng vào những năm gần đây, có một cách tốt hơn, nhanh hơn và đáng tin cậy hơn.
Change Data Capture (CDC) đang cách mạng hóa cách các hệ thống hiện đại phản ứng với các thay đổi dữ liệu thay thế các cron job dễ vỡ bằng các luồng công việc thời gian thực, điều khiển bằng sự kiện.
Đây là lý do tại sao cron đã “chết” và tại sao CDC là “kẻ hủy diệt”.
Cron Jobs: Một Di tích của Kỷ nguyên Polling
Cron đơn giản. Quá đơn giản.
Một cron job điển hình trong backend Spring Boot hoặc Go có thể trông như thế này:
@Scheduled(cron = "0 */5 * * * *") // mỗi 5 phút
public void syncOrders() {
List<Order> newOrders = orderRepository.findUnprocessed();
for (Order order : newOrders) {
process(order);
}
}
Hoặc trong Go:
ticker := time.NewTicker(5 * time.Minute)
for range ticker.C {
orders := db.FindUnprocessedOrders()
for _, o := range orders {
process(o)
}
}
Điều này hoạt động. Nhưng nó có những hạn chế nghiêm trọng:
- Độ trễ: Bạn phải chờ vài phút để phát hiện thay đổi.
- Dư thừa: Mỗi lần chạy đều quét toàn bộ tập dữ liệu.
- Vấn đề về đồng thời: Hai cron job có thể xung đột nếu một job bị chậm.
- Phí tổn vận hành (Ops overhead): Giám sát, thử lại, lên lịch lại đều làm tăng độ phức tạp.
Kết quả? Các hệ thống trên lý thuyết thì có tính phản ứng nhưng trong thực tế lại chậm chạp và tốn tài nguyên.
Change Data Capture (CDC) là gì?
CDC là một mô hình trong đó hệ thống của bạn lắng nghe các thay đổi cơ sở dữ liệu trong thời gian thực mà không cần polling. Thay vì hỏi “có gì thay đổi không?”, cơ sở dữ liệu sẽ cho bạn biết điều gì đã thay đổi.
Các công cụ phổ biến:
- Debezium (cho PostgreSQL, MySQL, MongoDB, v.v.)
- Kafka Connect (để truyền tải thay đổi vào Kafka)
- Litestream, Maxwell, AWS DMS, và các công cụ khác
Thay thế Cron bằng CDC
Cron: Polling và xử lý mỗi 5 phút
// Mỗi 5 phút
rows := db.Query("SELECT * FROM orders WHERE status = 'new'")
for _, row := range rows {
process(row)
}
CDC: Lắng nghe và phản ứng trong thời gian thực
func handleOrderEvent(e cdc.Event) {
if e.Table == "orders" && e.Change["status"] == "new" {
process(e.Change)
}
}
Thay vì quét tất cả các hàng sau mỗi khoảng thời gian, bạn đang phản ứng với chỉ những hàng đã thay đổi.
So sánh: Polling vs CDC
Chúng tôi đã thử nghiệm cả hai phương pháp trong một hệ thống giống môi trường production xử lý dữ liệu đơn hàng với 10.000 mục nhập mới/giờ.
Metric (Chỉ số) | Cron (Mỗi 5 phút) | CDC (Debezium + Kafka) |
---|---|---|
Avg. Latency (Độ trễ trung bình) | 150–300 giây | <1 giây |
DB Load (CPU %) (Tải DB (CPU %)) | 38% | 4% |
Event Duplication Rate (Tỷ lệ trùng lặp sự kiện) | ~5% (phủ/xung đột) | 0% |
Ops Overhead (Phí tổn vận hành) | Cao (timeout, race condition) | Thấp (có thể phát lại, dễ quan sát) |
CDC giảm độ trễ từ phút xuống mili giây và giảm mức sử dụng CPU trên DB gấp 8 lần.
Tại sao CDC chiến thắng
-
Phản hồi thời gian thực CDC phát ra các thay đổi trong vòng mili giây. Người dùng thấy kết quả nhanh hơn. Các workflow được kích hoạt ngay lập tức. Cron job không thể cạnh tranh được.
-
Giảm áp lực lên DB Các truy vấn polling thường liên quan đến việc quét toàn bộ bảng hoặc index được lọc. CDC đọc từ WAL (Write-Ahead Log), không phải từ chính bảng đó.
-
Xử lý Exactly-Once Với Kafka và metadata của CDC (LSN, timestamp), bạn có thể đạt được ngữ nghĩa idempotent (đảm bảo tác vụ chỉ thực hiện một lần) hoặc exactly-once. Cron job thường dẫn đến công việc bị trùng lặp hoặc bỏ sót do xung đột và thử lại.
-
Khả năng phát lại (Replayability) Bỏ lỡ một sự kiện do thời gian chết? Với CDC qua Kafka, chỉ cần “rewind” topic. Hãy thử làm điều đó với một cron job.
Khi nào Cron vẫn còn hữu ích
- Lịch trình tĩnh: “Chạy job này mỗi ngày vào 2 giờ sáng”
- Các script dọn dẹp một lần
- Các trigger không phải từ DB: API bên ngoài, tệp, hoặc xử lý theo lô (batch processing) mà log DB không khả thi.
Nhưng đối với dữ liệu bên trong cơ sở dữ liệu của bạn, CDC là lựa chọn mặc định mới.
Bắt đầu với CDC
- Thêm Debezium vào stack của bạn Sử dụng Kafka + Kafka Connect với Debezium connector cho DB của bạn.
- Tiêu thụ sự kiện (Consume Events) Truyền chúng vào các service của bạn bằng các Kafka client (Java, Go, v.v.)
- Lọc và xử lý
Chỉ xử lý những thay đổi quan trọng. Sử dụng
operation
,before/after
,table
và các metadata khác.
Ví dụ: Go Consumer (sử dụng segmentio/kafka-go
)
for {
msg, _ := r.ReadMessage(ctx)
var evt CDCEvent
json.Unmarshal(msg.Value, &evt)
if evt.Table == "orders" && evt.After.Status == "new" {
processOrder(evt.After)
}
}
Lời kết
Nếu bạn vẫn đang phụ thuộc vào cron job để điều khiển các luồng công việc, bạn đang xây dựng trên một nền tảng chậm chạp, dễ vỡ. Các hệ thống hiện đại là hướng sự kiện (event-driven), không phải hướng hẹn giờ (timer-driven).
Cron job thuộc về quá khứ. CDC là cách bạn bảo vệ backend của mình cho tương lai.