Pengantar gRPC

1. Perkenalan

gRPC adalah framework RPC open source berperforma tinggi yang awalnya dikembangkan oleh Google. Ini membantu dalam menghilangkan kode boilerplate dan membantu dalam menghubungkan layanan poliglot di dan di seluruh pusat data.

2. Ikhtisar

Kerangka kerja ini didasarkan pada model klien-server panggilan prosedur jarak jauh. Aplikasi klien bisa langsung memanggil metode pada aplikasi server seolah-olah itu adalah objek lokal.

Artikel ini akan menggunakan langkah-langkah berikut untuk membuat aplikasi server-klien biasa menggunakan gRPC:

  1. Tentukan layanan dalam file .proto
  2. Hasilkan kode server dan klien menggunakan kompilator buffer protokol
  3. Buat aplikasi server, terapkan antarmuka layanan yang dihasilkan, dan pemijahan server gRPC
  4. Buat aplikasi klien, lakukan panggilan RPC menggunakan stub yang dihasilkan

Mari kita definisikan HelloService sederhana yang mengembalikan salam sebagai ganti nama depan dan belakang.

3. Ketergantungan Maven

Mari tambahkan dependensi grpc-netty, grpc-protobuf dan grpc-stub:

 io.grpc grpc-netty 1.16.1   io.grpc grpc-protobuf 1.16.1   io.grpc grpc-stub 1.16.1  

4. Mendefinisikan Layanan

Kita mulai dengan mendefinisikan sebuah layanan, menentukan metode yang bisa dipanggil dari jarak jauh bersama dengan parameter dan tipe kembaliannya .

Ini dilakukan di file .proto menggunakan buffer protokol. Mereka juga digunakan untuk menjelaskan struktur pesan payload.

4.1. Konfigurasi Dasar

Mari kita buat file HelloService.proto untuk sampel HelloService kita . Kami mulai dengan menambahkan beberapa detail konfigurasi dasar:

syntax = "proto3"; option java_multiple_files = true; package org.baeldung.grpc;

Baris pertama memberi tahu kompiler sintaks apa yang digunakan dalam file ini. Secara default, kompilator menghasilkan semua kode Java dalam satu file Java. Baris kedua menggantikan pengaturan ini, dan semuanya akan dibuat dalam file individual.

Akhirnya, kami menentukan paket yang ingin kami gunakan untuk kelas Java yang kami buat.

4.2. Mendefinisikan Struktur Pesan

Selanjutnya, kami mendefinisikan pesan:

message HelloRequest { string firstName = 1; string lastName = 2; }

Ini mendefinisikan payload permintaan. Di sini setiap atribut yang masuk ke pesan ditentukan bersama dengan tipenya.

Sebuah nomor unik perlu diberikan ke setiap atribut, yang disebut sebagai tag. Tag ini digunakan oleh buffer protokol untuk mewakili atribut daripada menggunakan nama atribut.

Jadi, tidak seperti JSON di mana kita akan mengirimkan nama atribut firstName setiap saat, buffer protokol akan menggunakan angka 1 untuk mewakili firstName . Definisi payload respon mirip dengan permintaan.

Perhatikan bahwa kita dapat menggunakan tag yang sama di beberapa jenis pesan:

message HelloResponse { string greeting = 1; }

4.3. Mendefinisikan Kontrak Layanan

Terakhir, mari kita tentukan kontrak layanan. Untuk HelloService kami, kami mendefinisikan operasi hello () :

service HelloService { rpc hello(HelloRequest) returns (HelloResponse); }

Operasi hello () menerima permintaan unary dan mengembalikan respons unary. gRPC juga mendukung streaming dengan mengawali kata kunci streaming ke permintaan dan respons.

5. Menghasilkan Kode

Sekarang kita meneruskan file HelloService.proto ke protokol penyangga penyangga protoc untuk menghasilkan file Java. Ada banyak cara untuk memicu ini.

5.1. Menggunakan Protocol Buffer Compiler

Pertama, kita membutuhkan Protocol Buffer Compiler. Kita dapat memilih dari banyak binari prakompilasi yang tersedia di sini.

Selain itu, kita perlu mendapatkan Plugin Java Codegen gRPC.

Akhirnya, kita dapat menggunakan perintah berikut untuk menghasilkan kode:

protoc --plugin=protoc-gen-grpc-java=$PATH_TO_PLUGIN -I=$SRC_DIR --java_out=$DST_DIR --grpc-java_out=$DST_DIR $SRC_DIR/HelloService.proto

5.2. Menggunakan Plugin Maven

