1. Pengantar
Dalam codelab ini, Anda akan menggunakan gRPC-Rust untuk membuat klien dan server yang membentuk fondasi aplikasi pemetaan rute yang ditulis dalam Rust.
Di akhir tutorial, Anda akan memiliki klien yang terhubung ke server jarak jauh menggunakan gRPC untuk mendapatkan nama atau alamat pos dari apa yang terletak di koordinat tertentu pada peta. Aplikasi yang berfungsi penuh dapat menggunakan desain klien-server ini untuk menghitung atau meringkas lokasi menarik di sepanjang rute.
Layanan ini ditentukan dalam file Protocol Buffers, yang akan digunakan untuk membuat kode boilerplate bagi klien dan server sehingga keduanya dapat berkomunikasi satu sama lain, sehingga menghemat waktu dan upaya Anda dalam menerapkan fungsi tersebut.
Kode yang dihasilkan ini tidak hanya menangani kompleksitas komunikasi antara server dan klien, tetapi juga serialisasi dan deserialisasi data.
Yang akan Anda pelajari
- Cara menggunakan Protocol Buffers untuk menentukan API layanan.
- Cara membangun klien dan server berbasis gRPC dari definisi Protocol Buffers menggunakan pembuatan kode otomatis.
- Pemahaman tentang komunikasi klien-server dengan gRPC.
Codelab ini ditujukan bagi developer Rust yang baru menggunakan gRPC atau ingin mempelajari kembali gRPC, atau siapa pun yang tertarik untuk membangun sistem terdistribusi. Tidak diperlukan pengalaman gRPC sebelumnya.
2. Sebelum memulai
Prasyarat
Pastikan Anda telah menginstal berikut ini:
Mendapatkan kode
Agar Anda tidak perlu memulai dari awal, codelab ini menyediakan kerangka kode sumber aplikasi yang dapat Anda selesaikan. Langkah-langkah berikut akan menunjukkan cara menyelesaikan aplikasi, termasuk menggunakan plugin compiler buffer protokol untuk membuat kode gRPC boilerplate.
Pertama, buat direktori kerja codelab dan cd ke dalamnya:
mkdir grpc-rust-getting-started && cd grpc-rust-getting-started
Download dan ekstrak codelab:
curl -sL https://github.com/grpc-ecosystem/grpc-codelabs/archive/refs/heads/v1.tar.gz \
| tar xvz --strip-components=4 \
grpc-codelabs-1/codelabs/grpc-rust-getting-started/start_here
Atau, Anda dapat mendownload file .zip yang hanya berisi direktori codelab dan mengekstraknya secara manual.
Kode sumber yang sudah selesai tersedia di GitHub jika Anda ingin melewati pengetikan implementasi.
3. Menentukan layanan
Langkah pertama Anda adalah menentukan layanan gRPC aplikasi, metode RPC, serta jenis pesan permintaan dan responsnya menggunakan Protocol Buffers. Layanan Anda akan menyediakan:
- Metode RPC yang disebut
GetFeature
yang diimplementasikan server dan dipanggil klien. - Jenis pesan
Point
danFeature
yang merupakan struktur data yang dipertukarkan antara klien dan server saat menggunakan metodeGetFeature
. Klien memberikan koordinat peta sebagaiPoint
dalam permintaanGetFeature
ke server, dan server membalas denganFeature
yang sesuai yang menjelaskan apa pun yang berada di koordinat tersebut.
Metode RPC ini dan jenis pesannya akan ditentukan dalam file proto/route_guide.proto
kode sumber yang diberikan.
Protocol Buffers biasanya dikenal sebagai protobuf. Untuk mengetahui informasi selengkapnya tentang terminologi gRPC, lihat Konsep inti, arsitektur, dan siklus proses gRPC.
Metode layanan
Pertama, mari kita tentukan metode layanan, lalu tentukan jenis pesan Point
dan Feature
. File proto/routeguide.proto
memiliki struktur service
bernama RouteGuide
yang menentukan satu atau beberapa metode yang disediakan oleh layanan aplikasi.
Tambahkan metode rpc
GetFeature
di dalam definisi RouteGuide
. Seperti yang dijelaskan sebelumnya, metode ini akan mencari nama atau alamat lokasi dari sekumpulan koordinat tertentu, jadi buat GetFeature
menampilkan Feature
untuk Point
tertentu:
service RouteGuide {
// Definition of the service goes here
// Obtains the feature at a given position.
rpc GetFeature(Point) returns (Feature) {}
}
Ini adalah metode RPC unary: RPC sederhana di mana klien mengirim permintaan ke server dan menunggu respons kembali, seperti panggilan fungsi lokal.
Jenis pesan
Dalam file proto/route_guide.proto
kode sumber, tentukan terlebih dahulu jenis pesan Point
. Point
mewakili pasangan koordinat lintang-bujur di peta. Untuk codelab ini, gunakan bilangan bulat untuk koordinat:
message Point {
int32 latitude = 1;
int32 longitude = 2;
}
Angka 1
dan 2
adalah nomor ID unik untuk setiap kolom dalam struktur message
.
Selanjutnya, tentukan jenis pesan Feature
. Feature
menggunakan kolom string
untuk nama atau alamat pos sesuatu di lokasi yang ditentukan oleh Point
:
message Feature {
// The name or address of the feature.
string name = 1;
// The point where the feature is located.
Point location = 2;
}
4. Buat kode klien dan server
Kami telah memberikan kode yang dihasilkan dari file .proto
di direktori yang dihasilkan.
Seperti project lainnya, kita perlu memikirkan dependensi yang diperlukan untuk kode kita. Untuk project Rust, dependensi akan ada di Cargo.toml
. Kita telah mencantumkan dependensi yang diperlukan dalam file Cargo.toml
.
Jika Anda ingin mempelajari cara membuat kode dari file .proto
sendiri, lihat petunjuk ini.
Kode yang dihasilkan berisi:
- Definisi struct untuk jenis pesan
Point
danFeature
. - Trait layanan yang perlu kita terapkan:
route_guide_server::RouteGuide
. - Jenis klien yang akan kita gunakan untuk memanggil server:
route_guide_client::RouteGuideClient<T>
.
Selanjutnya, kita akan menerapkan metode GetFeature
di sisi server, sehingga saat klien mengirim permintaan, server dapat membalas dengan jawaban.
5. Menerapkan layanan
Di src/server/server.rs
, kita dapat memasukkan kode yang dihasilkan ke dalam cakupan melalui makro include_generated_proto!
gRPC dan mengimpor trait RouteGuide
dan Point
.
mod grpc_pb {
grpc::include_generated_proto!("generated", "routeguide");
}
pub use grpc_pb::{
route_guide_server::{RouteGuideServer, RouteGuide},
Point, Feature,
};
Kita dapat memulai dengan menentukan struct untuk merepresentasikan layanan, kita dapat melakukannya di src/server/server.rs
untuk saat ini:
#[derive(Debug)]
pub struct RouteGuideService {
features: Vec<Feature>,
}
Sekarang, kita perlu menerapkan trait route_guide_server::RouteGuide
dari kode yang dihasilkan.
RPC Unary
RouteGuideService
mengimplementasikan semua metode layanan kami. Fungsi get_feature
di sisi server adalah tempat pekerjaan utama dilakukan: fungsi ini mengambil pesan Point
dari klien dan menampilkan informasi lokasi yang sesuai dari daftar tempat yang diketahui dalam pesan Feature
. Berikut penerapan fungsi di src/server/server.rs
:
#[tonic::async_trait]
impl RouteGuide for RouteGuideService {
async fn get_feature(&self, request: Request<Point>) -> Result<Response<Feature>, Status> {
println!("GetFeature = {:?}", request);
let requested_point = request.get_ref();
for feature in self.features.iter() {
if feature.location().latitude() == requested_point.latitude() {
if feature.location().longitude() == requested_point.longitude(){
return Ok(Response::new(feature.clone()))
};
};
}
Ok(Response::new(Feature::default()))
}
}
Dalam metode ini, isi objek Feature
dengan informasi yang sesuai untuk Point
tertentu, lalu tampilkan.
Setelah menerapkan metode ini, kita juga perlu memulai server gRPC agar klien dapat menggunakan layanan kita. Ganti main()
dengan ini.
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let addr = "[::1]:10000".parse().unwrap();
println!("RouteGuideServer listening on: {addr}");
let route_guide = RouteGuideService {
features: load(),
};
let svc = RouteGuideServer::new(route_guide);
Server::builder().add_service(svc).serve(addr).await?;
Ok(())
}
Berikut yang terjadi di main()
, langkah demi langkah:
- Tentukan port yang ingin kita gunakan untuk memproses permintaan klien
- Buat
RouteGuideService
dengan fitur yang dimuat dengan memanggil fungsi bantuanload()
- Buat instance server gRPC menggunakan
RouteGuideServer::new()
menggunakan layanan yang kita buat. - Daftarkan implementasi layanan kita dengan server gRPC.
- Panggil
serve()
di server dengan detail port kami untuk melakukan penantian pemblokiran hingga proses dihentikan.
6. Buat klien
Di bagian ini, kita akan melihat cara membuat klien Rust untuk layanan RouteGuide di src/client/client.rs
.
Seperti yang kita lakukan di src/server/server.rs
, kita dapat membawa kode yang dihasilkan ke dalam cakupan melalui makro include_generated_code!
gRPC dan mengimpor jenis RouteGuideClient
.
mod grpc_pb {
grpc::include_generated_proto!("generated", "routeguide");
}
use grpc_pb::{
route_guide_client::RouteGuideClient,
Point,
};
Panggil metode layanan
Di gRPC-Rust, RPC beroperasi dalam mode pemblokiran/sinkron, yang berarti bahwa panggilan RPC menunggu server merespons, dan akan menampilkan respons atau error.
Untuk memanggil metode layanan, kita harus membuat channel terlebih dahulu untuk berkomunikasi dengan server. Kita membuatnya dengan terlebih dahulu membuat endpoint, menghubungkan ke endpoint tersebut, dan meneruskan channel yang dibuat saat terhubung ke RouteGuideClient::new()
sebagai berikut:
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
// Create endpoint to connect to
let endpoint = Endpoint::new("http://[::1]:10000")?;
let channel = endpoint.connect().await?;
// Create a new client
let mut client = RouteGuideClient::new(channel);
Ok(())
}
Dalam fungsi ini, saat membuat klien, kita akan membungkus channel generik yang dibuat di atas dengan stub kode yang dihasilkan yang menerapkan metode spesifik yang ditentukan dalam layanan .proto.
RPC Sederhana
Memanggil RPC GetFeature
sederhana hampir sama mudahnya dengan memanggil metode lokal. Tambahkan ini di main()
.
println!("*** SIMPLE RPC ***");
let point = proto!(Point{
latitude: 409_146_138,
longitude: -746_188_906
});
let response = client
.get_feature(Request::new(point))
.await?.into_inner();
Ok(())
Seperti yang dapat Anda lihat, kita memanggil metode pada stub yang kita dapatkan sebelumnya. Dalam parameter metode, kita membuat dan mengisi objek buffer protokol permintaan (dalam kasus ini Point
). Jika panggilan tidak menampilkan error, kita dapat membaca informasi respons dari server dari nilai yang ditampilkan pertama.
println!("Response = Name = \"{}\", Latitude = {}, Longitude = {}",
response.name(),
response.location().latitude(),
response.location().longitude());
Secara keseluruhan, fungsi main()
klien akan terlihat seperti ini:
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
//Create endpoint to connect to
let endpoint = Endpoint::new("http://[::1]:10000")?;
let channel = endpoint.connect().await?;
// Create a new client
let mut client = RouteGuideClient::new(channel);
println!("*** SIMPLE RPC ***");
let point = proto!(Point{
latitude: 409_146_138,
longitude: -746_188_906
});
let response = client
.get_feature(Request::new(point))
.await?.into_inner();
println!("Response = Name = \"{}\", Latitude = {}, Longitude = {}",
response.name(),
response.location().latitude(),
response.location().longitude());
Ok(())
}
7. Cobalah
Pertama, untuk menjalankan Klien dan Server, mari kita tambahkan sebagai target biner ke crate. Kita perlu mengedit Cargo.toml
dengan tepat dan menambahkan kode berikut:
[[bin]]
name = "routeguide-server"
path = "src/server/server.rs"
[[bin]]
name = "routeguide-client"
path = "src/client/client.rs"
Kemudian, jalankan perintah berikut dari direktori kerja kita:
- Jalankan server di satu terminal:
RUSTFLAGS="-Awarnings" cargo run --bin routeguide-server
- Jalankan klien dari terminal lain:
RUSTFLAGS="-Awarnings" cargo run --bin routeguide-client
Anda akan melihat output seperti ini, dengan stempel waktu yang dihilangkan agar lebih jelas:
*** SIMPLE RPC *** FEATURE: Name = "Berkshire Valley Management Area Trail, Jefferson, NJ, USA", Lat = 409146138, Lon = -746188906
8. Langkah berikutnya
- Pelajari cara kerja gRPC di Pengantar gRPC dan Konsep inti
- Pelajari tutorial Dasar-Dasar.