# Xử lý bất đồng bộ và Message Queue trong ứng dụng AI

> Giải pháp xử lý bất đồng bộ và Message Queue giúp tối ưu hạ tầng, chống nghẽn hệ thống và tăng khả năng mở rộng cho tác vụ AI.

Nguồn: https://camnangai.com/ky-thuat/xu-ly-bat-dong-bo-va-message-queue-trong-ai  
Xuất bản: 2026-11-01

Khi tích hợp các mô hình AI như suy luận LLM hay xử lý hình ảnh và audio, thời gian tính toán thường kéo dài từ vài giây đến nhiều phút. Nếu bạn duy trì kết nối HTTP đồng bộ truyền thống, tiến trình xử lý trên server sẽ bị bế tắc, làm kiệt quệ tài nguyên và khiến trải nghiệm người dùng sụp đổ. **Kiến trúc xử lý bất đồng bộ kết hợp Message Queue** ra đời để giải quyết triệt để nghẽn cổ chai này bằng cách tách rời khâu tiếp nhận yêu cầu khỏi khâu thực thi thực tế.

Bằng cách đưa tác vụ AI vào hàng đợi đệm (buffer queue), hệ thống có thể phản hồi cho client ngay lập tức và tiếp nhận các yêu cầu mới mà không bị quá tải. Kỹ thuật này giúp phân phẳng tải (Queue-Based Load Leveling), bảo vệ hạ tầng backend khỏi hiện tượng sụp đổ dây chuyền khi lượng truy cập tăng đột biến.

