1. Omówienie
gRPC to neutralna dla języka platforma i zbiór narzędzi opracowane przez Google do zdalnego wywoływania procedur (RPC). Umożliwia definiowanie usługi za pomocą buforów protokołów, czyli szczególnie zaawansowanych narzędzi i języka do serializacji plików binarnych. Następnie umożliwia generowanie idiomatycznych skrótów klientów i serwerów z definicji usługi w różnych językach.
Z tego ćwiczenia w programie dowiesz się, jak za pomocą platformy gRPC utworzyć usługę opartą na Javie, która udostępnia interfejs API, oraz jak napisać klienta, który będzie używał wygenerowanego fragmentu kodu gRPC po stronie klienta.
Czego się nauczysz
- język bufora protokołu
- Jak wdrożyć usługę gRPC za pomocą Javy
- Jak wdrożyć klienta gRPC za pomocą Javy
Jak wykorzystasz ten samouczek?
Jak oceniasz swoje doświadczenia z tworzeniem aplikacji Node.js?
Jak oceniasz swoje doświadczenia z tworzeniem aplikacji w języku Go?
2. Konfiguracja i wymagania
Samodzielne konfigurowanie środowiska
- Zaloguj się w konsoli Google Cloud i utwórz nowy projekt lub wykorzystaj już istniejący. Jeśli nie masz jeszcze konta Gmail ani Google Workspace, musisz je utworzyć.
Zapamiętaj identyfikator projektu, unikalną nazwę we wszystkich projektach Google Cloud (powyższa nazwa jest już zajęta i nie będzie Ci odpowiadać). W dalszej części tego ćwiczenia w Codelabs będzie ona określana jako PROJECT_ID
.
- Następnie musisz włączyć płatności w Cloud Console, aby korzystać z zasobów Google Cloud.
Ukończenie tego ćwiczenia z programowania nie powinno kosztować zbyt wiele. Postępuj zgodnie z instrukcjami podanymi w sekcji „Czyszczenie” W tym samouczku znajdziesz wskazówki, jak wyłączyć zasoby, aby uniknąć naliczania opłat. Nowi użytkownicy Google Cloud mogą skorzystać z programu bezpłatnego okresu próbnego o wartości 300 USD.
Google Cloud Shell,
Choć możesz wykonywać te ćwiczenia z programowania z poziomu Twojego komputera, w ramach tego ćwiczenia użyjemy Google Cloud Shell – środowiska wiersza poleceń działającego w Cloud.
Ta maszyna wirtualna oparta na Debianie zawiera wszystkie potrzebne narzędzia dla programistów. Zawiera stały katalog domowy o pojemności 5 GB i działa w Google Cloud, co znacznie zwiększa wydajność sieci i uwierzytelnianie. Oznacza to, że do tego ćwiczenia z programowania wystarczy przeglądarka (tak, działa ona na Chromebooku).
- Aby aktywować Cloud Shell z poziomu konsoli Cloud, kliknij Aktywuj Cloud Shell (udostępnienie środowiska i połączenie z nim powinno zająć tylko chwilę).
Po nawiązaniu połączenia z Cloud Shell powinno pojawić się potwierdzenie, że użytkownik jest już uwierzytelniony, a projekt jest już ustawiony na PROJECT_ID
.
gcloud auth list
Dane wyjściowe polecenia
Credentialed accounts: - <myaccount>@<mydomain>.com (active)
gcloud config list project
Dane wyjściowe polecenia
[core] project = <PROJECT_ID>
Jeśli z jakiegoś powodu projekt nie jest skonfigurowany, uruchom po prostu to polecenie:
gcloud config set project <PROJECT_ID>
Szukasz urządzenia PROJECT_ID
? Sprawdź identyfikator użyty w krokach konfiguracji lub wyszukaj go w panelu Cloud Console:
Cloud Shell ustawia też domyślnie niektóre zmienne środowiskowe, które mogą być przydatne podczas uruchamiania kolejnych poleceń.
echo $GOOGLE_CLOUD_PROJECT
Dane wyjściowe polecenia
<PROJECT_ID>
- Na koniec ustaw domyślną strefę i konfigurację projektu.
gcloud config set compute/zone us-central1-f
Możesz wybrać różne strefy. Więcej informacji znajdziesz w artykule Regiony i Strefy.
3. Tworzenie usługi gRPC
Utwórz nowy projekt Java w narzędziu Maven:
$ mvn archetype:generate -DgroupId=com.example.grpc \ -DartifactId=grpc-hello-server \ -DarchetypeArtifactId=maven-archetype-quickstart \ -DinteractiveMode=false $ cd grpc-hello-server
Dodaj plik definicji gRPC
W gRPC ładunki usługi (żądania i odpowiedzi) oraz operacje związane z usługą muszą być przechwytywane w języku IDL (Interface Definition Language). Do definiowania ładunków wiadomości i operacji w gRPC używa składni Protobuffer 3. Utwórzmy plik proto dla prostej usługi powitania z odpowiedziami Hello Request i Hello.
Najpierw utwórz nowy katalog proto, w którym będzie znajdować się nowy plik proto:
$ mkdir -p src/main/proto
Następnie utwórz nowy plik proto src/main/proto/GreetingService.proto
.
Aby edytować plik, możesz użyć vim,nano,
lub emacs
:
src/main/proto/GreetingService.proto
syntax = "proto3"; package com.example.grpc; // Request payload message HelloRequest { // Each message attribute is strongly typed. // You also must assign a "tag" number. // Each tag number is unique within the message. string name = 1; // This defines a strongly typed list of String repeated string hobbies = 2; // There are many more basics types, like Enum, Map // See https://developers.google.com/protocol-buffers/docs/proto3 // for more information. } message HelloResponse { string greeting = 1; } // Defining a Service, a Service can have multiple RPC operations service GreetingService { // Define a RPC operation rpc greeting(HelloRequest) returns (HelloResponse); }
Dodaj zależności gRPC i wtyczkę
Gdy będziesz już mieć definicję, będziemy mogli wygenerować z tego pliku wycinek po stronie serwera i kod po stronie klienta. Musisz dodać zależności i wtyczki gRPC.
Najpierw dodaj zależności gRPC do interfejsu pom.xml
:
pom.xml
<project> ... <dependencies> <dependency> <groupId>io.grpc</groupId> <artifactId>grpc-netty-shaded</artifactId> <version>1.24.0</version> </dependency> <dependency> <groupId>io.grpc</groupId> <artifactId>grpc-protobuf</artifactId> <version>1.24.0</version> </dependency> <dependency> <groupId>io.grpc</groupId> <artifactId>grpc-stub</artifactId> <version>1.24.0</version> </dependency> <dependency> <groupId>javax.annotation</groupId> <artifactId>javax.annotation-api</artifactId> <version>1.3.2</version> </dependency> ... </dependencies> ... </project>
Następnie dodaj wtyczkę:
pom.xml
<project> ... <dependencies> ... </dependencies> <build> <extensions> <extension> <groupId>kr.motd.maven</groupId> <artifactId>os-maven-plugin</artifactId> <version>1.6.2</version> </extension> </extensions> <plugins> <plugin> <groupId>org.xolstice.maven.plugins</groupId> <artifactId>protobuf-maven-plugin</artifactId> <version>0.6.1</version> <configuration> <protocArtifact>com.google.protobuf:protoc:3.9.0:exe:${os.detected.classifier}</protocArtifact> <pluginId>grpc-java</pluginId> <pluginArtifact>io.grpc:protoc-gen-grpc-java:1.24.0:exe:${os.detected.classifier}</pluginArtifact> </configuration> <executions> <execution> <goals> <goal>compile</goal> <goal>compile-custom</goal> </goals> </execution> </executions> </plugin> </plugins> </build> </project>
Wygeneruj częśćty
Gdy skompilujesz aplikację, wtyczka przekonwertuje definicje proto na kod w Javie.
$ mvn -DskipTests package
Aby wyświetlić wygenerowane pliki:
$ find target/generated-sources
Wdrażanie Usługi
Najpierw utwórz nową klasę GreetingServiceImpl
, która wdroży operację greeting
:
src/main/java/com/example/grpc/GreetingServiceImpl.java
package com.example.grpc; import io.grpc.stub.StreamObserver; public class GreetingServiceImpl extends GreetingServiceGrpc.GreetingServiceImplBase { @Override public void greeting(GreetingServiceOuterClass.HelloRequest request, StreamObserver<GreetingServiceOuterClass.HelloResponse> responseObserver) { // HelloRequest has toString auto-generated. System.out.println(request); // You must use a builder to construct a new Protobuffer object GreetingServiceOuterClass.HelloResponse response = GreetingServiceOuterClass.HelloResponse.newBuilder() .setGreeting("Hello there, " + request.getName()) .build(); // Use responseObserver to send a single response back responseObserver.onNext(response); // When you are done, you must call onCompleted. responseObserver.onCompleted(); } }
Wdrażanie serwera
Na koniec musisz uruchomić serwer, aby nasłuchiwać na porcie i zarejestrować tę implementację usługi. Edytuj klasę App
i jej główną metodę:
src/main/java/com/example/grpc/App.java
package com.example.grpc; import io.grpc.*; public class App { public static void main( String[] args ) throws Exception { // Create a new server to listen on port 8080 Server server = ServerBuilder.forPort(8080) .addService(new GreetingServiceImpl()) .build(); // Start the server server.start(); // Server threads are running in the background. System.out.println("Server started"); // Don't exit the main thread. Wait until server is terminated. server.awaitTermination(); } }
Na koniec uruchom serwer:
$ mvn -DskipTests package exec:java -Dexec.mainClass=com.example.grpc.App ... Server Started
4. Korzystanie z Usługi
Generator wygenerował już wszystkie atrapy po stronie klienta. Aby ułatwić korzystanie z modułu, użyjemy tego samego projektu Maven, ale po prostu dodamy nową klasę Client
z nową metodą główną.
Najpierw kliknij +, aby otworzyć nową sesję Cloud Shell, dzięki której nie będzie trzeba zamykać serwera:
W nowej sesji przejdź do katalogu grpc-hello-server
:
$ cd grpc-hello-server
Następnie dodaj nową klasę Client
:
src/main/java/com/example/grpc/Client.java
package com.example.grpc; import io.grpc.*; public class Client { public static void main( String[] args ) throws Exception { // Channel is the abstraction to connect to a service endpoint // Let's use plaintext communication because we don't have certs final ManagedChannel channel = ManagedChannelBuilder.forTarget("localhost:8080") .usePlaintext(true) .build(); // It is up to the client to determine whether to block the call // Here we create a blocking stub, but an async stub, // or an async stub with Future are always possible. GreetingServiceGrpc.GreetingServiceBlockingStub stub = GreetingServiceGrpc.newBlockingStub(channel); GreetingServiceOuterClass.HelloRequest request = GreetingServiceOuterClass.HelloRequest.newBuilder() .setName("Ray") .build(); // Finally, make the call using the stub GreetingServiceOuterClass.HelloResponse response = stub.greeting(request); System.out.println(response); // A Channel should be shutdown before stopping the process. channel.shutdownNow(); } }
Na koniec uruchom klienta:
$ mvn -DskipTests package exec:java -Dexec.mainClass=com.example.grpc.Client ... greeting: "Hello there, Ray"
Znakomicie. To całkiem proste, prawda?
5. Usługa strumieniowania
Możesz spróbować znacznie więcej. Aby na przykład łatwo utworzyć usługę strumieniowania, po prostu dodaj słowo kluczowe stream
w proto pliku do żądania lub odpowiedzi, np.
src/main/proto/GreetingService.proto
syntax = "proto3"; package com.example.grpc; ... // Defining a Service, a Service can have multiple RPC operations service GreetingService { // MODIFY HERE: Update the return to streaming return. rpc greeting(HelloRequest) returns (stream HelloResponse); }
Zaktualizuj serwer, aby wysyłał wiele odpowiedzi, a nie tylko jedną. Możesz to zrobić, nawiązując kilka wywołań funkcji responseObserver.onNext(...)
:
src/main/java/com/example/grpc/GreetingServiceImpl.java
package com.example.grpc; import io.grpc.stub.StreamObserver; public class GreetingServiceImpl extends GreetingServiceGrpc.GreetingServiceImplBase { @Override public void greeting(GreetingServiceOuterClass.HelloRequest request, StreamObserver<GreetingServiceOuterClass.HelloResponse> responseObserver) { ... // Feel free to construct different responses if you'd like. responseObserver.onNext(response); responseObserver.onNext(response); responseObserver.onNext(response); // When you are done, you must call onCompleted. responseObserver.onCompleted(); } }
Klient musi używać fragmentu kodu asynchronicznego zamiast fragmentu blokującego. Zaktualizuj kod klienta, zmieniając typ stub
na GreetingServiceStub
:
src/main/java/com/example/grpc/Client.java
package com.example.grpc; import io.grpc.*; // New import import io.grpc.stub.*; public class Client { public static void main( String[] args ) throws Exception { final ManagedChannel channel = ManagedChannelBuilder.forTarget("localhost:8080") .usePlaintext(true) .build(); // Replace the previous synchronous code with asynchronous code. // This time use an async stub: GreetingServiceGrpc.GreetingServiceStub stub = GreetingServiceGrpc.newStub(channel); // Construct a request GreetingServiceOuterClass.HelloRequest request = GreetingServiceOuterClass.HelloRequest.newBuilder() .setName("Ray") .build(); // Make an Asynchronous call. Listen to responses w/ StreamObserver stub.greeting(request, new StreamObserver<GreetingServiceOuterClass.HelloResponse>() { public void onNext(GreetingServiceOuterClass.HelloResponse response) { System.out.println(response); } public void onError(Throwable t) { } public void onCompleted() { // Typically you'll shutdown the channel somewhere else. // But for the purpose of the lab, we are only making a single // request. We'll shutdown as soon as this request is done. channel.shutdownNow(); } }); } }
Ponownie skompiluj aplikację:
$ mvn -DskipTests package
Uruchom ponownie serwer i klienta w osobnej sesji Cloud Shell.
Aby uruchomić serwer:
$ mvn exec:java -Dexec.mainClass=com.example.grpc.App ... Server Started
Aby uruchomić klienta:
$ mvn exec:java -Dexec.mainClass=com.example.grpc.Client ... greeting: "Hello there, Ray" greeting: "Hello there, Ray" greeting: "Hello there, Ray"
6. Gratulacje!
Omówione zagadnienia:
- język bufora protokołu
- Jak wdrożyć serwer gRPC za pomocą Javy
- Jak wdrożyć klienta gRPC za pomocą Javy
Dalsze kroki:
- Dowiedz się więcej o języku Java gRPC.
- Zobacz więcej przykładów kodu Java gRPC na GitHubie
- Dowiedz się więcej o przesyłaniu strumieniowym w gRPC.
- Dowiedz się więcej o transkodowaniu gRPC na REST.
Prześlij nam swoją opinię
- Poświęć chwilę na wypełnienie naszej bardzo krótkiej ankiety