Hẳn bạn đọc đã từng nghe khái niệm hàng đợi (queue), một cấu trúc dữ liệu thường gặp. Một ứng dụng phổ biến của hàng đợi là làm trung gian trong hệ thống microservice, giúp các thành phần trong hệ thống có thể giao tiếp bất đồng bộ, giảm phụ thuộc trực tiếp lẫn nhau, từ đó giúp cô lập lỗi cục bộ và tăng khả năng mở rộng. Trong AWS, dịch vụ hàng đợi được cung cấp là Simple Queue Service - SQS.
Trong bài này:
1. Tổng quan
Thành phần quan trọng nhất trong SQS tất nhiên là Hàng đợi (SQS Queue). Các hàng đợi được thiết kế phân tán, lưu trữ dữ liệu là các tin nhắn (message) trên nhiều máy chủ khác nhau, đảm bảo tính khả dụng và độ bền cao.
Trước đây mỗi tin nhắn trong SQS có giới hạn kích thước tối đa 256 KiB, nhưng từ 8/2025 đã được nâng lên 1 MiB. Các bộ dữ liệu lớn có thể được lưu trữ trong S3, và để đường dẫn trong tin nhắn.
1.1. Cách thức Hoạt động
Mỗi hàng đợi SQS có hai thành phần chính: bên gửi (producer) và bên nhận (consumer), theo mô hình Publish-Subscribe. Producer gửi tin nhắn đến hàng đợi, còn consumer lấy tin nhắn từ hàng đợi để xử lý. Qua đó, hai bên có thể giao tiếp bất đồng bộ, không cần biết về trạng thái của nhau, mà chỉ tương tác với hàng đợi. Việc này giúp hệ thống linh hoạt và chịu lỗi tốt hơn, một thành phần gặp sự cố sẽ không ảnh hưởng đến thành phần còn lại. Ngược lại, trong mô hình giao tiếp đồng bộ, producer và consumer phải tương tác trực tiếp, nên cả hệ thống sẽ lỗi nếu một trong hai gặp vấn đề.
Khi một consumer lấy tin nhắn từ hàng đợi để xử lý, tin nhắn đó vẫn sẽ tồn tại trong hàng đợi, nhưng tạm thời bị ẩn đi trong một khoảng thời gian gọi là visibility timeout. Điều này giúp tránh việc nhiều consumer xử lý cùng một tin nhắn, tiêu tốn tài nguyên và có thể gây lỗi khi có kết quả trùng lặp không mong muốn. Nếu consumer đó xử lý thành công, nó trực tiếp xóa tin nhắn khỏi hàng đợi. Ngược lại, nếu hết thời gian visibility timeout mà tin nhắn chưa bị xoá, SQS sẽ coi việc xử lý thất bại, và hiện lại tin nhắn để các consumer khác có thể lấy và xử lý tiếp. Cơ chế này đảm bảo tin nhắn được xử lý ít nhất một lần.
SQS tự động xoá các tin nhắn đã tồn tại trong hàng đợi quá lâu, dựa trên thiết lập message retention period, có thể từ 1 phút đến 14 ngày (mặc định 4 ngày), tránh việc hàng đợi bị đầy bởi các tin nhắn cũ không còn giá trị.
1.2. Kiến trúc Fanout với SNS và SQS
Như đã đề cập trong bài SNS, SQS thường được sử dụng trong kiến trúc Fanout, khi một tin nhắn nhắn tới một SNS Topic được chuyển tiếp đến nhiều dịch vụ khác nhau để xử lý song song (bất đồng bộ). SQS đóng vai trò là consumer của SNS Topic, nhận tin nhắn từ SNS và lưu trữ trong hàng đợi để xử lý sau.
Hình trên mô tả kiến trúc Fanout trong ví dụ đề cập trong bài SNS. Khi có đơn hàng mới, hệ thống gửi tin nhắn đến một SNS Topic, rồi SNS chuyển tiếp tin nhắn đến các hàng đợi SQS đăng ký topic, ứng với các tác vụ thanh toán, cập nhật kho hàng, gửi xác nhận, v.v., cùng lúc. Mỗi tác vụ có thể có một hoặc nhiều đơn vị tính toán riêng (Lambda Function, EC2 Instance, Auto Scaling Group, v.v.) để xử lý tin nhắn từ hàng đợi tương ứng.
Lý do cần dùng SNS Topic để phân phối tin nhắn đến nhiều hàng đợi SQS, thay vì gửi trực tiếp từ producer đến từng hàng đợi SQS, là do rất nhiều dịch vụ producer nguồn chỉ gửi một tin nhắn ứng với mỗi sự kiện (ví dụ, khi một tệp được tải lên S3, S3 chỉ gửi một thông báo duy nhất về sự kiện này), nên không thể gửi trực tiếp đến nhiều hàng đợi SQS cùng lúc. Cần sử dụng SNS Topic làm trung gian, SNS sẽ sao chép tin nhắn để gửi đến tất cả đối tượng đã đăng ký (subscribe) Topic đó (các hàng đợi SQS).
2. Các Loại Hàng đợi trong SQS
SQS hỗ trợ hai loại hàng đợi chính: hàng đợi tiêu chuẩn (Standard Queue) và hàng đợi FIFO (FIFO Queue), phục vụ các nhu cầu khác nhau về hiệu suất và thứ tự xử lý tin nhắn.
2.1. Hàng đợi Tiêu chuẩn
Đây là loại hàng đợi mặc định trong SQS, với cơ chế xử lý ít nhất một lần đã đề cập phía trên. Hàng đợi tiêu chuẩn có băng thông gần như không giới hạn, hỗ trợ tần suất gọi các API gửi, nhận và xoá tin nhắn rất rất cao, phù hợp cho các ứng dụng cần xử lý khối lượng lớn tin nhắn.
Hai hạn chế của hàng đợi tiêu chuẩn là tin nhắn bên trong có thể trùng lặp, có thể do độ trễ mạng, v.v. Do đó, ứng dụng sử dụng hàng đợi tiêu chuẩn cần tự xây dựng cơ chế xử lý trùng lặp. Ngoài ra, thứ tự xử lý tin nhắn trong hàng đợi tiêu chuẩn không được đảm bảo, nghĩa là tin nhắn gửi sau có thể được xử lý trước. Đây là những trường hợp hy hữu, do băng thông rất lớn. Nếu ứng dụng yêu cầu thứ tự xử lý nghiêm ngặt, cần sử dụng hàng đợi FIFO.
2.2. Hàng đợi FIFO
FIFO là viết tắt của “First-In-First-Out” (vào trước ra trước). Hàng đợi FIFO đảm bảo tin nhắn được xử lý chính xác một lần (exactly once) và đảm bảo đúng thứ tự. Mỗi tin nhắn chỉ được xử lý một lần duy nhất, theo đúng thứ tự. Tuy nhiên, hàng đợi FIFO có băng thông thấp hơn hàng đợi tiêu chuẩn, tối đa 300 lần gọi API mỗi giây, với mỗi API xử lý 10 tin nhắn.
2.3. Hàng đợi Trễ
Như tên gọi, hàng đợi trễ (Delay Queue) cho phép trì hoãn việc gửi tin nhắn đến consumer trong một khoảng thời gian xác định, từ 0 đến 15 phút. Khi tin nhắn được gửi đến hàng đợi trễ, nó sẽ không hiển thị cho các consumer trong khoảng thời gian đó.
Cần phân biệt cơ chế này với visibility timeout đã đề cập phía trên. Visibility timeout áp dụng khi một consumer đã lấy tin nhắn từ hàng đợi để xử lý, nhằm tránh việc nhiều consumer xử lý cùng một tin nhắn. Ngược lại, hàng đợi trễ ẩn tin nhắn ngay khi được gửi đến.
2.4. Hàng đợi Chết
Dead-Letter là những bức thư không thể gửi đến người nhận, thường do địa chỉ nhận sai. Trong AWS, Dead-Letter Queue (DLQ) là một hàng đợi đặc biệt, lưu trữ các tin nhắn không thể xử lý sau nhiều lần thử. Loại hàng đợi này hữu ích khi cần gỡ lỗi (debug) ứng dụng, DLQ cung cấp log chứa lý do tin nhắn được chuyển đến đó, và đương nhiên người dùng có thể phân tích nội dung từng tin nhắn để xác định nguyên nhân.
Tài liệu tham khảo
Trên đây là các kiến thức về SQS hay xuất hiện trong các bài thi chứng chỉ AWS. Tiếp theo, ta sẽ tiếp tục chuỗi bài serverless với API Gateway.