Computer >> Hướng Dẫn Máy Tính >  >> Lập Trình >> Ruby

Thành thạo Ruby trên AWS Lambda: Xây dựng Hàm Hướng sự kiện, Có thể mở rộng

AWS Lambda cho phép thiết lập các hàm có thể mở rộng trong khi giảm thiểu overhead. Thay vì viết, host và duy trì toàn bộ ứng dụng Ruby on Rails, chúng ta có thể dùng Lambda functions để phản hồi các sự kiện riêng lẻ một cách độc lập. Bài viết này sẽ đưa bạn từ người mới AWS đến việc viết Ruby trong các Lambda function của riêng bạn.

Lambda cho phép chạy code phản hồi sự kiện mà không quản lý server. Kiến trúc hướng sự kiện này đảm bảo bạn chỉ trả tiền cho code khi nó đang làm việc cho bạn, không phải khi nó nhàn rỗi. Mặc dù Lambda thường dùng để phản hồi sự kiện trong hệ sinh thái AWS, như xóa file trong S3 Bucket, nó cũng có thể cấu hình hoạt động như API kết hợp với AWS API Gateway.

Có thể dùng Lambda để tự động hóa tác vụ dựa trên thời gian, như Cron Jobs, hoặc phản hồi sự kiện. Điều này có thể mở rộng vào xử lý dữ liệu, thường với các dịch vụ AWS khác như DynamoDB, thậm chí thành API có thể mở rộng. Ví dụ, sơ đồ sau từ tài liệu Amazon cho thấy kiến trúc đơn giản: client mobile thực hiện HTTP request, giả định để thực hiện hành động CRUD trên database. API Gateway định tuyến request đến Lambda function tương ứng (giống như Rails định tuyến HTTP request đến controller), và nó thực hiện logic nghiệp vụ và giao tiếp với AWS DynamoDB để đáp ứng request.

Thành thạo Ruby trên AWS Lambda: Xây dựng Hàm Hướng sự kiện, Có thể mở rộng

Vì code chạy trong container, hạ tầng Amazon tự động đưa function vào chế độ ngủ khi không dùng. Khi request mới đến, container phải khởi động từ trạng thái lạnh, làm tăng thời gian thực thi lên tới 2000ms. Điều này không chỉ làm giảm chất lượng dịch vụ về mặt thời gian phản hồi mà còn tốn tiền. Vì vậy, dùng Lambda cho tác vụ nhạy cảm về thời gian, như gửi email người dùng hoặc phản hồi sự kiện UI, có thể tạo bottleneck. Bạn có thể giảm thiểu bằng cách lên lịch AWS CloudWatch gửi request định kỳ để giữ function "nóng", nhưng sẽ tăng chi phí hosting.

Tại sao dùng AWS Lambda

Amazon Web Services (AWS) là dịch vụ cloud computing phổ biến nhất thế giới. Nó đủ đơn giản cho lập trình viên độc lập dùng nhưng đủ mạnh và mở rộng để làm hạ tầng cho các công ty lớn nhất thế giới.

AWS Lambda là một sản phẩm của Amazon đóng vai trò "serverless compute service", cho phép chạy code chỉ phản hồi sự kiện. Điều này giảm overhead và cho phép phản hồi lập trình sự kiện, như API call, mà không cần host toàn bộ server hoặc xây dựng toàn bộ app.

Với trường hợp dùng phù hợp, kiến trúc serverless này có thể tiết kiệm đáng kể chi phí. Định giá tính theo chi phí mỗi request và chi phí mỗi thời gian tính toán. Sau một triệu request đầu tiên trong tháng, giá là $0.20 cho mỗi triệu request cộng $0.0000166667 cho mỗi GB-giây thời gian tính toán function dùng. Như bạn thấy, định giá dựa trên tỷ lệ này làm cho việc chạy dịch vụ nhỏ trên Lambda trở nên đáng kinh ngạc rẻ mà vẫn giữ tùy chọn mở rộng vô hạn cùng tỷ lệ.

Lập trình viên Ruby có thể tận dụng dịch vụ cloud này bằng cách dùng nó như cách không trạng thái để phản hồi API call hoặc thậm chí các sự kiện AWS khác.

Thiết lập tài khoản AWS dùng thử

AWS cung cấp free tier khá hào phóng: một triệu request miễn phí và lên tới 3.2 triệu giây tính toán mỗi tháng với AWS Lambda! Nếu đã có tài khoản, bạn có thể bỏ qua bước này, nhưng thiết lập rất đơn giản.

