AWS Lambda function

Khi bạn gọi AWS Lambda function một cách đồng bộ, bạn mong đợi function này sẽ trả về response. Ví dụ: đây là trường hợp khi client gọi Lambda function thông qua Amazon API Gateway hoặc từ AWS Step Functions. Vì khách hàng đang chờ response, Lambda function nên trả về response càng sớm càng tốt.

Tuy nhiên, có thể có những trường hợp bạn phải thực hiện công việc bổ sung không ảnh hưởng đến phản response và Lambda function có thể thực hiện việc đó một cách không đồng bộ sau khi trả về response. Ví dụ: bạn có thể lưu trữ dữ liệu trong cơ sở dữ liệu hoặc gửi thông tin đến hệ thống lưu logs.

Sau khi bạn gửi response từ function , Lambda sẽ đóng băng runtime environment và function không thể chạy mã bổ sung. Ngay cả khi bạn tạo một luồng để chạy một tác vụ ở background, Lambda service sẽ đóng băng runtime environment sau khi handler return, khiến luồng đó bị treo cho đến lần gọi tiếp theo. Mặc dù bạn có thể trì hoãn việc return response cho client cho đến khi mọi công việc hoàn tất nhưng cách tiếp cận này có thể tác động tiêu cực đến trải nghiệm người dùng.

Bài blog này khám phá các cách chạy một tác vụ có thể bắt đầu trước khi function return nhưng vẫn tiếp tục chạy sau khi function return response cho client.

Gọi Lambda function bất đồng bộ

Option đầu tiên là chia code thành hai functions. Function đầu tiên chạy code đồng bộ; function thứ hai chạy code bất đồng bộ. Trước khi function đồng bộ trả về, nó sẽ gọi function thứ hai bất đồng bộ, trực tiếp bằng cách call API hoặc gián tiếp, chẳng hạn như bằng cách gửi message đến Amazon SQS để trigger function thứ hai.

Code Python này trình bày cách implement:

Sử dụng Lambda response streaming

Response streaming cho phép developers bắt đầu stream response ngay khi nó có byte đầu tiên của response mà không cần đợi toàn bộ response. Nó thường sử dụng tính năng response streaming khi phải giảm thiểu Time to First Byte (TTFB) hoặc khi nó gửi response lớn hơn 6 MB (size limit của Lambda response payload).

Khi sử dụng phương pháp này, function có thể gửi response bằng response streaming mechanism và có thể tiếp tục chạy code ngay cả sau khi gửi byte cuối cùng của response. Bằng cách này, client sẽ nhận được response và Lambda function có thể tiếp tục chạy.

Code Node.js này trình bày cách implement:

Sử dụng Lambda extensions

Lambda extension có thể tăng cường các Lambda function để tích hợp với các công cụ giám sát, khả năng quan sát, bảo mật và quản trị ưa thích của bạn. Bạn cũng có thể sử dụng extension để chạy code của riêng mình trong background để code tiếp tục chạy sau khi function của bạn trả về response cho client.

Có hai loại Lambda extensions: external extensions và internal extensions. Các external extensions chạy dưới dạng các tiến trình riêng biệt trong cùng một môi trường thực thi. Lambda function có thể giao tiếp với extension bằng cách sử dụng các file trong thư mục /tmp hoặc sử dụng mạng cục bộ, chẳng hạn như thông qua các HTTP request. Bạn phải đóng gói các external extensionsi dưới dạng Lambda layer.

Internal extensions chạy dưới dạng các luồng riêng biệt trong cùng một quy trình chạy handler. Handler có thể giao tiếp với các extensions bằng bất kỳ in-process mechanism, chẳng hạn như internal queues. Ví dụ này cho thấy internal extension, là một luồng chuyên dụng trong handler process.

Khi Lambda service gọi một function, nó cũng thông báo cho tất cả phần extension của lệnh gọi đó. Lambda service chỉ đóng băng execution environment khi Lambda function trả về response và tất cả các extension báo hiệu cho runtime rằng chúng đã hoàn tất. Với phương pháp này, function có extension chạy tác vụ độc lập với chính function đó và extension sẽ thông báo cho thời gian chạy Lambda khi nó xử lý xong tác vụ. Bằng cách này, execution environment vẫn hoạt động cho đến khi tác vụ được hoàn thành.

Ví dụ về code Python sau đây tách extension code thành file riêng của nó và handler sẽ import và sử dụng nó để chạy tác vụ nền:

Sử dụng custom runtime

Lambda hỗ trợ một số runtimes: Python, Node.js, Java, Dotnet và Ruby. Lambda cũng hỗ trợ custom runtimes, cho phép bạn phát triển các Lambda function bằng bất kỳ ngôn ngữ lập trình nào khác mà bạn cần.

