Giới thiệu tổng quan về Knative và WebAssembly
Knative là một khung công nghệ (framework) tính toán Serverless được xây dựng trên nền tảng Kubernetes, giúp đơn giản hóa đáng kể quy trình phát triển và vận hành các ứng dụng trên cụm K8s. Được CNCF chấp nhận vào chương trình incubation từ đầu năm 2022, Knative bao gồm hai thành phần cốt lõi: Knative Serving dành cho các ứng dụng HTTP và Knative Eventing hỗ trợ kiến trúc hướng sự kiện (Event-driven) với CloudEvents.
Thông thường, Knative hỗ trợ các môi trường runtime dạng container. Tuy nhiên, bài viết này sẽ khám phá việc tích hợp WebAssembly (WASM) như một runtime mới cho Serverless, mang lại những lợi ích khác biệt so với container truyền thống.
Từ WebAssembly đến WASI và WAGI
WebAssembly (WASM) là một tiêu chuẩn W3C định nghĩa một kiến trúc tập lệnh ảo (virtual ISA). Mục tiêu ban đầu là cho phép các chương trình viết bằng C/C++ hoặc Rust hoạt động an toàn và hiệu quả trên trình duyệt. Hiện nay, WASM đã được hỗ trợ rộng rãi bởi các trình duyệt lớn. Quan trọng hơn, nó đóng vai trò như một sandbox ảo an toàn, có tính khả chuyển cao và hiệu suất tốt, cho phép chạy ứng dụng trên bất kỳ hệ điều hành hay kiến trúc CPU nào.
Để mở rộng ứng dụng của WASM ra ngoài trình duyệt, Mozilla đã giới thiệu WebAssembly System Interface (WASI). WASI cung cấp các API chuẩn kiểu POSIX để ứng dụng WASM tương tác với tài nguyên hệ thống như hệ thống tệp và bộ nhớ. Sự ra đời của WASI, cùng với sự thành lập của Bytecode Alliance (bao gồm Mozilla, Fastly, Intel, Red Hat...), đã thúc đẩy WASM trở thành một ứng viên tiềm năng để chạy các ứng dụng phía máy chủ (server-side).
So với container vốn là các tiến trình hệ điều hành (OS process) độc lập, ứng dụng WASM có thể实现 sự cô lập an toàn ngay trong cùng một tiến trình. Điều này giúp giảm thiểu mức tiêu thụ tài nguyên và đạt được thời gian khởi động lạnh (cold start) ở mức mili-giây.
Mặc dù vậy, WASM/WASI vẫn đang trong giai đoạn phát triển và có những hạn chế như thiếu hỗ trợ luồng (threading) hay các ứng dụng socket cấp thấp. Để vượt qua những trở ngại này khi phát triển web API, các kỹ sư từ Microsoft Deislabs đã đề xuất dự án WAGI (WebAssembly Gateway Interface). WAGI lấy cảm hứng từ giao diện CGI (Common Gateway Interface) cổ điển.
Trong mô hình CGI, máy chủ HTTP giao tiếp với các script thông qua stdin/stdout. Tương tự, WAGI cho phép gọi các ứng dụng WASI thông qua giao thức chuẩn. Điều này giúp lập trình viên phát triển các microservice bằng WebAssembly mà không cần quan tâm sâu đến các chi tiết phức tạp của việc xử lý mạng. Khác với CGI tạo mới một tiến trình OS cho mỗi yêu cầu, WAGI gọi ứng dụng WASM trong một luồng riêng biệt và sử dụng chính máy ảo WASM để cô lập bảo mật, giúp giảm thiểu chi phí tài nguyên.
Tối ưu hóa hiệu suất khởi động lạnh cho ứng dụng WAGI
Trong môi trường Serverless, thời gian phản hồi và hiệu suất khởi động lạnh là những chỉ số then chốt. Khi kiểm thử hiệu năng ban đầu của WAGI bằng công cụ đo áp lực (benchmark), chúng ta nhận thấy thời gian phản hồi P90 khoảng 115ms - một con số chưa thực sự tối ưu so với kỳ vọng về sự "nhẹ nhàng" của WASM.
Bằng cách sử dụng biểu đồ flame (flamegraph) để phân tích, chúng tôi phát hiện ra rằng hàm prepare_wasm_instance đang chiếm tới 80% tổng thời gian xử lý. Nguyên nhân là do logic ban đầu thực hiện việc kết nối lại các mở rộng WASI và cấu hình môi trường cho từng yêu cầu HTTP riêng lẻ.
Giải pháp đưa ra là tái cấu trúc logic thực thi: thay vì chuẩn bị instance cho mỗi request, chúng ta di chuyển công tác khởi tạo sang giai đoạn khởi động (initialization) của ứng dụng và thực hiện chỉ một lần. Các instance đã cấu hình sẵn sẽ được lưu trong bộ nhớ đệm để tái sử dụng cho các lần gọi sau. Sau khi áp dụng thay đổi này, thời gian xử lý của prepare_wasm_instance giảm xuống còn 17%, và thời gian phản hồi P90 cải thiện đáng kể xuống còn 21ms.
Triển khai ứng dụng WAGI trên Knative
Để tích hợp WAGI vào hệ sinh thái Knative, chúng ta cần đảm bảo container WAGI hỗ trợ tín hiệu SIGTERM để có thể tắt (shutdown) một cách优雅 (graceful) khi Knative yêu cầu thu hồi Pod. Bạn có thể tham khảo tài liệu cài đặt Knative để thiết lập môi trường kiểm thử trên Minikube hoặc sử dụng các dịch vụ K8s Serverless đám mây có sẵn hỗ trợ Knative.
Dưới đây là một tệp cấu hình mẫu để triển khai dịch vụ Knative sử dụng WAGI:
apiVersion: serving.knative.dev/v1
kind: Service
metadata:
name: wasm-demo-service
namespace: default
spec:
template:
metadata:
annotations:
# Sử dụng lớp autoscaling dựa trên độ đồng thời (concurrency)
autoscaling.knative.dev/class: kpa.autoscaling.knative.dev
autoscaling.knative.dev/metric: concurrency
# Mục tiêu là 10 yêu cầu đồng thời trên mỗi Pod
autoscaling.knative.dev/target: "10"
# Giới hạn số lượng Pod tối đa là 10
autoscaling.knative.dev/max-scale: "10"
spec:
containers:
# Sử dụng image chứa WAGI gateway và ứng dụng WASM mẫu
- image: docker.io/library/web-assembly-runtime:latest
ports:
- containerPort: 8080
Trong cấu hình trên:
- Image:
web-assembly-runtimebao gồm gateway WAGI cùng với một số ứng dụng mẫu biên dịch sang định dạng WASM. - Autoscaling: Dịch vụ
wasm-demo-servicesẽ tự động mở rộng quy mô (scale out) dựa trên số lượng yêu cầu đến.
Sau khi áp dụng tệp cấu hình, bạn có thể kiểm tra trạng thái dịch vụ:
$ kubectl apply -f wasm-service.yaml
$ kubectl get ksvc wasm-demo-service
NAME URL LATESTCREATED LATESTREADY READY REASON
wasm-demo-service http://wasm-demo.default.example.com wasm-demo-service-0001 wasm-demo-service-0001 True
Kiểm tra phản hồi từ dịch vụ:
$ curl http://wasm-demo.default.example.com
Xin chao the gioi WASM
$ curl http://wasm-demo.default.example.com/api/info
Thong tin he thong
Bạn có thể thực hiện kiểm thử áp lực để quan sát khả năng tự động co giãn của Knative khi chạy với các khối công việc WebAssembly.