1. Обзор
gRPC — это инфраструктура и набор инструментов удаленного вызова процедур (RPC), не зависящие от языка и платформы, разработанные в Google. Он позволяет определить службу с помощью протокольных буферов — особенно мощного набора инструментов и языка двоичной сериализации. Затем он позволяет генерировать идиоматические клиентские и серверные заглушки на основе определения вашего сервиса на различных языках.
В этой лаборатории кода вы узнаете, как создать службу на основе Java, которая предоставляет API с использованием инфраструктуры gRPC, а затем написать клиент для использования сгенерированной клиентской заглушки gRPC.
Что вы узнаете
- Язык буфера протокола
- Как реализовать службу gRPC с помощью Java
- Как реализовать клиент gRPC с помощью Java
Как вы будете использовать это руководство?
Как бы вы оценили свой опыт создания приложений Node.js?
Как бы вы оценили свой опыт создания приложений Go?
2. Настройка и требования
Самостоятельная настройка среды
- Войдите в Cloud Console и создайте новый проект или повторно используйте существующий. Если у вас еще нет учетной записи Gmail или Google Workspace, вам необходимо ее создать .
Запомните идентификатор проекта — уникальное имя для всех проектов Google Cloud (имя, указанное выше, уже занято и не подойдет вам, извините!). Позже в этой лаборатории он будет называться PROJECT_ID
.
- Далее вам необходимо включить биллинг в Cloud Console, чтобы использовать ресурсы Google Cloud.
Прохождение этой лаборатории кода не должно стоить много, если вообще стоит. Обязательно следуйте всем инструкциям в разделе «Очистка», в которых рассказывается, как отключить ресурсы, чтобы вам не приходилось нести расходы, выходящие за рамки этого руководства. Новые пользователи Google Cloud имеют право на участие в программе бесплатной пробной версии стоимостью 300 долларов США .
Google Cloud Shell
Хотя этой лабораторией кода можно управлять с вашего компьютера, в ней мы будем использовать Google Cloud Shell , среду командной строки, работающую в облаке.
Эта виртуальная машина на базе Debian оснащена всеми необходимыми инструментами разработки. Он предлагает постоянный домашний каталог объемом 5 ГБ и работает в Google Cloud, что значительно повышает производительность сети и аутентификацию. Это означает, что все, что вам понадобится для этой лаборатории кода, — это браузер (да, он работает на Chromebook).
- Чтобы активировать Cloud Shell из Cloud Console, просто нажмите «Активировать Cloud Shell». (подготовка и подключение к среде займет всего несколько минут).
После подключения к Cloud Shell вы увидите, что вы уже прошли аутентификацию и что для проекта уже установлен ваш PROJECT_ID
.
gcloud auth list
Вывод команды
Credentialed accounts: - <myaccount>@<mydomain>.com (active)
gcloud config list project
Вывод команды
[core] project = <PROJECT_ID>
Если по какой-то причине проект не установлен, просто введите следующую команду:
gcloud config set project <PROJECT_ID>
Ищете свой PROJECT_ID
? Узнайте, какой идентификатор вы использовали на этапах настройки, или найдите его на панели управления Cloud Console:
Cloud Shell также по умолчанию устанавливает некоторые переменные среды, которые могут быть полезны при выполнении будущих команд.
echo $GOOGLE_CLOUD_PROJECT
Вывод команды
<PROJECT_ID>
- Наконец, установите зону по умолчанию и конфигурацию проекта.
gcloud config set compute/zone us-central1-f
Вы можете выбрать множество различных зон. Дополнительную информацию см. в разделе «Регионы и зоны» .
3. Создайте службу gRPC.
Создайте новый проект Java с помощью Maven:
$ mvn archetype:generate -DgroupId=com.example.grpc \ -DartifactId=grpc-hello-server \ -DarchetypeArtifactId=maven-archetype-quickstart \ -DinteractiveMode=false $ cd grpc-hello-server
Добавьте файл определения gRPC
В gRPC полезные данные службы (запрос и ответ) и операции службы должны быть зафиксированы в IDL (языке определения интерфейса). gRPC использует синтаксис Protobuffer 3 для определения полезных данных и операций сообщений. Давайте создадим файл прототипа для простой службы приветствия с запросом приветствия и ответом приветствия.
Сначала создайте новый каталог proto для хранения нового файла proto:
$ mkdir -p src/main/proto
Затем создайте новый файл прототипа src/main/proto/GreetingService.proto
.
Вы можете использовать vim,nano,
или 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); }
Добавьте зависимости и плагин gRPC
Получив определение, мы можем создать из этого файла как серверную, так и клиентскую заглушку. Вам нужно будет добавить зависимости и плагины gRPC.
Сначала добавьте зависимости gRPC в 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>
Затем добавьте плагин:
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>
Создание заглушек
Когда вы создаете приложение, плагин преобразует определения прототипа в код Java.
$ mvn -DskipTests package
Чтобы просмотреть сгенерированные файлы:
$ find target/generated-sources
Внедрить услугу
Сначала создайте новый класс GreetingServiceImpl
, который будет реализовывать операцию 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(); } }
Реализация сервера
Наконец, вам нужно запустить сервер для прослушивания порта и зарегистрировать эту реализацию службы. Отредактируйте класс App
и его основной метод:
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(); } }
Наконец, запустите сервер:
$ mvn -DskipTests package exec:java -Dexec.mainClass=com.example.grpc.App ... Server Started
4. Использование сервиса
Генератор уже сгенерировал все заглушки на стороне клиента. Для простоты лабораторной работы мы будем использовать тот же проект Maven, но просто добавим новый класс Client
с новым основным методом.
Сначала нажмите + , чтобы открыть новый сеанс Cloud Shell, чтобы вам не приходилось завершать работу сервера:
В новом сеансе переключитесь в каталог grpc-hello-server
:
$ cd grpc-hello-server
Затем добавьте новый класс 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(); } }
Наконец, запустите клиент:
$ mvn -DskipTests package exec:java -Dexec.mainClass=com.example.grpc.Client ... greeting: "Hello there, Ray"
Вот и все! Довольно просто, правда?
5. Стриминговый сервис
Вы можете попробовать еще много всего. Например, вы можете легко создать службу потоковой передачи, просто добавив ключевое слово stream
в файле прототипа либо к параметру запроса, либо к параметру ответа, например
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); }
Обновите свой сервер, чтобы он отправлял несколько ответов, а не один. Вы можете сделать это, выполнив несколько вызовов 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(); } }
Клиент должен использовать асинхронную заглушку вместо блокирующей заглушки. Обновите клиентский код, обязательно обновив тип stub
на 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(); } }); } }
Пересоберите приложение:
$ mvn -DskipTests package
Перезапустите сервер и клиент каждый в своем сеансе Cloud Shell.
Чтобы запустить сервер:
$ mvn exec:java -Dexec.mainClass=com.example.grpc.App ... Server Started
Чтобы запустить клиент:
$ mvn exec:java -Dexec.mainClass=com.example.grpc.Client ... greeting: "Hello there, Ray" greeting: "Hello there, Ray" greeting: "Hello there, Ray"
6. Поздравляем!
Что мы рассмотрели:
- Язык буфера протокола
- Как реализовать сервер gRPC с помощью Java
- Как реализовать клиент gRPC с помощью Java
Следующие шаги:
- Узнайте больше о gRPC Java
- Дополнительные примеры gRPC Java см. на GitHub.
- Узнайте о потоковой передаче в gRPC
- Узнайте больше о перекодировании gRPC в REST.
Оставьте нам свой отзыв
- Пожалуйста, уделите немного времени и заполните наш очень короткий опрос.