Giới thiệu wasi-grpc cho Spin
Tác giả: Brian Hardock
Trong hệ sinh thái microservices hiện đại, gRPC thường được sử dụng để giao tiếp hiệu quả với kiểu dữ liệu mạnh mẽ. gRPC dựa trên HTTP/2, tận dụng luồng đa kênh và tuần tự nhị phân (Protobuf) để cung cấp băng thông cao và độ trễ thấp.
Tính năng mới trong Spin 3.4
Trước phiên bản Spin 3.4, các thành phần Spin chỉ có thể thực hiện các yêu cầu HTTP/1.1. Điều này có nghĩa là các client gRPC không thể chạy trực tiếp bên trong Spin; các nhà phát triển phải dựa vào các sidecar hoặc dịch vụ proxy để kết nối. Điều này đã thêm sự phức tạp và làm chậm ứng dụng.
Spin 3.4 đã giới thiệu hỗ trợ HTTP/2 outbound, cho phép các thành phần hoạt động như client gRPC chính thức. Các ứng dụng Spin giờ đây có thể gọi vào các hệ thống dựa trên gRPC, API đám mây và service meshes một cách trực tiếp mà không cần các giải pháp tạm thời.
Trong bài viết này, chúng ta sẽ đi qua một hướng dẫn về cách xây dựng một thành phần Spin bằng Rust kết nối với một dịch vụ gRPC đơn giản sử dụng crate mới là wasi-grpc.
Mục lục
- Hướng dẫn
- Bước 1: Tạo một ứng dụng Spin mới
- Bước 2: Cấu hình
- Thực hiện
- Chạy ứng dụng
- Kết luận
- Câu hỏi thường gặp
Hướng dẫn
Chúng ta sẽ điều chỉnh client helloworld
mẫu từ tonic để thực thi trong Spin. Ngoài ra, để kiểm tra, chúng ta sẽ chạy server helloworld
để thực thi thành phần của chúng ta.
Bước 1: Tạo một ứng dụng Spin mới
Chạy lệnh sau để tạo một ứng dụng mới:
bash
spin new -t http-rust helloworld-client --accept-defaults
Lệnh này sẽ tạo một thư mục mới helloworld-client
với một ứng dụng Spin HTTP bằng Rust. Chuyển vào thư mục này để tiếp tục hướng dẫn:
bash
cd helloworld-client
Bước 2: Cấu hình
Đầu tiên, trong Cargo.toml
, thêm các phụ thuộc cần thiết để làm việc với gRPC, Protobuf và crate wasi-grpc:
toml
[dependencies]
anyhow = "1"
prost = "0.13.5"
wasi-grpc = "0.1.0"
spin-sdk = "4.0.0"
tonic = { version = "0.13.1", features = ["codegen", "prost", "router"], default-features = false}
Tiếp theo, sao chép tệp proto helloworld
vào thư mục làm việc hiện tại.
Sau đó, chúng ta sẽ thêm các phụ thuộc xây dựng để tạo mã từ tệp proto. Trong Cargo.toml
, thêm đoạn sau:
toml
[build-dependencies]
tonic-build = { version = "0.13.1", features = ["prost"] }
Cuối cùng, chúng ta sẽ thêm tệp build.rs
để tạo client gRPC từ tệp proto helloworld
:
rust
// Trong build.rs
fn main() {
tonic_build::configure()
.build_transport(false)
.compile_protos(&["helloworld.proto"], &[""])
.unwrap();
}
Thực hiện
Trong src/lib.rs
, bắt đầu bằng cách kéo vào mã đã được tạo ra từ việc thực thi build.rs
:
rust
use hello_world::greeter_client::GreeterClient;
use hello_world::HelloRequest;
pub mod hello_world {
tonic::include_proto!("helloworld");
}
Tiếp theo, kéo vào kiểu wasi_grpc::WasiGrpcEndpoint
mà thực hiện tower_service::Service
. Kiểu này tạo ra cầu nối giữa tonic và wasi-hyperium, là thứ mà wasi-grpc
sử dụng để gửi các yêu cầu HTTP ra ngoài.
rust
use wasi_grpc::WasiGrpcEndpoint;
LƯU Ý: Quyết định sử dụng
wasi-hyperium
như cơ chế cơ bản để gửi yêu cầu ra ngoài được đưa ra vìspin-sdk
hiện có một số hạn chế liên quan đến streaming outbound.
Cuối cùng, chúng ta có thể triển khai bộ xử lý yêu cầu:
rust
#[http_component]
async fn handler(_req: http::Request) -> anyhow::Result<impl IntoResponse> {
let endpoint_uri = "http://[::1]:50051".parse().context("Failed to parse endpoint URI")?;
let endpoint = WasiGrpcEndpoint::new(endpoint_uri);
let mut client = GreeterClient::new(endpoint);
let request = Request::new(HelloRequest {
name: "World".to_string(),
});
let message = client
.say_hello(request)
.await?
.into_inner()
.message;
let response = http::Response::new(200, message);
Ok(response)
}
LƯU Ý: Để đơn giản, chúng ta đang sử dụng một endpoint cố định (“http://[::1]:50051”) để giao tiếp với server gRPC địa phương mà thực hiện
GreeterService
. Đối với các ứng dụng sản xuất, nên sử dụng các biến ứng dụng để chèn giá trị của địa chỉ tại thời điểm chạy/triển khai.
Kết hợp tất cả lại, mã cuối cùng trong src/lib.rs
trông như sau:
rust
use anyhow::Context;
use spin_sdk::http::{self, IntoResponse};
use spin_sdk::http_component;
use tonic::Request;
use wasi_grpc::WasiGrpcEndpoint;
use hello_world::greeter_client::GreeterClient;
use hello_world::HelloRequest;
pub mod hello_world {
tonic::include_proto!("helloworld");
}
// Thành phần HTTP của Spin
#[http_component]
async fn handler(_req: http::Request) -> anyhow::Result<impl IntoResponse> {
let endpoint_uri = "http://[::1]:50051".parse().context("Failed to parse endpoint URI")?;
let endpoint = WasiGrpcEndpoint::new(endpoint_uri);
let mut client = GreeterClient::new(endpoint);
let request = Request::new(HelloRequest {
name: "World".to_string(),
});
let message = client
.say_hello(request)
.await?
.into_inner()
.message;
// Trả về phản hồi gRPC dưới dạng nội dung phản hồi HTTP cho thành phần Spin
let response = http::Response::new(200, message);
Ok(response)
}
Chạy ứng dụng
Như đã đề cập trước đó, chúng ta sẽ sử dụng server helloworld để thực thi ứng dụng của mình. Cách dễ nhất để chạy điều này là sao chép kho lưu trữ tonic và chạy server helloworld:
bash
$ gh repo clone hyperium/tonic
$ cargo run --bin helloworld-server
...
GreeterServer listening on [::1]:50051
Tiếp theo, chúng ta cần cấu hình ứng dụng Spin sao cho thành phần của chúng ta có thể giao tiếp với server đang chạy ở [::1]:50051
. Trong tệp spin.toml
, thêm đoạn sau:
toml
[component.helloworld-client]
...
allowed_outbound_hosts = ["http://[::1]:50051"]
Giờ đây, khi chúng ta đã có server đang chạy và ứng dụng được cấu hình đúng, hãy spin up
ứng dụng của chúng ta và gửi yêu cầu để thực thi thành phần mới:
bash
$ SPIN_OUTBOUND_H2C_PRIOR_KNOWLEDGE=[::1]:50051 spin up --build
LƯU Ý: Biến môi trường
SPIN_OUTBOUND_H2C_PRIOR_KNOWLEDGE
được sử dụng để thông báo cho runtime Spin rằng chúng ta dự định sử dụng HTTP/2 mà không cần TLS. Nếu bạn đang chạy ví dụ này với server có TLS được bật, bạn có thể bỏ qua biến này.
Cuối cùng, hãy gửi một yêu cầu đến ứng dụng của chúng ta:
bash
$ curl localhost:3000/
Hello World!
Kết luận
Hỗ trợ HTTP/2 outbound trong Spin 3.4 đã loại bỏ một trong những rào cản lớn nhất trong việc sử dụng Spin trong các hệ thống theo kiểu dịch vụ hiện đại: hỗ trợ client gRPC trực tiếp. Với sự trợ giúp của crate wasi-grpc, các thành phần giờ đây có thể:
- Gọi microservices gRPC trực tiếp mà không cần sidecars
- Tích hợp với các API được xây dựng trên gRPC
- Tận dụng các mẫu streaming hiệu suất cao như những công dân hàng đầu trong Spin
Ví dụ trên sử dụng dịch vụ helloworld đơn giản, nhưng cùng một cách tiếp cận có thể áp dụng cho các dịch vụ phức tạp hơn — bao gồm các API streaming. Để lấy cảm hứng, hãy xem routeguide-client trong kho lưu trữ wasi-grpc.
Nếu bạn có bất kỳ câu hỏi nào, chúng tôi rất muốn giúp đỡ qua kênh Slack Spin CNCF. Hy vọng sẽ gặp bạn ở đó!