GRPC从使用到深入--服务的定义和使用

一、使用GRPC需要考虑的问题

忽略底层细节,从使用RPC的角度,最主要的就是要定义一个方法签名。这个方法,由服务端去实现,由客户端去调用。

因此我们关心一下几方面:

①方法的参数:决定了客户端要请求的数据;

②方法的返回值:决定了服务端要返回的数据;

③方法的名称:决定了RPC要实现什么功能;

从这个角度去看GRPC的文档,发现他的方法定义不太好理解。

我们先看一下官网给的案例:

syntax = "proto3";

service RouteGuide {

  // A simple RPC.
  rpc GetFeature(Point) returns (Feature) {}

  // A server-to-client streaming RPC.
  rpc ListFeatures(Rectangle) returns (stream Feature) {}

  // A client-to-server streaming RPC.
  rpc RecordRoute(stream Point) returns (RouteSummary) {}

  // A Bidirectional streaming RPC.
  rpc RouteChat(stream RouteNote) returns (stream RouteNote) {}
}

以上定义中

关键字rpc代表这是一个服务的定义

另外一个关键字 stream则是GRPC的重要特性。我们从客户端和服务端通信的角度去理解它

最简单的情况下:

这种情况很简单,但是如果客户端或者服务端之间的交互很频繁时,每次方法调用都要建立连接,所以开销比较大,GRPC考虑了这一点,所以需要再定义客户端和服务端是否为Stream。这四种定义方式带来的影响,我们通过GRPC生成的代码来分析。

1.1服务端代码分析

public static abstract class RouteGuideIMplBase {

public void getFeature(Point request,StreamObserver<Feature> responseObserver) {}

public void listFeatures(Rectangle request,StreamObserver<Feature> responseObserver){}

public StreamObserver<Point> recordRoute(StreamObserver<RouteSummary>responseObserver){}

public treamObserver<RouteNote> routeChat(StreamObserver<RouteNote> responseObserver){}

}

这是需要我们继承并实现的一个抽象类。从这四个方法签名去看,发现虽然服务定义有四种类型,但是生成的代码只有两种签名。

不管是否定义了Server-Stream,GRPC框架都为我们提供了一个responseObserver, 这是一个Stream<ResponseType>,服务端用它来返回相应数据。

至于Client-Stream,才是对方法签名产生影响的唯一因素:

未定义为Client-Stream: 这就是开头说的最简单的行式,客户端将请求数据一次性地发送给服务端,服务端则直接处理完数据,然后通过responseObserver返回处理结果即可。

定义了Client-Stream: 这种情况下,服务端无法知道请求数据何时到达,也不知道请求数据何时结束。因此GRPC框架要求我们自己实现一个处理请求流数据的Observer对象,即方法返回的StreamObserver<RequestType>类型对象。 返回的整个Observer对象会交给GRPC框架去调用。

1.2 客户端代码分析

生成的客户端代码相对来说复杂一些,因为GRPC为客户端生成了三种存根:

public static RouteGuideStub newStub(Channel channel) {
    return new RouteGuideStub(channel);
}

public static RouteGuideBlockingStub newBlockingStub(Channel channel) {
    return new RouteGuideBlockingStub(channel);
}

public static RouteGuideFutureStub newFutureStub(Channel channel) {
    return new RouteGuideFutureStub(channel);
}

这三种存根从名字也大概能猜出他们的功能

1.Stub:提供完全异步的方法

public static final class RouteGuideStub {

public void getFeature(Point request,StreamObserver<Feature> responseObserver){}

public void listFeatures(Rectangle request,StreamObserver<Feature> responseObserver){}

public StreamObserver<Point> recordRoute(StreamObserver<RouteSummary> responseObserver){}

public StreamObserver<RouteNote> routeChat(StreamObserver<RouteNote> responseObserver){}

}

客户端要使用Stub,必须要先实现自己的responseObserver,用来处理服务端返回的消息。

前面也说了,服务端的实现里面,响应数据都是以Stream的行式返回的,因此这部分很好理解。

区别仍然是Client-Stream部分。

1.未定义Client-Stream,则Stub直接将客户端准备好的数据放到前两个方法的参数中,然后调用方法

2.定义了Client-Stream,这说明Client无法一次性准备好请求数据,因此stub的后两个方法调用后,GRPC框架会返回一个Stream Observer<RequestType>,这个对象供客户端随时调用,发送Stream行式的数据。

2.BlockStub :提供完全同步的方法

public static final class RouteGuideBlockingStub{

  public Feature getFeature(Point request){……}

  public Iterator<Feature> listFeatures(Rectangle request){……}

}

可以看到,BlockStub只实现了定义Client-Stream的服务,这也很好理解,既然是同步方法,那就要求一次调用就结束。

唯一需要说明的是,同步方法也实现了Server-Stream,其实BlockStub是等服务端把数据都返回后,再一次性处理的,如果服务端一直没有完成响应数据的返回,那么listFeatures()方法会一直阻塞等待。

3.FutrueStub

public static final class RouteGuideFutureStub{

 public ListenableFuture<Feature> getFeature(Point request) {}

}

可以看到,FutureStub只实现了一个方法,它其实就是解决了BlockStub在处理Server-Stream的方法时阻塞的问题

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值