1. Background Jobs & Queues là gì?
Trong một ứng dụng backend, không phải công việc nào cũng cần hoàn thành ngay trong lúc xử lý HTTP request.
Ví dụ, khi người dùng đăng ký tài khoản, hệ thống có thể cần:
- Lưu thông tin người dùng vào database.
- Gửi email xác nhận.
- Gửi thông báo chào mừng.
- Ghi nhận sự kiện đăng ký.
- Đồng bộ dữ liệu sang một hệ thống khác.
Việc lưu tài khoản thường cần hoàn thành trước khi API trả về thành công. Tuy nhiên, việc gửi email hoặc đồng bộ dữ liệu có thể mất vài giây do phụ thuộc vào dịch vụ bên ngoài.
Nếu tất cả công việc đều chạy trực tiếp trong HTTP request, thời gian phản hồi sẽ tăng lên và request dễ thất bại khi một dịch vụ bên ngoài gặp sự cố.
Background Job là gì?
Background Job là một công việc được thực thi ở phía sau, độc lập với vòng đời của request ban đầu.
Một job thường đại diện cho một đơn vị công việc cụ thể, chẳng hạn:
SendWelcomeEmailGenerateInvoiceResizeUploadedImageExportOrdersToCSVSyncProductToExternalSystemProcessPaymentWebhook
Job nên có mục đích rõ ràng, dữ liệu đầu vào xác định và quy tắc xử lý lỗi phù hợp.
Queue là gì?
Queue là hàng đợi chứa các công việc đang chờ được xử lý.
Thay vì thực thi công việc ngay lập tức, ứng dụng đưa job vào queue. Worker sẽ lấy job ra và thực hiện sau đó.
Các thành phần chính gồm:
| Thành phần | Vai trò |
|---|---|
| Producer / Dispatcher | Tạo và gửi job vào queue |
| Queue / Broker | Lưu trữ, phân phối các job đang chờ |
| Worker / Consumer | Nhận và thực thi job |
| Handler | Logic thực tế của job |
| Retry mechanism | Lên lịch xử lý lại job thất bại |
| Dead Letter Queue (DLQ) | Lưu hoặc chuyển các message không thể xử lý thành công |
| Monitoring | Theo dõi số lượng job, độ trễ, lỗi và throughput |
2. Vì sao cần Background Jobs?
Giảm thời gian phản hồi API
Giả sử API đăng ký tài khoản mất:
- Ghi database: 50 ms.
- Gửi email: 1.500 ms.
- Gửi thông báo: 300 ms.
Nếu chạy tuần tự, tổng thời gian xử lý có thể gần 1.850 ms, chưa tính overhead khác.
Nếu chỉ cần tạo tài khoản thành công rồi đưa email và thông báo vào queue, API có thể trả về sau khi lưu dữ liệu và thực hiện các bước enqueue cần thiết.
Kết quả: request nhanh hơn và ít phụ thuộc vào tốc độ của dịch vụ gửi email.
Hấp thụ tải tăng đột biến
Giả sử hệ thống nhận 10.000 yêu cầu xuất báo cáo trong một khoảng thời gian ngắn, nhưng mỗi worker chỉ xử lý được 5 báo cáo mỗi giây.
Queue đóng vai trò như bộ đệm. Các yêu cầu được xếp hàng và worker xử lý dần thay vì bắt toàn bộ request phải chờ tác vụ nặng.
Tách biệt các thành phần
API server có thể tiếp nhận yêu cầu, còn worker chuyên xử lý email, ảnh hoặc báo cáo.
Nhờ đó, mỗi loại workload có thể được triển khai, giám sát và mở rộng độc lập.
3. Queue backend: Redis, RabbitMQ và Database Queue
Redis-backed queue
Redis thường được dùng khi hệ thống cần một backend queue có độ trễ thấp, vận hành tương đối đơn giản và hỗ trợ nhiều worker.
Ưu điểm:
- Độ trễ thấp.
- Phù hợp với nhiều ứng dụng web và workload nền.
- Có thể dùng chung hạ tầng với cache, nếu thiết kế tài nguyên cẩn thận.
- Nhiều thư viện cung cấp retry, scheduling và theo dõi job.
Nhược điểm:
- Phải hiểu rõ cách thư viện lưu job, phục hồi job và xử lý worker chết.
- Cấu hình persistence, replication và failover ảnh hưởng đến độ bền dữ liệu.
- Dùng chung Redis cho cache và queue có thể khiến hai workload cạnh tranh bộ nhớ và CPU.
Không nên tự mặc định rằng cứ dùng Redis là job sẽ không bao giờ mất. Cần xem xét thư viện queue và cấu hình triển khai cụ thể.
RabbitMQ
RabbitMQ là message broker phù hợp khi hệ thống cần routing message linh hoạt, acknowledgement, publisher confirms và các cơ chế phân phối message rõ ràng.
Ví dụ, một exchange có thể định tuyến message đến các queue khác nhau cho email, hóa đơn và webhook.
Một điểm quan trọng là publisher confirm và consumer acknowledgement giải quyết hai vấn đề khác nhau:
- Publisher confirm giúp producer biết broker đã tiếp nhận message theo cơ chế xác nhận.
- Consumer acknowledgement giúp broker biết consumer đã xử lý message đến mức có thể xác nhận.
Database Queue
Một số framework hỗ trợ dùng database quan hệ làm queue backend.
Ưu điểm:
- Không nhất thiết cần triển khai thêm broker.
- Dễ bắt đầu với ứng dụng nhỏ.
- Có thể dùng SQL để kiểm tra dữ liệu job khi cần.
Nhược điểm:
- Worker và ứng dụng cạnh tranh tài nguyên database.
- Queue có thể tạo nhiều thao tác ghi, cập nhật và xóa.
- Khi throughput tăng, việc polling và quản lý hàng đợi có thể trở thành điểm nghẽn.
4. Idempotency: Chống xử lý trùng
Đây là một trong những chủ đề quan trọng nhất khi thiết kế queue.
Trong môi trường phân tán, một job có thể được thực thi nhiều lần dù hệ thống đã cố gắng xác nhận thành công.
Ví dụ:
- Worker nhận job gửi email.
- Email được gửi thành công.
- Worker bị crash trước khi ghi nhận job hoàn thành.
- Job được đưa lại vào queue.
- Worker khác nhận job và gửi email lần nữa.
Vì vậy, không nên mặc định rằng mỗi job chỉ chạy đúng một lần.
Idempotency là gì?
Một thao tác có tính idempotent khi thực hiện lặp lại cùng một yêu cầu không làm thay đổi kết quả nghiệp vụ so với việc thực hiện một lần, trong phạm vi được định nghĩa.
Ví dụ, cập nhật trạng thái đơn hàng thành paid theo một quy trình có kiểm tra điều kiện có thể được thiết kế để chịu được lần gọi lặp lại.
Ngược lại, thao tác “cộng thêm 100.000 đồng vào số dư” không tự nhiên có tính idempotent: gọi hai lần sẽ cộng tiền hai lần.
Sử dụng idempotency key
Có thể gắn một khóa duy nhất với mỗi yêu cầu nghiệp vụ, ví dụ:
payment:order_123
Worker ghi nhận khóa đã xử lý trong database với ràng buộc unique. Khi một job lặp lại, hệ thống kiểm tra khóa và tránh thực hiện lại tác dụng phụ đã hoàn tất.
Tuy nhiên, thao tác kiểm tra khóa và cập nhật dữ liệu cần được thiết kế nguyên tử. Nếu chỉ kiểm tra rồi cập nhật trong hai bước riêng biệt, hai worker có thể cùng vượt qua bước kiểm tra.
5. tổng kết
Background Jobs & Queues không chỉ là đưa công việc vào một hàng đợi. Đây là một cơ chế kiến trúc để tách việc tiếp nhận yêu cầu khỏi quá trình xử lý, giúp ứng dụng phản hồi nhanh hơn và kiểm soát workload tốt hơn.








Khoá học lập trình game con rắn cho trẻ em




