写点什么

刨根问底系列之 grpc-java 入门

作者:零点999
  • 2022-12-26
    北京
  • 本文字数:5963 字

    阅读完需:约 20 分钟

介绍

  • google 开源的高性能且可以运行在任何环境的远程调用框架

  • gRPC-Java 支持 Java 8 及更高版本。

GPPC 背后的故事

  • 是 google 出品

  • 谷歌一直使用名为 Stubby 的单一通用 RPC 基础设施来连接在其数据中心内和跨数据中心运行的大量微服务

  • 2015 年 3 月,决定构建下一代版本 Stubby 并且开源,改名为 grpc,

使用者

  • Square

  • Netflix

  • Core os

  • Juniper networks

  • cisco

优点

  • 支持可插拔的身份验证、跟踪、负载平衡和健康检查

  • 可以跨平台,支持多种语言(11 种语言)

  • 基于 http/2 传输的双向流式传输

  • 使用 proto3 生成指定语言的数据结构、服务端接口以及客户端 Stub;

缺点

  • grpc 生态相对于 RESTful 还是比较小,因为浏览器和移动端对 grpc 支持 依然在初级阶段

  • grpc 不太直接适合面向外部通信,强类型来说有更多约束,向外提供接口的解决方案是配合网关使用


参考 https://zhuanlan.zhihu.com/p/436034072

例子

mvn 定义


<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">    <modelVersion>4.0.0</modelVersion>    <groupId>com.google.grpc</groupId>    <artifactId>grpc-java-learning</artifactId>    <packaging>jar</packaging>    <version>1.0-SNAPSHOT</version>    <name>grpc-java-learning</name>    <url>http://maven.apache.org</url>
<properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <os.detected.classifier>osx-x86_64</os.detected.classifier>
<protoc.version>3.21.7</protoc.version> <grpc.version>1.51.1</grpc.version>
<!-- required for JDK 8 --> <maven.compiler.source>1.8</maven.compiler.source> <maven.compiler.target>1.8</maven.compiler.target> </properties>
<dependencies> <dependency> <groupId>io.grpc</groupId> <artifactId>grpc-netty-shaded</artifactId> <version>${grpc.version}</version> <scope>runtime</scope> </dependency> <dependency> <groupId>io.grpc</groupId> <artifactId>grpc-protobuf</artifactId> <version>${grpc.version}</version> </dependency> <dependency> <groupId>io.grpc</groupId> <artifactId>grpc-stub</artifactId> <version>${grpc.version}</version> </dependency> <dependency> <groupId>com.google.protobuf</groupId> <artifactId>protobuf-java-util</artifactId> <version>3.21.7</version> </dependency> <dependency> <groupId>com.google.code.gson</groupId> <artifactId>gson</artifactId> <version>2.9.0</version> </dependency>
<dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <version>1.18.24</version> </dependency>
<dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.12</version> <scope>test</scope> </dependency> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <version>RELEASE</version> <scope>compile</scope> </dependency>
</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:${protoc.version}:exe:${os.detected.classifier} </protocArtifact> <clearOutputDirectory>false</clearOutputDirectory> <outputDirectory>src/main/java</outputDirectory> <pluginId>grpc-java</pluginId> <pluginArtifact>io.grpc:protoc-gen-grpc-java:${grpc.version}:exe:${os.detected.classifier} </pluginArtifact> </configuration> <executions> <execution> <goals> <goal>compile</goal> <goal>compile-custom</goal> </goals> </execution> </executions> </plugin> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-enforcer-plugin</artifactId> <version>1.4.1</version> <executions> <execution> <id>enforce</id> <goals> <goal>enforce</goal> </goals> <configuration> <rules> <requireUpperBoundDeps/> </rules> </configuration> </execution> </executions> </plugin> </plugins> </build>
</project>
复制代码


定义 protobuf 的协议类

syntax = "proto3";
option java_multiple_files = true;option java_package = "com.google.grpc.learning.helloworld";option java_outer_classname = "HelloWorldProto";option objc_class_prefix = "HLW";
package helloworld;
// The greeting service definition.service Greeter { // Sends a greeting rpc SayHello (HelloRequest) returns (HelloReply) {}}
// The request message containing the user's name.message HelloRequest { string name = 1;}
// The response message containing the greetingsmessage HelloReply { string message = 1;}
复制代码

生成 java 类

mvn -U clean compile
复制代码

服务提供者代码

package com.google.grpc.learning.helloworld.server;

