1. Pengantar
Dalam codelab ini, Anda akan menggunakan gRPC-Java untuk membuat klien dan server yang membentuk dasar aplikasi pemetaan rute yang ditulis dalam Java.
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.
API server 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 Java yang baru mengenal gRPC atau ingin mempelajari kembali gRPC, atau siapa pun yang tertarik untuk membangun sistem terdistribusi. Tidak diperlukan pengalaman gRPC sebelumnya.
2. Sebelum memulai
Prasyarat
- JDK versi 8 atau yang lebih baru
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-java-getting-started && cd grpc-java-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-java-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 src/main/proto/routeguide/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.
Karena kita membuat kode Java dalam contoh ini, kita telah menentukan opsi file java_package
dan nama untuk class Java dalam .proto
:
option java_package = "io.grpc.examples.routeguide";
option java_outer_classname = "RouteGuideProto";
Jenis pesan
Dalam file routeguide/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;
}
Metode layanan
File route_guide.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.
4. Membuat kode klien dan server
Selanjutnya, kita perlu membuat antarmuka klien dan server gRPC dari definisi layanan .proto
. Kami melakukannya menggunakan compiler protocol buffer protoc
dengan plugin gRPC Java khusus. Anda harus menggunakan compiler proto3 (yang mendukung sintaksis proto2 dan proto3) untuk membuat layanan gRPC.
Saat menggunakan Gradle atau Maven, plugin build protoc
dapat membuat kode yang diperlukan sebagai bagian dari build. Anda dapat melihat README grpc-java untuk mengetahui cara membuat kode dari file .proto
Anda sendiri.
Kami telah menyediakan lingkungan dan konfigurasi Gradle dalam kode sumber codelab untuk membangun project ini.
Di dalam direktori grpc-java-getting-started
, jalankan perintah berikut:
$ chmod +x gradlew $ ./gradlew generateProto
Class berikut dihasilkan dari definisi layanan kita:
Feature.java
,Point.java
, dan lainnya yang berisi semua kode buffer protokol untuk mengisi, membuat serial, dan mengambil jenis pesan permintaan dan respons kita.RouteGuideGrpc.java
yang berisi (bersama dengan beberapa kode berguna lainnya) class dasar untuk diterapkan serverRouteGuide
,RouteGuideGrpc.RouteGuideImplBase
, dengan semua metode yang ditentukan dalam layananRouteGuide
dan class stub untuk digunakan klien.
5. Menerapkan server
Pertama, mari kita lihat cara membuat server RouteGuide
. Ada dua bagian untuk membuat layanan RouteGuide
kami melakukan tugasnya:
- Mengimplementasikan antarmuka layanan yang dihasilkan dari definisi layanan kami, yang melakukan "pekerjaan" layanan kami yang sebenarnya.
- Menjalankan server gRPC untuk memproses permintaan dari klien dan mengirimkannya ke implementasi layanan yang tepat.
Mengimplementasikan RouteGuide
Seperti yang dapat Anda lihat, server kita memiliki class RouteGuideService
yang memperluas class abstrak RouteGuideGrpc.RouteGuideImplBase
yang dihasilkan:
private static class RouteGuideService extends RouteGuideGrpc.RouteGuideImplBase {
...
}
Kami telah menyediakan 2 file berikut untuk menginisialisasi server Anda dengan fitur:
./src/main/java/io/grpc/examples/routeguide/RouteGuideUtil.java
./src/main/resources/io/grpc/examples/routeguide/route_guide_db.json
Mari kita pelajari implementasi RPC sederhana secara mendetail.
RPC Unary
RouteGuideService
mengimplementasikan semua metode layanan kita. Dalam hal ini, hanya GetFeature()
, yang mengambil pesan Point
dari klien dan menampilkan informasi lokasi yang sesuai dari daftar tempat yang diketahui dalam pesan Feature
.
@Override
public void getFeature(Point request, StreamObserver<Feature> responseObserver) {
responseObserver.onNext(checkFeature(request));
responseObserver.onCompleted();
}
Metode getFeature()
menggunakan dua parameter:
Point
: permintaan.StreamObserver<Feature>
: pengamat respons, yang merupakan antarmuka khusus bagi server untuk memanggil dengan responsnya.
Untuk menampilkan respons kami kepada klien dan menyelesaikan panggilan:
- Kita membuat dan mengisi objek respons
Feature
untuk ditampilkan kepada klien, seperti yang ditentukan dalam definisi layanan kita. Dalam contoh ini, kita melakukannya dalam metodecheckFeature()
pribadi yang terpisah. - Kita menggunakan metode
onNext()
pengamat respons untuk menampilkanFeature
. - Kita menggunakan metode
onCompleted()
pengamat respons untuk menentukan bahwa kita telah selesai menangani RPC.
Mulai server
Setelah menerapkan semua metode layanan, kita perlu memulai server gRPC agar klien dapat menggunakan layanan kita. Kami menyertakan pembuatan objek ServerBuilder dalam boilerplate kami:
ServerBuilder.forPort(port), port, RouteGuideUtil.parseFeatures(featureFile)
Kita membangun layanan di konstruktor:
- Tentukan port yang ingin kita gunakan untuk memproses permintaan klien menggunakan metode
forPort()
builder (akan menggunakan alamat wildcard). - Buat instance class implementasi layanan
RouteGuideService
dan teruskan ke metodeaddService()
builder. - Panggil
build()
di builder untuk membuat server RPC bagi layanan kita.
Cuplikan berikut menunjukkan cara membuat objek ServerBuilder
.
/** Create a RouteGuide server listening on {@code port} using {@code featureFile} database. */
public RouteGuideServer(int port, URL featureFile) throws IOException {
this(Grpc.newServerBuilderForPort(port, InsecureServerCredentials.create()),
port, RouteGuideUtil.parseFeatures(featureFile));
}
Cuplikan berikut menunjukkan cara membuat objek server untuk layanan RouteGuide
.
/** Create a RouteGuide server using serverBuilder as a base and features as data. */
public RouteGuideServer(ServerBuilder<?> serverBuilder, int port, Collection<Feature> features) {
this.port = port;
server = serverBuilder.addService(new RouteGuideService(features))
.build();
}
Terapkan metode start yang memanggil start
di server yang kita buat di atas.
public void start() throws IOException {
server.start();
logger.info("Server started, listening on " + port);
}
Terapkan metode untuk menunggu server selesai sehingga tidak langsung keluar.
/** Await termination on the main thread since the grpc library uses daemon threads. */
private void blockUntilShutdown() throws InterruptedException {
if (server != null) {
server.awaitTermination();
}
}
Seperti yang dapat Anda lihat, kita membangun dan memulai server menggunakan ServerBuilder
.
Dalam metode utama, kita:
- Buat instance
RouteGuideServer
. - Panggil
start()
untuk mengaktifkan server RPC untuk layanan kami. - Tunggu hingga layanan dihentikan dengan memanggil
blockUntilShutdown()
.
public static void main(String[] args) throws Exception {
RouteGuideServer server = new RouteGuideServer(8980);
server.start();
server.blockUntilShutdown();
}
6. Buat klien
Di bagian ini, kita akan melihat cara membuat klien untuk layanan RouteGuide
.
Membuat instance stub
Untuk memanggil metode layanan, kita harus membuat stub terlebih dahulu. Ada dua jenis stub, tetapi kita hanya perlu menggunakan stub pemblokiran untuk codelab ini. Kedua jenis tersebut adalah:
- stub pemblokiran/sinkron yang melakukan panggilan RPC dan menunggu server merespons, dan akan menampilkan respons atau memunculkan pengecualian.
- stub non-blocking/asinkron yang membuat panggilan non-blocking ke server, dengan respons ditampilkan secara asinkron. Anda dapat melakukan jenis panggilan streaming tertentu hanya dengan menggunakan stub asinkron.
Pertama, kita perlu membuat channel gRPC, lalu menggunakan channel tersebut untuk membuat stub.
Kita dapat menggunakan ManagedChannelBuilder
secara langsung untuk membuat channel.
ManagedChannelBuilder.forAddress(host, port).usePlaintext().build
Namun, mari kita gunakan metode utilitas yang mengambil string dengan hostname:port
.
Grpc.newChannelBuilder(target, InsecureChannelCredentials.create()).build();
Sekarang kita dapat menggunakan channel untuk membuat stub pemblokiran. Untuk codelab ini, kita hanya memiliki RPC pemblokiran, jadi kita menggunakan metode newBlockingStub
yang disediakan di class RouteGuideGrpc
yang kita buat dari .proto
.
blockingStub = RouteGuideGrpc.newBlockingStub(channel);
Panggil metode layanan
Sekarang, mari kita lihat cara memanggil metode layanan.
RPC Sederhana
Memanggil RPC GetFeature
sederhana hampir sama mudahnya dengan memanggil metode lokal.
Kita membuat dan mengisi objek buffer protokol permintaan (dalam kasus kita, Point
), meneruskannya ke metode getFeature()
pada stub pemblokiran, dan mendapatkan Feature
kembali.
Jika terjadi error, error tersebut dienkode sebagai Status
, yang dapat kita peroleh dari StatusRuntimeException
.
Point request = Point.newBuilder().setLatitude(lat).setLongitude(lon).build();
Feature feature;
try {
feature = blockingStub.getFeature(request);
} catch (StatusRuntimeException e) {
logger.log(Level.WARNING, "RPC failed: {0}", e.getStatus());
return;
}
Boilerplate mencatat pesan yang berisi konten berdasarkan ada atau tidaknya fitur pada titik yang ditentukan.
7. Cobalah!
- Di dalam direktori
start_here
, jalankan perintah berikut:
$ ./gradlew installDist
Tindakan ini akan mengompilasi kode Anda, mengemasnya dalam jar, dan membuat skrip yang menjalankan contoh. File akan dibuat di direktori build/install/start_here/bin/
. Skripnya adalah: route-guide-server
dan route-guide-client
.
Server harus berjalan sebelum memulai klien.
- Jalankan server:
$ ./build/install/start_here/bin/route-guide-server
- Jalankan klien:
$ ./build/install/start_here/bin/route-guide-client
Anda akan melihat output seperti ini, dengan stempel waktu yang dihilangkan agar lebih jelas:
INFO: *** GetFeature: lat=409,146,138 lon=-746,188,906 INFO: Found feature called "Berkshire Valley Management Area Trail, Jefferson, NJ, USA" at 40.915, -74.619 INFO: *** GetFeature: lat=0 lon=0 INFO: Found no feature at 0, 0
8. Langkah berikutnya
- Pelajari cara kerja gRPC di Pengantar gRPC dan Konsep inti
- Pelajari tutorial Dasar-Dasar.
- Pelajari referensi API.