Truy cập đăng ký tại đây và điền thông tin để bắt đầu! Thành thạo Ruby trên AWS Lambda: Xây dựng Hàm Hướng sự kiện, Có thể mở rộng

Bạn sẽ được nhắc điền thêm thông tin, bao gồm loại tài khoản và thông tin liên lạc, và cần nhập thông tin thẻ tín dụng/ghi nợ để chi trả usage ngoài free tier. Việc dùng Lambda đơn giản của chúng ta nằm trong free tier, nhưng nếu lo lắng về vượt ngân sách ngẫu nhiên, bạn có thể thiết lập budget để kiểm soát usage và ngăn chặn billing bất ngờ.

Tạo Lambda Function với Ruby

Sau khi đăng ký, di chuột qua products, rồi compute, chọn Lambda.

Thành thạo Ruby trên AWS Lambda: Xây dựng Hàm Hướng sự kiện, Có thể mở rộng

Khi vào Lambda Console (có thể phải bấm "get started"), bạn sẽ thấy danh sách function trống với nút cam "Create Function". Như bạn đoán, chúng ta sẽ bấm nút đó.

Thành thạo Ruby trên AWS Lambda: Xây dựng Hàm Hướng sự kiện, Có thể mở rộng

Sau đó, chọn "Author from Scratch", vì chưa có template function cho Ruby, và làm từ đầu là cách tốt nhất để học.

Đặt tên function phù hợp và chọn phiên bản Ruby bạn muốn dùng. Tôi đặt tên là FizzBuzz, theo bài toán lập trình nổi tiếng.

Có thể phải double-click vào file lambda_function.rb ở navigation pane để hiện source code.

Function được viết sẵn với tên lambda_handler. Như hiện tại, khi được invoke, function trả về response 200 với text "Hello From Lambda!", như hình dưới. Thành thạo Ruby trên AWS Lambda: Xây dựng Hàm Hướng sự kiện, Có thể mở rộng

Sử dụng Test Trigger cho Lambda Function

Như thảo luận ở phần mở đầu, Lambda function có thể được trigger nhiều cách. Phổ biến nhất là qua API call. Tuy nhiên, điều này yêu cầu thiết lập AWS API Gateway, hơi ngoài phạm vi bài viết. API Gateway hoạt động tuyệt vời với Lambda để tạo API với cấu hình rất ít và mở rộng vô hạn.

May mắn là không quá khó để mô phỏng API call qua function console, và một test event đã sẵn sàng cho chúng ta.

Dưới function overview là toolbar hiện tại chọn "Code". Như ảnh trước, ngay bên cạnh "Code" là tab "Test". Chọn "Test", bạn sẽ thấy Test console hiện ra thay vì source code.

Thành thạo Ruby trên AWS Lambda: Xây dựng Hàm Hướng sự kiện, Có thể mở rộng

Test event được cấu hình sẵn là object JSON được gửi đến Lambda function như object event, mà function nhận làm tham số. Nếu bạn gọi endpoint qua API Gateway, đây sẽ là body của request.

Vì placeholder Lambda function không đọc event, nên không quan trọng chúng ta gửi gì làm body. Vì vậy, ta có thể tiến hành như viết bằng cách bấm nút cam "Invoke".

Nếu bạn thiết lập function đúng, bạn sẽ thấy hộp xanh "Execution Succeeded", có thể mở rộng để xem JSON response từ function.

Viết FizzBuzz

Sau khi xác nhận Lambda function hoạt động đúng, chúng ta có thể tùy chỉnh với code Ruby riêng. Trong ví dụ này, Lambda function sẽ phản hồi bài toán FizzBuzz nổi tiếng. FizzBuzz là yêu thích phỏng vấn, đề bài đại loại:

Viết chương trình in số từ 1 đến 50. Nhưng, cho bội của ba, in "Fizz" thay số, cho bội của năm, in "Buzz". Cho số là bội của cả ba và năm in "FizzBuzz".

Thay code trong Lambda function bằng giải pháp FizzBuzz của tôi -

require 'json'
def lambda_handler(event:, context:)
  max_val = event['max_val']
  textResponse = ''
  1.upto(max_val) do |i|
    if i % 5 == 0 and i % 3 == 0
      textResponse += "FizzBuzz"
    elsif i % 5 == 0
      textResponse += "Buzz"
    elsif i % 3 == 0
      textResponse += "Fizz"
    else
      textResponse += i.to_s
    end
  end
  { statusCode: 200, body: JSON.generate(textResponse) }