![Minh hoạ kiến trúc xử lý bất đồng bộ: yêu cầu từ người dùng được đưa vào hàng đợi đệm và xử lý ngầm thay vì chặn kết nối HTTP](https://camnangai.com/articles/xu-ly-bat-dong-bo-va-message-queue-trong-ai/01-infographic-vn.webp)

## Nghẽn cổ chai của mô hình đồng bộ trong tác vụ AI

Các API REST truyền thống thường được thiết kế để phản hồi trong khoảng 100 ms hoặc ít hơn đối với các thao tác I/O nhẹ. Tuy nhiên, khối lượng công việc tính toán AI (AI workloads) thuộc nhóm nặng (heavy CPU/GPU-bound), đòi hỏi khoảng thời gian xử lý kéo dài từ vài giây đến nhiều phút. Độ trễ phản hồi bị tác động bởi nhiều yếu tố: tải hiện tại của ứng dụng, dung lượng dữ liệu truyền tải (payload), độ dài hàng đợi xử lý tại backend và thời gian thực thi suy luận của mô hình.

Khi áp dụng mô hình đồng bộ (Synchronous Request-Reply) cho tác vụ AI, client buộc phải giữ kết nối mở để chờ kết quả. Khi hệ thống chịu tải cao hoặc xuất hiện các đợt truy cập tăng đột biến, thời gian xử lý kéo dài khiến các kết nối HTTP bị timeout.

Tình trạng này dễ kích hoạt hiện tượng xoáy bế tắc ("Spirals of doom"): khi phản hồi bị chậm hoặc timeout, client bắt đầu phát lại yêu cầu (retry). Nếu không có cơ chế điều tiết, các yêu cầu lặp lại này sẽ phát ra theo các chu kỳ đồng bộ hóa (thundering herd problem), tạo thành bão yêu cầu (retry storm) nhân bản lượng công việc lên hệ thống vốn đang quá tải. Hàng chờ xử lý bị tắc nghẽn nghiêm trọng, làm gia tăng xung đột tài nguyên và cuối cùng dẫn đến sụp đổ dây chuyền (cascading failure) toàn bộ hệ thống.

## Kiến trúc Asynchronous Request-Reply và mã HTTP 202

![Sơ đồ vòng đời Asynchronous Request-Reply với mã HTTP 202 Accepted, truy vấn trạng thái và chuyển hướng HTTP 303](https://camnangai.com/articles/xu-ly-bat-dong-bo-va-message-queue-trong-ai/02-vn.webp)

Để giải quyết triệt để bế tắc của mô hình đồng bộ, kiến trúc Asynchronous Request-Reply tách rời khâu tiếp nhận yêu cầu và khâu trả kết quả. Luồng vận hành chuẩn diễn ra như sau:

1. Client gửi yêu cầu HTTP POST chứa dữ liệu đầu vào cho mô hình AI.
2. API thực hiện kiểm tra tính hợp lệ (validation) của request. Nếu dữ liệu không hợp lệ, API trả về ngay lỗi `HTTP 400 (Bad Request)` theo định dạng cấu trúc chuẩn **RFC 9457 (Problem Details for HTTP APIs)**. Nếu hợp lệ, API đẩy công việc vào Message Queue và trả về ngay phản hồi `HTTP 202 (Accepted)`.
3. Phản hồi `HTTP 202` đi kèm hai header quan trọng: `Location` (URL chỉ tới endpoint để client truy vấn trạng thái, ví dụ `/api/status/{requestId}`) và `Retry-After` (khoảng thời gian gợi ý tính bằng giây để client chờ trước khi thực hiện lần truy vấn tiếp theo, giúp giảm tải polling). Ngoài ra, response có thể đi kèm header `Expires` hoặc chính sách lưu trữ (retention policy) định sẵn để thông báo cho client thời điểm tài nguyên kết quả sẽ bị xóa bỏ nhằm giải phóng bộ nhớ.
4. Client thực hiện gửi yêu cầu HTTP GET định kỳ tới URL trong header `Location`. Khi công việc đang chạy, status endpoint trả về `HTTP 200 (OK)` kèm thông tin trạng thái (`Pending` hoặc `Running`). Khi tác vụ hoàn thành, endpoint sẽ trả về `HTTP 303 (See Other)` để chuyển hướng client tới URL chứa kết quả cuối cùng. Trường hợp tác vụ bị lỗi trong quá trình xử lý, status endpoint sẽ trả về mã lỗi 4xx/5xx đi kèm đối tượng lỗi dạng cấu trúc theo chuẩn RFC 9457.
5. Để phòng ngừa sự cố mạng khiến client phát lại yêu cầu POST ban đầu, request cần đi kèm header `Idempotency-Key`. Nếu backend nhận được một idempotency key trùng lặp, nó sẽ trả về ngay resource trạng thái hiện có chứ không khởi tạo lại job mới vào hàng đợi.

Cấu hình HTTP response chuẩn cho mã 202 Accepted:

```http
HTTP/1.1 202 Accepted
Location: https://api.example.com/status/req-12345
Retry-After: 5
Content-Type: application/json

{
  "status": "Pending",
  "requestId": "req-12345"
}
```

## Thành phần cốt lõi: Producer, Message Queue và Worker Pool

![Mô hình 3 tầng gồm Producer, Message Broker điều tiết tải và Worker Pool thực thi suy luận AI](https://camnangai.com/articles/xu-ly-bat-dong-bo-va-message-queue-trong-ai/03-vn.webp)

Mô hình hàng đợi xử lý tác vụ AI được cấu thành từ 3 lớp cơ bản, đảm bảo tính phân tách trách nhiệm và khả năng mở rộng độc lập:

- **Producer (Bên phát hành):** Là ứng dụng web hoặc API server tiếp nhận request từ người dùng. Producer đóng gói dữ liệu công việc (payload), gán ID duy nhất và đưa tin nhắn vào Queue, sau đó trả phản hồi cho client mà không cần chờ tác vụ hoàn thành.
- **Message Queue / Broker (Hàng chờ tin nhắn):** Bộ đệm trung gian lưu trữ công việc tạm thời. Broker thực hiện cơ chế phân phẳng tải (Queue-Based Load Leveling), giúp tốc độ tiếp nhận yêu cầu không bị phụ thuộc vào tốc độ xử lý của backend. Giao tiếp qua hàng đợi tuân theo nguyên tắc point-to-point (one-to-one): mỗi job chỉ được tiếp nhận và xử lý bởi đúng 1 consumer. Về cơ chế lưu trữ:
  - Khi sử dụng **Redis backend**, các script Lua được thực thi để đảm bảo mọi thao tác chuyển trạng thái job (`wait`, `active`, `completed`, `failed`) diễn ra nguyên tử (atomic). Workers sẽ block trên một marker key để nhận thông báo tức thì khi có job mới mà không cần polling.
  - Khi sử dụng **PostgreSQL backend** (như trong BullMQ), các job được lưu trong các bảng thông thường và thao tác trạng thái quản lý bằng hàm SQL trong transaction. Workers duy trì kết nối `LISTEN` và được awaken chủ động qua cơ chế `NOTIFY` từ producer.
  - Khi sử dụng **RabbitMQ**, tính năng Quorum Queues bảo toàn dữ liệu trên đĩa cứng. Tuy nhiên, lưu ý rằng việc đánh dấu tin nhắn persistent không đồng nghĩa với việc gọi `fsync(2)` trên từng lệnh ghi, do đó dữ liệu vẫn có thể nằm trong cache đĩa. Để đạt được bảo đảm phân phối tuyệt đối, hệ thống cần kết hợp Quorum Queues với cơ chế **Publisher Confirms**.
- **Worker Pool (Tập hợp tiến trình xử lý):** Các tiến trình chạy ngầm riêng biệt (như Celery workers hay BullMQ workers). Chúng kết nối tới Broker, liên tục lấy job ra khỏi queue, thực thi tính toán suy luận AI/ML nặng và ghi kết quả vào bộ nhớ lưu trữ (Storage/Database).

Minh họa cấu hình tác vụ Celery tối giản bằng Python:

```python
from celery import Celery

app = Celery('ai_tasks', broker='pyamqp://guest@localhost//', backend='redis://localhost:6379/0')

@app.task
def run_ai_inference(prompt_data):
    # Giả lập thực thi mô hình AI nặng
    return {"result": "generated_text"}
```

## Nhận kết quả xử lý: Polling, Webhook và Server-Sent Events

Sau khi tác vụ AI được tiếp nhận bất đồng bộ, có 3 cơ chế chính để truyền kết quả từ backend về cho client:

- **Polling (Periodic Polling & Long Polling):** Với Periodic Polling, client chủ động gửi yêu cầu GET định kỳ đến endpoint trạng thái. Phương pháp này dễ triển khai trên trình duyệt nhưng gây lãng phí băng thông nếu tần suất quá dày. Biến thể Long Polling giữ kết nối mở tại server cho đến khi có dữ liệu hoặc hết thời gian timeout; cách này giảm độ trễ phản hồi nhưng làm tăng phức tạp trong quản lý kết nối và timeout.
- **Webhook (Callback):** Server sẽ chủ động thực hiện một HTTP POST request đẩy dữ liệu kết quả đến URL do client cung cấp ngay khi tác vụ hoàn thành. Webhook rất phù hợp cho mô hình giao tiếp giữa server với server (Server-to-Server API). Tuy nhiên, phương pháp này không thể áp dụng nếu client nằm sau NAT/Firewall hoặc là ứng dụng chạy trực tiếp trên trình duyệt web.
- **Server-Sent Events (SSE):** Dòng đẩy dữ liệu một chiều (unidirectional push) từ Server về Client dựa trên giao thức HTTP chuẩn. SSE là lựa chọn tối ưu cho các tác vụ AI cần phản hồi theo dạng dòng (như streaming từng token văn bản từ mô hình LLM hoặc cập nhật phần trăm tiến độ xử lý ảnh) mà không đòi hỏi hạ tầng phức tạp như WebSocket.

## Quản trị rủi ro: Rate limit, Retry lũy thừa và Dead-Letter Queue

![Cơ chế xử lý lỗi bền bỉ: giới hạn tốc độ, retry lũy thừa kèm jitter và cách ly lỗi bằng Dead-Letter Queue](https://camnangai.com/articles/xu-ly-bat-dong-bo-va-message-queue-trong-ai/04-vn.webp)

Xây dựng hàng đợi cho tác vụ AI đòi hỏi các cơ chế quản trị rủi ro chặt chẽ để bảo đảm tính bền vững (resilience) của hạ tầng:

- **Xác nhận tin nhắn (Message Acknowledgment & Durability):** Để tránh mất dữ liệu khi tiến trình worker bị sụp đột ngột, worker chỉ gửi tín hiệu xác nhận (`basic_ack`) về cho Broker sau khi đã hoàn thành toàn bộ tác vụ. Nếu worker ngắt kết nối giữa chừng, Broker sẽ đưa job trở lại hàng đợi để phân phối cho worker khác. Ngoài ra, hàng đợi và tin nhắn phải được cấu hình ở chế độ lưu trữ bền vững (`durable` / `persistent`), kết hợp cùng Publisher Confirms để loại bỏ rủi ro mất dữ liệu trên RAM đệm.
- **Phân phối công bằng & Khống chế tốc độ (Fair Dispatch & Rate Limit):** Cần thiết lập `prefetch_count=1` trên các worker. Cấu hình này buộc Broker không phân phối job mới cho worker cho đến khi worker đó xử lý xong và gửi `ack` cho job hiện tại, tránh tình trạng dồn việc vào một worker đang bị nghẽn. Đồng thời, áp dụng giới hạn tốc độ (ví dụ `rate_limit='10/m'`) để tránh việc các worker xả lượng request quá lớn làm sập API của mô hình AI phía downstream.
- **Retry lũy thừa (Exponential Backoff with Jitter) & Dead-Letter Queue (DLQ):** Khi gặp các lỗi tạm thời (transient errors), hệ thống cần tự động retry. Nếu áp dụng thuật toán lũy thừa thuần túy, các tiến trình retry vẫn có nguy cơ chạm mốc thời gian trùng nhau, tiếp tục gây ra bão yêu cầu (thundering herd). Việc bổ sung yếu tố nhiễu ngẫu nhiên (jitter) giúp làm phân tán các khoảng thời gian phát lại request, triệt tiêu sóng xung đột lên backend. Đối với các tin nhắn độc ("poison messages" - job chứa dữ liệu đầu vào hỏng hoặc lỗi vĩnh viễn), sau khi vượt quá số lần retry tối đa, job phải được đẩy sang Dead-Letter Queue (DLQ) để kỹ sư truy vết mà không làm tắc nghẽn hàng đợi chính.

## Khi nào dùng in-process background task, khi nào cần Message Queue?

- **Nên dùng In-process Background Task (như `BackgroundTasks` từ `fastapi`):** Khi tác vụ có thời gian thực thi ngắn, cực kỳ nhẹ, không tiêu tốn tài nguyên CPU/GPU (ví dụ: ghi log đơn giản, gửi email thông báo sau khi phản hồi HTTP). Điều kiện đi kèm là hệ thống chấp nhận rủi ro mất dữ liệu tác vụ nếu process ứng dụng bị crash hoặc restart.
- **Bắt buộc dùng Message Queue chuyên dụng (Celery, BullMQ kết hợp Redis/RabbitMQ/PostgreSQL):** Khi tác vụ là tính toán suy luận AI nặng, chiếm dụng nhiều CPU/RAM/GPU, yêu cầu khả năng phân tán trên nhiều node (multi-node worker pool), cần lưu trữ tác vụ bền vững (persistence), kiểm soát tần suất truy cập (rate limiting) và yêu cầu các cơ chế xử lý lỗi nâng cao như Dead-Letter Queue.

## Tài liệu tham khảo

- [Asynchronous Request-Reply pattern — Azure Architecture Center | Microsoft Learn](https://learn.microsoft.com/en-us/azure/architecture/patterns/async-request-reply)
- [Queue-Based Load Leveling pattern — Azure Architecture Center | Microsoft Learn](https://learn.microsoft.com/en-us/azure/architecture/patterns/queue-based-load-leveling)
- [What is a Message Queue? — AWS](https://aws.amazon.com/message-queue/)
- [Reliability, constant work, and a good cup of coffee — AWS Builders' Library](https://aws.amazon.com/builders-library/reliability-and-constant-work/)
- [First Steps with Celery — Celery Documentation](https://docs.celeryq.dev/en/stable/getting-started/first-steps-with-celery.html)
- [Architecture & Overview — BullMQ Guide](https://docs.bullmq.io/guide/architecture)
- [Work Queues in Python — RabbitMQ Tutorials](https://www.rabbitmq.com/tutorials/tutorial-two-python)
- [Background Tasks — FastAPI Documentation](https://fastapi.tiangolo.com/tutorial/background-tasks/)