Khi bạn gọi Lambda function sử dụng custom runtime, Lambda service sẽ gọi một quy trình có tên là ‘bootstrap’ chứa code tùy chỉnh của bạn. Code tùy chỉnh cần tương tác với Lambda Runtime API. Nó gọi /next endpoint để lấy thông tin về lệnh gọi tiếp theo. API call này đang bị chặn và nó đợi cho đến khi có yêu cầu. Khi function xử lý xong yêu cầu, nó phải gọi /response endpoint để gửi response trở lại client, sau đó nó phải gọi lại /next endpoint để chờ lệnh gọi tiếp theo. Lambda đóng băng execution environment sau khi bạn gọi /next, cho đến khi có yêu cầu.

Bằng cách sử dụng phương pháp này, bạn có thể chạy tác vụ bất đồng bộ sau khi gọi /response và gửi responsei lại cho client cũng như trước khi gọi /next, cho biết rằng quá trình xử lý đã hoàn tất.

Ví dụ về code Python sau đây tách custom runtime code thành file riêng và function sẽ import và sử dụng code đó để tương tác với runtime API:

Tổng kết

Blog này trình bày bốn cách kết hợp các tác vụ đồng bộ và bất đồng bộ trong Lambda function, cho phép bạn chạy các tác vụ tiếp tục chạy sau khi function trả về response cho client. Bảng sau đây tóm tắt ưu và nhược điểm của từng giải pháp:

Function URLs, không thể sử dụng với API Gateway, luôn công khai

Asynchronous invocationResponse streamingLambda extensionsCustom runtime
Độ phức tạpDễ dàng triển khaiDễ dàng triển khaiGiải pháp phức tạp nhất để triển khai vì nó yêu cầu tương tác với extensions API và dedicated threadTrung bình vì nó tương tác với runtime API
Triển khaiCần 2 artifact: function đồng bộ và bất đồng bộTriển khai artifact duy nhất chứa tất cả codeTriển khai artifact duy nhất chứa tất cả codeTriển khai artifact duy nhất, yêu cầu đóng gói tất cả các file runtime cần thiết
Chi phíĐắt nhất vì nó phát sinh thêm chi phí gọi cũng như thời lượng tổng thể của hai function cao hơn so với việc gộp lại thành mộtít tốn kém nhấtít tốn kém nhấtít tốn kém nhất
Bắt đầu tác vụ đồng bộTrước khi return từ handlerBất kì lúc nào suốt quá trình handlerBất kì lúc nào suốt quá trình handlerSau khi trả về response cho client, nếu không sử dụng dedicated thread
Giới hạnPayload được gửi đến function không đồng bộ không được vượt quá 256 KBChỉ được hỗ trợ với Node.js và custom runtimes. Yêu cầu Lambda Function URLs, không thể sử dụng với API Gateway, luôn ở chế độ công khai
Lợi íchTách rời tốt hơn giữa code đồng bộ và bất đồng bộKhả năng gửi response theo từng giai đoạn. Hỗ trợ payload lớn hơn 6 MB (có tính thêm phí)Tác vụ bất đồng bộ chạy trong luồng riêng của nó, điều này có thể giảm thời lượng và chi phí tổng thể
Thử lại trong trường hợp code bất đồng bộ bị lỗiQuản lí bởi Lambda serviceTrách nhiệm của developerTrách nhiệm của developerTrách nhiệm của developer

Việc lựa chọn phương pháp phù hợp tùy thuộc vào trường hợp sử dụng của bạn. Nếu bạn viết function của mình trong Node.js và gọi function đó bằng Lambda Function URLs, hãy sử dụng response streaming. Đây là cách dễ thực hiện nhất và tiết kiệm chi phí nhất.

Nếu có khả năng xảy ra lỗi trong tác vụ bất đồng bộ (ví dụ: không thể truy cập cơ sở dữ liệu) và bạn phải đảm bảo rằng tác vụ đó đã hoàn thành, hãy sử dụng phương thức asynchronous Lambda invocatio. Lambda service thử lại function bất đồng bộ của bạn cho đến khi thành công. Cuối cùng, nếu tất cả các lần thử lại đều không thành công, nó sẽ gọi Lambda destination để bạn có thể thực hiện hành động.

Nếu bạn cần custom runtime vì cần sử dụng ngôn ngữ lập trình mà Lambda không hỗ trợ, hãy sử dụng option custom runtime. Nếu không, hãy sử dụng option Lambda extensions. Nó phức tạp hơn nếu thực hiện, nhưng nó có hiệu quả về mặt chi phí. Điều này cho phép bạn đóng gói code trong một single artifact và bắt đầu xử lý tác vụ bất đồng bộ trước khi gửi response cho client.

Để biết thêm tài nguyên học tập về serverless, hãy truy cập Serverless Land.