Tạo một cơ chế retry tùy chỉnh serverless cho các queue consumer không lưu trạng thái

Bởi Kaizad Wadia ngày 11 tháng 2 năm 2025 trong Amazon EventBridge, Amazon Simple Queue Service (SQS), Architecture, AWS Lambda, Foundational (100), Serverless 

Các bộ xử lý queue serverless như AWS Lambda thường tồn tại trong các kiến trúc nơi chúng lấy messages từ các queue như Amazon Simple Queue Service (Amazon SQS) và tương tác với downstream services hoặc external APIs trong một kiến trúc phân tán. Các phương pháp retry mạnh mẽ là cần thiết để đảm bảo xử lý message đáng tin cậy do các downstream services này dễ bị gián đoạn ngắn hạn hoặc throttling. Điều này thường đòi hỏi phải triển khai logic retry đặc biệt với các tính năng như dead-letter queues (DLQs) và exponential backoff để xử lý các trường hợp này một cách nhẹ nhàng, đảm bảo các hệ thống downstream không bị quá tải bởi quá nhiều lần retry.

Trong bài viết này, chúng tôi đề xuất một giải pháp xử lý các retry serverless khi trạng thái của workflow không được quản lý bởi một service bổ sung.

Tổng quan giải pháp

Một số logic retry tùy chỉnh là cần thiết khi các Lambda functions tương tác với downstream services sau khi tiêu thụ messages từ SQS queues. Chiến lược này liên quan đến việc sử dụng EventBridge Scheduler và code trong Lambda. Khái niệm cốt lõi là triển khai một cơ chế retry mạnh mẽ để xử lý các lần xử lý message thất bại bằng cách sử dụng EventBridge scheduler. Khi một Lambda function gặp sự cố trong quá trình xử lý message, nó kích hoạt một lỗi cụ thể. Khi bắt được lỗi này trong khối catch, function tạo ra một EventBridge schedule. Kết quả là, message được gửi trở lại SQS queue và sẽ có sẵn để xử lý lại tại một thời điểm cụ thể trong tương lai.

Trong cách tiếp cận này, cơ chế retry có thể có mức độ kiểm soát chi tiết về thời gian retry có thể hỗ trợ các kỹ thuật khác nhau, bao gồm exponential backoff và linear retry intervals. Cách tiếp cận này tách biệt logic retry khỏi code để xử lý bản thân message, làm cho Lambda function hiệu quả hơn. Cùng với việc xử lý messages khi tất cả các lần retry đã hết, giải pháp này kết nối với DLQ để giữ các messages như vậy tách biệt khỏi queue chính.

Sơ đồ sau minh họa kiến trúc giải pháp.

Logic xử lý lỗi và lựa chọn retry trong code Lambda function tạo nên cơ sở cho việc triển khai cơ chế retry tùy chỉnh này. Nếu có lỗi trong quá trình xử lý message, function sẽ tạo ra một exception cụ thể. Việc tạo ra exception sau đó khởi động luồng retry. Một khối try-catch xử lý exception này và gọi một function tương tác với EventBridge Scheduler API để tạo một schedule tùy chỉnh. Để cấu hình schedule, chúng ta bao gồm SQS queue đích và timestamp dự định khi message sẽ được retry. Chúng ta có thể thay đổi độ trễ với một số sửa đổi code tùy thuộc vào một số tham số, như loại lỗi, số lần retry trước đó, hoặc các scheme backoff tùy chỉnh khác.

Như một phần của cách tiếp cận này, chúng ta sử dụng các thuộc tính message SQS để đảm bảo idempotency và theo dõi các lần retry. Trong mỗi lần retry, function thêm timestamp mới vào một mảng trong message body. Nếu function tiêu thụ message nhiều lần hơn giới hạn retry tối đa (được xác định bởi mảng các lần retry) nó sẽ gửi message đến DLQ mà không lên lịch lại.