Sebagai pengembang, Anda ingin pembuatan kode terintegrasi erat dengan sistem build Anda. gRPC menyediakan plugin protobuf-maven untuk sistem build Maven:

   kr.motd.maven os-maven-plugin 1.6.1     org.xolstice.maven.plugins protobuf-maven-plugin 0.6.1   com.google.protobuf:protoc:3.3.0:exe:${os.detected.classifier}  grpc-java  io.grpc:protoc-gen-grpc-java:1.4.0:exe:${os.detected.classifier}      compile compile-custom      

Ekstensi / plugin os-maven-plugin menghasilkan berbagai properti proyek yang bergantung pada platform yang berguna seperti $ {os.detected.classifier}

6. Membuat Server

Terlepas dari metode mana yang Anda gunakan untuk pembuatan kode, file kunci berikut akan dibuat:

  • HelloRequest.java - berisi definisi tipe HelloRequest
  • HelloResponse.java - ini berisi definisi tipe HelleResponse
  • HelloServiceImplBase.java - ini berisi kelas abstrak HelloServiceImplBase yang menyediakan implementasi dari semua operasi yang kami tentukan di antarmuka layanan

6.1. Mengesampingkan Kelas Basis Layanan

The implementasi standar dari kelas abstrak HelloServiceImplBase adalah untuk membuang pengecualian runtime io.grpc.StatusRuntimeException mengatakan bahwa metode ini diimplementasikan.

We shall extend this class and override the hello() method mentioned in our service definition:

public class HelloServiceImpl extends HelloServiceImplBase { @Override public void hello( HelloRequest request, StreamObserver responseObserver) { String greeting = new StringBuilder() .append("Hello, ") .append(request.getFirstName()) .append(" ") .append(request.getLastName()) .toString(); HelloResponse response = HelloResponse.newBuilder() .setGreeting(greeting) .build(); responseObserver.onNext(response); responseObserver.onCompleted(); } }

If we compare the signature of hello() with the one we wrote in the HellService.proto file, we'll notice that it does not return HelloResponse. Instead, it takes the second argument as StreamObserver, which is a response observer, a call back for the server to call with its response.

This way the client gets an option to make a blocking call or a non-blocking call.

gRPC uses builders for creating objects. We use HelloResponse.newBuilder() and set the greeting text to build a HelloResponse object. We set this object to the responseObserver's onNext() method to send it to the client.

Finally, we need to call onCompleted() to specify that we’ve finished dealing with the RPC, else the connection will be hung, and the client will just wait for more information to come in.

6.2. Running the Grpc Server

Next, we need to start the gRPC server to listen for incoming requests:

public class GrpcServer { public static void main(String[] args) { Server server = ServerBuilder .forPort(8080) .addService(new HelloServiceImpl()).build(); server.start(); server.awaitTermination(); } }

Here, again we use the builder to create a gRPC server on port 8080 and add the HelloServiceImpl service that we defined. start() would start the server. In our example, we will call awaitTermination() to keep the server running in the foreground blocking the prompt.

7. Creating the Client

gRPC provides a channel construct that abstracts out the underlying details like connection, connection pooling, load balancing, etc.

We'll create a channel using ManagedChannelBuilder. Here, we specify the server address and port.

We'll be using plain text without any encryption:

public class GrpcClient { public static void main(String[] args) { ManagedChannel channel = ManagedChannelBuilder.forAddress("localhost", 8080) .usePlaintext() .build(); HelloServiceGrpc.HelloServiceBlockingStub stub = HelloServiceGrpc.newBlockingStub(channel); HelloResponse helloResponse = stub.hello(HelloRequest.newBuilder() .setFirstName("Baeldung") .setLastName("gRPC") .build()); channel.shutdown(); } }

Next, we need to create a stub which we'll use to make the actual remote call to hello(). The stub is the primary way for clients to interacts with the server. When using auto-generated stubs, the stub class will have constructors for wrapping the channel.

Here we're using a blocking/synchronous stub so that the RPC call waits for the server to respond, and will either return a response or raise an exception. There are two other types of stubs provided by gRPC, which facilitate non-blocking/asynchronous calls.

Akhirnya, waktunya untuk melakukan panggilan RPC hello () . Di sini kami melewati HelloRequest . Kita bisa menggunakan penyetel yang dibuat secara otomatis untuk menyetel atribut firstName , lastName dari objek HelloRequest .

Kami mendapatkan kembali objek HelloResponse yang dikembalikan dari server.

8. Kesimpulan

Dalam tutorial ini, kita melihat bagaimana kita dapat menggunakan gRPC untuk memudahkan pengembangan komunikasi antara dua layanan dengan berfokus pada mendefinisikan layanan dan membiarkan gRPC menangani semua kode boilerplate.

Seperti biasa, Anda akan menemukan sumbernya di GitHub.