import com.google.grpc.learning.helloworld.GreeterGrpc;import com.google.grpc.learning.helloworld.HelloReply;import com.google.grpc.learning.helloworld.HelloRequest;import io.grpc.Grpc;import io.grpc.InsecureServerCredentials;import io.grpc.Server;import io.grpc.stub.StreamObserver;
import java.io.IOException;import java.util.concurrent.TimeUnit;
/** * Server that manages startup/shutdown of a {@code Greeter} server. */public class HelloWorldServer {
private Server server;
private void start() throws IOException { /* The port on which the server should run */ int port = 50051; server = Grpc.newServerBuilderForPort(port, InsecureServerCredentials.create()) .addService(new GreeterImpl()) .build() .start(); System.out.println("Server started, listening on " + port); Runtime.getRuntime().addShutdownHook(new Thread() { @Override public void run() { // Use stderr here since the logger may have been reset by its JVM shutdown hook. System.err.println("*** shutting down gRPC server since JVM is shutting down"); try { HelloWorldServer.this.stop(); } catch (InterruptedException e) { e.printStackTrace(System.err); } System.err.println("*** server shut down"); } }); }
private void stop() throws InterruptedException { if (server != null) { server.shutdown().awaitTermination(30, TimeUnit.SECONDS); } }
/** * Await termination on the main thread since the grpc library uses daemon threads. */ private void blockUntilShutdown() throws InterruptedException { if (server != null) { server.awaitTermination(); } }
/** * Main launches the server from the command line. */ public static void main(String[] args) throws IOException, InterruptedException { final HelloWorldServer server = new HelloWorldServer(); server.start(); server.blockUntilShutdown(); }
static class GreeterImpl extends GreeterGrpc.GreeterImplBase {
@Override public void sayHello(HelloRequest req, StreamObserver<HelloReply> responseObserver) { HelloReply reply = HelloReply.newBuilder().setMessage("Hello " + req.getName()).build(); responseObserver.onNext(reply); responseObserver.onCompleted(); } }}
复制代码

消费者代码

package com.google.grpc.learning.helloworld.client;
import com.google.grpc.learning.helloworld.GreeterGrpc;import com.google.grpc.learning.helloworld.HelloReply;import com.google.grpc.learning.helloworld.HelloRequest;import com.google.grpc.learning.helloworld.server.HelloWorldServer;import io.grpc.Channel;import io.grpc.Grpc;import io.grpc.InsecureChannelCredentials;import io.grpc.ManagedChannel;import io.grpc.StatusRuntimeException;
import java.util.concurrent.TimeUnit;
/** * A simple client that requests a greeting from the {@link HelloWorldServer}. */public class HelloWorldClient {
private final GreeterGrpc.GreeterBlockingStub blockingStub;
/** Construct client for accessing HelloWorld server using the existing channel. */ public HelloWorldClient(Channel channel) { // 'channel' here is a Channel, not a ManagedChannel, so it is not this code's responsibility to // shut it down.
// Passing Channels to code makes code easier to test and makes it easier to reuse Channels. blockingStub = GreeterGrpc.newBlockingStub(channel); }
/** Say hello to server. */ public void greet(String name) { System.out.println("Will try to greet " + name + " ..."); HelloRequest request = HelloRequest.newBuilder().setName(name).build(); HelloReply response; try { response = blockingStub.sayHello(request); } catch (StatusRuntimeException e) { System.out.println( "RPC failed: "+ e.getStatus()); return; } System.out.println("Greeting: " + response.getMessage()); }
/** * Greet server. If provided, the first element of {@code args} is the name to use in the * greeting. The second argument is the target server. */ public static void main(String[] args) throws Exception { String user = "world"; // Access a service running on the local machine on port 50051 String target = "localhost:50051"; // Allow passing in the user and target strings as command line arguments if (args.length > 0) { if ("--help".equals(args[0])) { System.err.println("Usage: [name [target]]"); System.err.println(""); System.err.println(" name The name you wish to be greeted by. Defaults to " + user); System.err.println(" target The server to connect to. Defaults to " + target); System.exit(1); } user = args[0]; } if (args.length > 1) { target = args[1]; }
ManagedChannel channel = Grpc.newChannelBuilder(target, InsecureChannelCredentials.create()) .build(); try { HelloWorldClient client = new HelloWorldClient(channel); client.greet(user); } finally { // ManagedChannels use resources like threads and TCP connections. To prevent leaking these // resources the channel should be shut down when it will no longer be used. If it may be used // again leave it running. channel.shutdownNow().awaitTermination(5, TimeUnit.SECONDS); } }}
复制代码


代码位置:https://github.com/bee06/grpc-java-learning后面我们会根据例子的代码一步一步 debeg 看看内部的逻辑

参考资料

https://grpc.io/about/


https://grpc.io/blog/


https://zhuanlan.zhihu.com/p/436034072

用户头像

零点999

关注

还未添加个人签名 2018-01-19 加入

持续输出

评论

发布
暂无评论
刨根问底系列之grpc-java入门_零点999_InfoQ写作社区