Giải pháp cũng liên quan đến việc tích hợp một DLQ để không giữ messages trong queue xử lý chính và được retry mãi mãi. Lambda function sẽ đăng ký messages với DLQ trong trường hợp vượt quá giới hạn retry tối đa hoặc khi một số kịch bản lỗi nhất định yêu cầu dừng sớm. Queue này giữ tất cả các thông tin liên lạc đã thất bại cho đến khi chúng có thể được xem xét thủ công, xử lý lại, hoặc thậm chí sửa chữa.

Cân nhắc và best practices

Có một số yếu tố quan trọng cần ghi nhớ khi đưa hệ thống retry tùy chỉnh này vào thực tế. Một khía cạnh là xử lý các thất bại một phần, tức là xử lý khi chỉ một phần các bước được hoàn thành. Trong những trường hợp như vậy, chúng ta có thể sử dụng một số hình thức hành động bù trừ hoặc rollback để duy trì tính nhất quán trong dữ liệu và tránh sự khác biệt downstream của queue consumer.

Một yếu tố quan trọng khác là kiểm soát giới hạn retry. Mặc dù thiết kế hệ thống cho phép giới hạn retry thay đổi, chúng ta phải cân bằng việc sử dụng tài nguyên và khả năng phục hồi. Quá nhiều lần retry có thể gây ra chi phí cao hơn và dẫn đến chậm trễ hoặc suy giảm dịch vụ. Đó là lý do tại sao chúng tôi khuyến nghị thiết lập giới hạn retry phù hợp, xem xét tỷ lệ thất bại có thể xảy ra, SLA và hậu quả kinh doanh của các thất bại.

Chúng ta cũng phải xem xét rằng EventBridge Scheduler có độ chi tiết là 1 phút, và có độ trễ bổ sung giữa queue và function, vì vậy cơ chế sẽ không hoàn toàn chính xác. Về nguyên tắc, scheduler thiết lập thời gian tối thiểu trước khi message có thể được xử lý, đảm bảo Lambda function tuân thủ các giới hạn tốc độ ở mức tối thiểu. Điều này cũng có thể dẫn đến độ trễ bổ sung, vì vậy cơ chế cần được điều chỉnh cho các ứng dụng nhạy cảm về thời gian để tính đến các độ trễ này.

Bởi vì giải pháp có thể xử lý khối lượng messages và tải xử lý thay đổi, các vấn đề về quy mô cũng quan trọng. Ví dụ, concurrent của Lambda và thời gian lưu giữ cho queue đại diện cho các cấu hình tài nguyên mà chúng ta nên giám sát và điều chỉnh để có hiệu suất và chi phí tối ưu.

Cuối cùng, chúng ta cần xem xét bảo mật như một phần của giải pháp. Nếu downstream service chạy trong virtual private cloud (VPC), chúng ta cũng cần đặt Lambda function trong VPC. Trong trường hợp này, chúng ta cần truy cập EventBridge Scheduler thông qua AWS PrivateLink, cho phép truy cập an toàn và hiệu quả vào các dịch vụ từ bên trong VPC.

Ngoài ra, điều quan trọng là triển khai các vai trò AWS Identity and Access Management (IAM) (chủ yếu là vai trò Lambda function) với nguyên tắc đặc quyền tối thiểu, cho phép nó truy cập để tạo EventBridge schedule (và iam:PassRole để cấp cho scheduler các quyền cần thiết) cũng như chuyển vai trò IAM của scheduler cho nó. Vai trò của scheduler chỉ cần quyền đặt message vào source queue. Chúng ta cũng cần cấp cho function quyền đặt message trong DLQ và nhận messages từ source queue.

Giám sát và xử lý sự cố

Cơ chế retry tùy chỉnh đòi hỏi giám sát và gỡ lỗi hiệu quả. Với điều đó trong tâm trí, chúng ta có thể xem các hành vi khác nhau của hệ thống và xác định các vấn đề tiềm ẩn bằng cách sử dụng Amazon CloudWatch logs và metrics.

