Java hiếm khi là lựa chọn đầu tiên khi nói đến các hàm serverless. Các ngôn ngữ thông dịch như JavaScript, Python và Go thống lĩnh lĩnh vực này nhờ thời gian khởi động nhanh hơn so với các ứng dụng chạy trên JVM.
Trong chuỗi bài viết này, tôi sẽ khám phá những trường hợp mà viết hàm serverless bằng Java không chỉ khả thi mà còn mang lại lợi ích thực sự. Chúng ta cũng sẽ tìm hiểu cách tối ưu hóa thời gian khởi động lạnh (cold start) và những kỹ thuật giúp xây dựng giải pháp serverless hiệu quả với Java.
Serverless Function là gì?
Trước tiên, hãy cùng phân tích khái niệm function. Trong toán học, một hàm xác định mối quan hệ giữa giá trị đầu vào (x) và giá trị đầu ra (f(x)), trong đó với mỗi x xác định, luôn có một kết quả duy nhất. Ví dụ:
f(x) = x² + 3
Vậy nếu x = 2, ta có f(2) = 7.
Hàm serverless hoạt động trên nguyên lý tương tự – nó nhận đầu vào, xử lý và trả về kết quả. Nó không lưu trạng thái (stateless) – chỉ chạy khi được gọi, thực hiện tính toán cần thiết rồi biến mất, không tiêu tốn tài nguyên khi không sử dụng.
Đây là một cách nhìn đơn giản, nhưng nắm bắt đúng bản chất của hàm serverless.
Hàm Serverless hoạt động như thế nào?
Giả sử bạn đang vận hành một cửa hàng trực tuyến và cần cơ chế tính giá giảm giá theo yêu cầu. Thay vì triển khai một máy chủ ứng dụng đầy đủ, bạn có thể tạo một hàm serverless:
- Nhận giá gốc và phần trăm giảm giá làm đầu vào.
- Tính toán giá đã giảm theo công thức định sẵn.
- Trả kết quả cho người dùng.
Các hàm serverless có thể được kích hoạt theo nhiều cách:
- Qua API khi người dùng gửi yêu cầu HTTP.
- Theo lịch trình (scheduled job), ví dụ như phân tích dữ liệu hàng ngày.
- Đáp ứng sự kiện như khi có file mới thêm vào cơ sở dữ liệu hoặc tin nhắn mới đến hàng đợi.
Phép màu bắt đầu – Tự động Scale từ 0 đến... vô hạn
Một trong những lợi thế lớn nhất của serverless là khả năng scale tự động – từ 0 khi không có truy cập đến hàng nghìn instance khi nhu cầu tăng vọt.
Trong thực tế điều này hoạt động ra sao?
Quay lại ví dụ tính giá giảm: ban ngày chỉ vài yêu cầu mỗi giờ, nhưng buổi tối cửa hàng mở chương trình giảm giá sốc, hàng nghìn người dùng cùng truy cập.
Với hạ tầng truyền thống, bạn sẽ phải:
- Dự đoán lượng truy cập (khó khăn – có thể 500 hoặc 50.000).
- Tự mở rộng tài nguyên để đáp ứng nhu cầu.
- Trả tiền cho hạ tầng ngay cả khi không dùng hết.
Với serverless thì khác:
- Nếu chỉ có 1 yêu cầu, chỉ 1 instance được kích hoạt.
- Nếu có 10.000 yêu cầu trong vài phút, cloud sẽ tự sinh ra 10.000 instance, mỗi cái xử lý 1 yêu cầu.
- Khi hết truy cập, tất cả instance dừng lại → không tốn tài nguyên, không tốn chi phí.
Chỉ trả phí khi sử dụng
Nhờ mô hình tính phí theo thời gian chạy, bạn không trả phí cho tài nguyên rỗi – chỉ trả cho thời gian thực thi hàm. Nếu cả ngày không ai truy cập, chi phí là 0. Nếu có 100.000 yêu cầu trong 1 giờ, bạn chỉ trả cho những lần hàm chạy thực tế.
Vượt xa hạ tầng truyền thống – Tự động mở rộng không giới hạn
Ứng dụng truyền thống cần scale thủ công hoặc cài auto-scaler, dự đoán nhu cầu và quản lý tài nguyên. Serverless loại bỏ gánh nặng này. Dù cần 100, 1.000 hay 100.000 instance, hệ thống sẽ lo liệu. Mặc dù các nhà cung cấp cloud có giới hạn, nhưng với hầu hết trường hợp, serverless vẫn vượt trội hơn hạ tầng truyền thống.
Tại sao thực tế không hề "Màu hồng"?
Nghe như quá tuyệt – tự động scale, không quản lý server, chỉ trả phí khi chạy? Đúng là vậy… nhưng không hoàn toàn. Serverless vẫn có những hạn chế và thách thức mà lập trình viên cần lưu ý.
Cold Start – Nỗi Đau Lớn Nhất Của JVM
Một trong những nhược điểm lớn nhất là cold start – thời gian khởi động lại function sau thời gian không hoạt động.
Tại sao điều này lại quan trọng?
- Ngôn ngữ thông dịch (Python, JS) khởi động gần như tức thì.
- Java cần tải môi trường runtime JVM → có thể mất vài giây.
- Với ứng dụng tương tác, chậm vài giây có thể gây khó chịu, đặc biệt nếu xử lý yêu cầu người dùng.
Giới hạn thời gian thực thi
Hầu hết nhà cung cấp cloud giới hạn thời gian chạy hàm:
- AWS Lambda – tối đa 15 phút.
- Azure Functions – tối đa 10 phút (gói Consumption).
- Google Cloud Functions – vài phút, tùy cấu hình.
→ Không phù hợp với các quy trình dài – nên dùng server hoặc hệ thống xử lý phân tán cho tác vụ phức tạp.
Không lưu trạng thái
Hàm serverless stateless – mỗi lần chạy đều bắt đầu trong môi trường mới. Nếu cần lưu trữ:
- Sử dụng database (DynamoDB, Firebase).
- Hàng đợi & stream (Kafka, SQS).
- Lưu trữ cloud (S3, Cloud Storage).
Khó khăn khi Debug & giám sát
Khó debug vì không thể truy cập hạ tầng trực tiếp. Phải dựa vào:
- Log của nhà cung cấp cloud.
- Công cụ giám sát hiệu năng thời gian thực.
- Công cụ test cục bộ như AWS SAM, LocalStack để giả lập quá trình chạy.
Hy vọng các bạn thấy thông tin vừa rồi hữu ích!