1. Descripción general
gRPC es un conjunto de herramientas y marco de trabajo de llamada de procedimiento remoto (RPC) independiente del lenguaje y de la plataforma desarrollados en Google. Te permite definir un servicio mediante búferes de protocolo, un lenguaje y un conjunto de herramientas de serialización binario potentes. Luego, te permite generar stubs de cliente y servidor idiomáticos a partir de la definición de tu servicio en una variedad de lenguajes.
En este codelab, aprenderás a compilar un servicio basado en Java que exponga una API con el framework de gRPC y, luego, escribirás un cliente para usar el stub generado del cliente de gRPC.
Qué aprenderás
- El lenguaje del búfer de protocolo
- Cómo implementar un servicio de gRPC con Java
- Cómo implementar un cliente de gRPC con Java
¿Cómo usarás este instructivo?
¿Cómo calificarías tu experiencia con la compilación de apps de Node.js?
¿Cómo calificarías tu experiencia con la compilación de apps de Go?
2. Configuración y requisitos
Configuración del entorno de autoaprendizaje
- Accede a la consola de Cloud y crea un proyecto nuevo o reutiliza uno existente. Si aún no tienes una cuenta de Gmail o de Google Workspace, debes crear una.
Recuerde el ID de proyecto, un nombre único en todos los proyectos de Google Cloud (el nombre anterior ya se encuentra en uso y no lo podrá usar). Se mencionará más adelante en este codelab como PROJECT_ID
.
- A continuación, deberás habilitar la facturación en la consola de Cloud para usar los recursos de Google Cloud recursos.
Ejecutar este codelab no debería costar mucho, tal vez nada. Asegúrate de seguir las instrucciones de la sección “Realiza una limpieza” en la que se aconseja cómo cerrar recursos para no incurrir en facturación más allá de este instructivo. Los usuarios nuevos de Google Cloud son aptos para participar en el programa Prueba gratuita de$300.
Google Cloud Shell
Si bien este codelab se puede operar desde tu computadora, en él usaremos Google Cloud Shell, un entorno de línea de comandos que se ejecuta en la nube.
Esta máquina virtual basada en Debian está cargada con todas las herramientas de desarrollo que necesitarás. Ofrece un directorio principal persistente de 5 GB y se ejecuta en Google Cloud, lo que permite mejorar considerablemente el rendimiento de la red y la autenticación. Esto significa que todo lo que necesitarás para este Codelab es un navegador (sí, funciona en una Chromebook).
- Para activar Cloud Shell desde la consola de Cloud, solo haz clic en Activar Cloud Shell (el aprovisionamiento y la conexión al entorno debería llevar solo unos minutos).
Una vez conectado a Cloud Shell, debería ver que ya se autenticó y que el proyecto ya se configuró con tu PROJECT_ID
:
gcloud auth list
Resultado del comando
Credentialed accounts: - <myaccount>@<mydomain>.com (active)
gcloud config list project
Resultado del comando
[core] project = <PROJECT_ID>
Si, por algún motivo, el proyecto no está configurado, solo emite el siguiente comando:
gcloud config set project <PROJECT_ID>
Si no conoce su PROJECT_ID
, Observa el ID que usaste en los pasos de configuración o búscalo en el panel de la consola de Cloud:
Cloud Shell también configura algunas variables de entorno de forma predeterminada, lo que puede resultar útil cuando ejecutas comandos futuros.
echo $GOOGLE_CLOUD_PROJECT
Resultado del comando
<PROJECT_ID>
- Establece la zona predeterminada y la configuración del proyecto.
gcloud config set compute/zone us-central1-f
Puedes elegir una variedad de zonas diferentes. Para obtener más información, consulta Regiones y zonas.
3. Crea un Service de gRPC
Crea un nuevo proyecto de Java con Maven:
$ mvn archetype:generate -DgroupId=com.example.grpc \ -DartifactId=grpc-hello-server \ -DarchetypeArtifactId=maven-archetype-quickstart \ -DinteractiveMode=false $ cd grpc-hello-server
Agrega un archivo de definición de gRPC
En gRPC, las cargas útiles del servicio (solicitud y respuesta) y las operaciones del servicio deben capturarse en un IDL (lenguaje de definición de la interfaz). gRPC usa la sintaxis de Protobuffer 3 para definir cargas útiles y operaciones de mensajes. Creemos un archivo .proto para un servicio de saludo simple con una solicitud “Hello” y una respuesta “Hello”.
Primero, crea un directorio proto nuevo que contenga el archivo proto nuevo:
$ mkdir -p src/main/proto
Luego, crea un nuevo archivo proto src/main/proto/GreetingService.proto
.
Puedes usar vim,nano,
o emacs
para editar el archivo:
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); }
Agrega dependencias y complementos de gRPC
Una vez que tengas la definición, podremos generar el stub del servidor y el stub del cliente a partir de este archivo. Deberás agregar las dependencias y los complementos de gRPC.
Primero, agrega las dependencias de gRPC a 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>
Luego, agrega el complemento:
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>
Cómo generar los stubs
Cuando compiles la aplicación, el complemento convertirá las definiciones de proto en código Java.
$ mvn -DskipTests package
Para ver los archivos generados, haz lo siguiente:
$ find target/generated-sources
Implementar el servicio
Primero, crea una nueva clase GreetingServiceImpl
que implemente la operación 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(); } }
Implementa el servidor
Por último, deberás iniciar un servidor para escuchar en un puerto y registrar esta implementación de servicio. Edita la clase App
y su método principal:
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(); } }
Por último, ejecuta el servidor:
$ mvn -DskipTests package exec:java -Dexec.mainClass=com.example.grpc.App ... Server Started
4. Consumo del Servicio
El generador ya generó todos los stubs del cliente. Para simplificar el lab, usaremos el mismo proyecto de Maven, pero solo agregaremos una nueva clase Client
con un método principal nuevo.
Primero, haz clic en + para abrir una nueva sesión de Cloud Shell de modo que no necesites finalizar el servidor:
En la sesión nueva, cambia al directorio grpc-hello-server
:
$ cd grpc-hello-server
Luego, agrega la clase Client
nueva:
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(); } }
Por último, ejecuta el cliente:
$ mvn -DskipTests package exec:java -Dexec.mainClass=com.example.grpc.Client ... greeting: "Hello there, Ray"
Eso es todo. Es fácil, ¿verdad?
5. Servicio de transmisión
Hay mucho más que puedes probar. Por ejemplo, puedes compilar un servicio de transmisión con facilidad agregando la palabra clave stream
en el archivo proto a la solicitud o al parámetro de respuesta, p.ej.,
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); }
Actualiza tu servidor para que envíe varias respuestas en lugar de solo una. Para hacerlo, realiza varias llamadas a 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(); } }
El cliente debe usar un stub asíncrono en lugar del stub de bloqueo. Actualiza el código del cliente y asegúrate de actualizar el tipo stub
a 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(); } }); } }
Vuelve a compilar la aplicación:
$ mvn -DskipTests package
Reinicia el servidor y el cliente, cada uno en su propia sesión de Cloud Shell.
Para iniciar el servidor, sigue estos pasos:
$ mvn exec:java -Dexec.mainClass=com.example.grpc.App ... Server Started
Para iniciar el cliente, haz lo siguiente:
$ mvn exec:java -Dexec.mainClass=com.example.grpc.Client ... greeting: "Hello there, Ray" greeting: "Hello there, Ray" greeting: "Hello there, Ray"
6. ¡Felicitaciones!
Temas abordados:
- El lenguaje del búfer de protocolo
- Cómo implementar un servidor de gRPC con Java
- Cómo implementar un cliente de gRPC con Java
Próximos pasos:
- Obtén más información sobre Java de gRPC.
- Consulta más ejemplos de Java de gRPC en GitHub.
- Obtén información sobre la transmisión en gRPC.
- Obtén más información sobre la transcodificación de gRPC a REST.
Envíanos tus comentarios
- Tómate un momento para completar nuestra breve encuesta