Grpc概述
发布日期:2021-05-16 10:23:23 浏览次数:8 分类:技术文章

本文共 6597 字,大约阅读时间需要 21 分钟。

前言

gRPC 是一个高性能、开源和通用的 RPC 框架,面向移动和 《》 设计。目前提供 C、Java 和 Go 语言版本。

快速开始

主要分为以下几个步骤

引入依赖及插件

grpc对《》的插件进行扩展,生成客户端,服务端的基础部份

io.grpc
grpc-all
1.36.0
kr.motd.maven
os-maven-plugin
1.6.2
org.xolstice.maven.plugins
protobuf-maven-plugin
0.6.1
true
${project.basedir}/src/main/resources/proto
true
com.google.protobuf:protoc:3.12.0:exe:${os.detected.classifier}
grpc-java
io.grpc:protoc-gen-grpc-java:1.36.0:exe:${os.detected.classifier}
generate-sources
compile
compile-custom
编写proto文件并生成

定义了接口,参数类型,返回值

syntax = "proto3";option java_multiple_files = true;option java_package = "grpc";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;}

在这里插入图片描述

基于生成类编写两端
// 服务端public class HelloWorldServer {
private static final Logger logger = Logger.getLogger(HelloWorldServer.class.getName()); private Server server; private void start() throws IOException {
/* The port on which the server should run */ int port = 50051; server = ServerBuilder.forPort(port) .addService(new GreeterImpl()) .build() .start(); logger.info("Server started, listening on " + port); Runtime.getRuntime().addShutdownHook(new Thread() {
@Override public void run() {
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); } } private void blockUntilShutdown() throws InterruptedException {
if (server != null) {
server.awaitTermination(); } } 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
responseObserver) {
HelloReply reply = HelloReply.newBuilder().setMessage("Hello " + req.getName()).build(); responseObserver.onNext(reply); responseObserver.onCompleted(); } }}public class HelloWorldClient {
private static final Logger logger = Logger.getLogger(HelloWorldClient.class.getName()); private final GreeterGrpc.GreeterBlockingStub blockingStub; public HelloWorldClient(Channel channel) {
blockingStub = GreeterGrpc.newBlockingStub(channel); } public void greet(String name) {
logger.info("Will try to greet " + name + " ..."); HelloRequest request = HelloRequest.newBuilder().setName(name).build(); HelloReply response; try {
response = blockingStub.sayHello(request); } catch (StatusRuntimeException e) {
logger.log(Level.WARNING, "RPC failed: {0}", e.getStatus()); return; } logger.info("Greeting: " + response.getMessage()); } public static void main(String[] args) throws Exception {
String user = "world"; String target = "localhost:50051"; // 连接服务端并创建管道 ManagedChannel channel = ManagedChannelBuilder.forTarget(target) .usePlaintext() .build(); try {
// 创建客户端 HelloWorldClient client = new HelloWorldClient(channel); // 客户端的请求接口 client.greet(user); } finally {
channel.shutdownNow().awaitTermination(5, TimeUnit.SECONDS); } }}

Grpc原理

RPC 框架的目标就是让远程服务调用更加简单,服务调用者可以像调用本地接口一样调用远程的服务提供者,而不需要关心底层通信细节和调用过程.

在这里插入图片描述

GRPC的Client与Server,对我们封装了,通过Netty Channel数据通信及Protobuf序列化、反序列化的过程。

Server端

gRPC 服务端创建采用 Build 模式,对底层服务绑定、transportServer 和 NettyServer 的创建和实例化做了封装和屏蔽。

在这里插入图片描述
NettyServer中利用NettyServerHandler实现》中的FrameListener.接入http2.0协议。

在这里插入图片描述

client端

Grpc使用ManagedChannelBuilder来创建客户端channel,ManagedChannel是客户端最核心的类,它表示逻辑上的一个channel.

每个Service客户端,都生成了2种stub:BlockingStub和FutureStub;这两个Stub内部调用过程几乎一样,唯一不同的是BlockingStub的方法直接返回Response Model,而FutureStub返回一个Future对象。其中BlockingStub内部也是基于Future机制,只是封装了阻塞等待的过程:

public static 
RespT blockingUnaryCall( Channel channel, MethodDescriptor
method, CallOptions callOptions, ReqT param) {
ThreadlessExecutor executor = new ThreadlessExecutor(); ClientCall
call = channel.newCall(method, callOptions.withExecutor(executor)); try {
//也是基于Future ListenableFuture
responseFuture = futureUnaryCall(call, param); //阻塞过程 while (!responseFuture.isDone()) {
try {
executor.waitAndDrain(); } catch (InterruptedException e) {
Thread.currentThread().interrupt(); throw Status.CANCELLED.withCause(e).asRuntimeException(); } } return getUnchecked(responseFuture); } catch (Throwable t) {
call.cancel(null, t); throw t instanceof RuntimeException ? (RuntimeException) t : new RuntimeException(t); } }
调用过程
  1. 服务端启动时,会对调用addService方法,会把service保存在内部的一个map中,key为serviceName
  2. Client在调用时会将调用的service名称 + method信息保存在一个GRPC“保留”的header中,那么Server端即可通过获取这个特定的header信息,就可以得知此stream需要请求的service、以及其method,那么接下来只需要从上述提到的map中找到service,然后找到此method,直接代理调用即可

主要参考

《》

转载地址:https://blog.csdn.net/y3over/article/details/114603187 如侵犯您的版权,请留言回复原文章的地址,我们会给您删除此文章,给您带来不便请您谅解!

上一篇:dubbo之SPI
下一篇:http2概述

发表评论

最新留言

做的很好,不错不错
[***.243.131.199]2024年03月31日 05时43分53秒