Số lần gọi (invocations) của Lambda functions, tỷ lệ lỗi liên quan, thời gian chạy và việc sử dụng DLQ là các chỉ số quan trọng mà chúng ta nên giám sát. Sẽ rất đáng giá để thiết lập các cảnh báo trong CloudWatch để gửi thông báo hoặc khởi động các hành động tự động khi các metrics của Lambda function vượt quá các ngưỡng đã định trước. Bằng cách này, chúng ta chủ động phát hiện và giải quyết các vấn đề nhất định liên quan đến function.

Ngoài ra, chúng ta có thể kiểm tra logs của Lambda function cho các tình huống lỗi nhất định, mẫu retry, hoặc vấn đề với downstream services hoặc với logic retry. Chúng ta có thể đặt các dòng logging một cách khôn ngoan trong code function để ghi lại thông tin liên quan, bao gồm thuộc tính message, số lần retry và chi tiết lỗi.

Cải tiến trong tương lai

Có một số cải tiến mà chúng ta có thể xem xét để nâng cao hơn nữa khả năng và tính linh hoạt của cách tiếp cận được đề xuất, cung cấp nền tảng để tùy chỉnh cơ chế retry.

Một cải tiến có thể là giới thiệu khoảng thời gian retry động tùy thuộc vào điều kiện của downstream service hoặc loại lỗi. Thay vì dựa trên các scheme backoff đã định nghĩa trước, hệ thống có thể động điều chỉnh khoảng thời gian retry dựa trên các loại lỗi cụ thể được phát hiện hoặc giám sát sức khỏe dịch vụ trong thời gian thực. Nhược điểm chính của khái niệm này là độ phức tạp bổ sung, có thể gây ra thất bại của chính quá trình retry.

Một cải tiến tiềm năng khác là tích hợp hệ thống với các dịch vụ cấu hình bên ngoài như Amazon DynamoDB hoặc Parameter Store, một khả năng của AWS Systems Manager. Bằng cách đó, chúng ta có thể xử lý các cấu hình retry một cách tập trung và động để dễ dàng bảo trì và sửa đổi trong chiến lược retry mà không cần phải triển khai lại code Lambda function.

Cũng có thể xây dựng phân tích lỗi và báo cáo nâng cao vào hệ thống. Hệ thống sau đó sẽ có tiềm năng cung cấp những hiểu biết quan trọng cho phân tích nguyên nhân gốc rễ và khắc phục chủ động thông qua báo cáo toàn diện, mẫu lỗi được phân tích và các thất bại được tương quan với sức khỏe downstream service.

Kết luận

Việc xây dựng các ứng dụng serverless có thể mở rộng, mạnh mẽ có thể cần giao tiếp với các dịch vụ bên ngoài thường là một thách thức. Tuy nhiên, giải pháp đề xuất sử dụng Lambda, Amazon SQS và EventBridge Scheduler mang lại một giải pháp đơn giản nhưng hiệu quả để triển khai các cơ chế retry tùy chỉnh. Nó cho phép developer kiểm soát chi tiết về khoảng thời gian retry, hỗ trợ các kịch bản như exponential backoff và hoạt động liền mạch với DLQs để lưu trữ các thất bại và EventBridge Scheduler để retry messages bị trì hoãn. Cơ chế này cũng có thể được tái sử dụng rộng rãi hơn cho các queue consumers không trạng thái, không chỉ cho Lambda functions. Mẫu này cho phép developers triển khai các hệ thống serverless mạnh mẽ, chịu lỗi, có khả năng xử lý gián đoạn trong downstream services một cách nhẹ nhàng.

Về Tác giả 

Kaizad Wadia

Kaizad Wadia là Solutions Architect tại Amazon Web Services, giúp khách hàng triển khai các ứng dụng mạnh mẽ và tối đa hóa tiềm năng dữ liệu của họ trên AWS, thúc đẩy đổi mới và tăng trưởng kinh doanh thông qua các giải pháp cloud được điều chỉnh phù hợp.

Leave a comment