end

Đây là biến thể nhỏ của FizzBuzz thông thường. Thay vì chỉ loop đến 50, chúng ta loop đến số được gửi kèm event. Object event truyền vào như dictionary, nên hỏi event[max_val] trả về giá trị tại key max_val. Cuối cùng, thay vì in ra giải pháp FizzBuzz, chúng ta chỉ nối vào String và trả về như object JSON.

Tiếp theo, nhớ bấm nút cam "Deploy" để cập nhật Lambda function với code mới.

Sau khi viết xong và deploy, quay lại Test console. Thay đổi test event để chỉ truyền cặp key/value max_val. Nó nên trông như sau:

Thành thạo Ruby trên AWS Lambda: Xây dựng Hàm Hướng sự kiện, Có thể mở rộng

JSON đơn giản là

{ "max_val": 70 }

Cuối cùng, bấm "Invoke" để chạy test! Bạn có thể mở rộng kết quả để thấy function đọc input và trả về kết quả bài toán FizzBuzz.

Phát triển dễ dàng hơn

Mặc dù làm việc trên web console tiện cho học tập, bị giới hạn ở đó sẽ là ác mộng. Một cách phổ biến nhất để phát triển với AWS Lambda là dùng CLI (Command Line Interface).

Sau khi tạo quyền phù hợp qua IAM roles, cài CLI trên máy và cấu hình với credentials. Sau đó, bạn có thể dùng Lambda CLI để test function khi phát triển local (trong IDE ưa thích) và deploy thay đổi qua command line.

Cách phát triển phổ biến khác là qua framework, như Serverless. Serverless xử lý phần lớn cấu hình phiền toái mà AWS gặp phải, bao gồm thiết lập API Gateway nếu bạn cần cho function. Serverless cũng cải thiện logging, quản lý Ruby Gem dễ dàng hơn, và cho phép cấu hình CI/CD, để tự động deploy từ repository dựa trên pipeline.

Không dùng Serverless hay framework tương tự, việc include Ruby Gem yêu cầu nhảy qua nhiều vòng. Bạn phải mở rộng function thành folder, rồi tạo file .bundle/config ở root directory với code khởi tạo sau để bảo bundler đặt gem cài ở đâu:

---
BUNDLE_PATH: "vendor/bundle"

Sau đó, dùng CLI để bundle add gem cần thiết và require trực tiếp trong code.

Hạn chế của AWS Lambda

Chúc mừng, bạn vừa viết AWS Lambda function đầu tiên bằng Ruby! Trước đây, giải pháp khả thi duy nhất để chạy API với Ruby thường là tạo toàn bộ Rails app. Bây giờ, bạn có thể tạo endpoint từng cái, bỏ qua tất cả phồng to đi kèm full application. Lambda tính phí usage theo microsecond, nên rất rẻ cho giải pháp nhanh. Hơn nữa, tận dụng dịch vụ cloud này cho phép vận hành chi phí thấp nhưng vẫn mở rộng cực nhanh. AWS là lý do Netflix hoạt động trong giờ cao điểm mà không phải trả cho bandwidth server tối đa liên tục.

Dù có nhiều ưu điểm, AWS Lambda không phải giải pháp cho mọi thứ. Nó không tự hoạt động như API và bị giới hạn về khả năng state. Lambda function không thể chạy quá 15 phút, và memory giới hạn 6GB. Cũng hơi thách thức khi test Lambda function, vì thường phải duplicate toàn bộ hạ tầng trong môi trường riêng.

Nếu bạn có app hoặc feature không cần chạy 24/7, thì Lambda có thể phù hợp. Nếu function cần duy trì trạng thái nào đó hoặc cập nhật dữ liệu ngoài hệ sinh thái AWS, thì Lambda không phù hợp. Lambda mặc định 1,000 concurrent connection, nên app thường xuyên thấy usage hơn con số đó sẽ rất không tin cậy trên Lambda. Về cơ bản, Lambda tốt nhất cho tác vụ tự động hóa hướng sự kiện, ngắn hạn, không yêu cầu state bền vững.

Lambda function có thể là công cụ mạnh mẽ, đặc biệt trong tay lập trình viên Ruby như bạn.