加入收藏 | 设为首页 | 会员中心 | 我要投稿 濮阳站长网 (https://www.0393zz.cn/)- 专属主机、数据湖、操作系统、媒体智能、数据分析!
当前位置: 首页 > 云计算 > 正文

五分钟学会 gRPC,你学会了吗?

发布时间:2022-07-06 09:25:37 所属栏目:云计算 来源:互联网
导读:介绍 我猜测大部分长期使用 Java 的开发者应该较少会接触 gRPC,毕竟在 Java 圈子里大部分使用的还是 Dubbo/SpringClound 这两类服务框架。 我也是近段时间有机会从零开始重构业务才接触到 gRPC 的,当时选择gRPC 时也有几个原因: 基于云原生的思路开发部署
  介绍
  我猜测大部分长期使用 Java 的开发者应该较少会接触 gRPC,毕竟在 Java 圈子里大部分使用的还是 Dubbo/SpringClound 这两类服务框架。
 
  我也是近段时间有机会从零开始重构业务才接触到 gRPC 的,当时选择gRPC 时也有几个原因:
 
 
 
  基于云原生的思路开发部署项目,而在云原生中 gRPC 几乎已经是标准的通讯协议了。
  开发语言选择了 Go,在 Go 圈子中 gRPC 显然是更好的选择。
  公司内部有部分业务使用的是 Python 开发,在多语言兼容性上 gRPC 支持的非常好。
  经过线上一年多的平稳运行,可以看出 gRPC 还是非常稳定高效的;rpc 框架中最核心的几个要点:
 
  序列化
  通信协议
  IDL(接口描述语言)
  这些在 gRPC 中分别对应的是:
 
  基于 Protocol Buffer 序列化协议,性能高效。
  基于 HTTP/2 标准协议开发,自带 stream、多路复用等特性;同时由于是标准协议,第三方工具的兼容性会更好(比如负载均衡、监控等)。
  编写一份 .proto 接口文件,便可生成常用语言代码。
  HTTP/2
  学习 gRPC 之前首先得知道它是通过什么协议通信的,我们日常不管是开发还是应用基本上接触到最多的还是 HTTP/1.1 协议。
 
 
 
  由于 HTTP/1.1 是一个文本协议,对人类非常友好,相反的对机器性能就比较低。
 
  需要反复对文本进行解析,效率自然就低了;要对机器更友好就得采用二进制,HTTP/2 自然做到了。
 
  除此之外还有其他优点:
 
  多路复用:可以并行的收发消息,互不影响。
  HPACK 节省 header 空间,避免 HTTP1.1 对相同的 header 反复发送。
  Protocol
  gRPC 采用的是 Protocol 序列化,发布时间比 gRPC 早一些,所以也不仅只用于 gRPC,任何需要序列化 IO 操作的场景都可以使用它。
 
  它会更加的省空间、高性能;之前在开发 https://github.com/crossoverJie/cim 时就使用它来做数据交互。
 
  复制
  package order.v1;
 
  service OrderService{
 
    rpc Create(OrderApiCreate) returns (Order) {}
 
    rpc Close(CloseApiCreate) returns (Order) {}
 
    // 服务端推送
    rpc ServerStream(OrderApiCreate) returns (stream Order) {}
 
    // 客户端推送
    rpc ClientStream(stream OrderApiCreate) returns (Order) {}
    
    // 双向推送
    rpc BdStream(stream OrderApiCreate) returns (stream Order) {}
  }
 
  message OrderApiCreate{
    int64 order_id = 1;
    repeated int64 user_id = 2;
    string remark = 3;
    repeated int32 reason_id = 4;
  }
  1.
  2.
  3.
  4.
  5.
  6.
  7.
  8.
  9.
  10.
  11.
  12.
  13.
  14.
  15.
  16.
  17.
  18.
  19.
  20.
  21.
  22.
  23.
  24.
  使用起来也是非常简单的,只需要定义自己的 .proto 文件,便可用命令行工具生成对应语言的 SDK。
 
  具体可以参考官方文档:https://grpc.io/docs/languages/go/generated-code/
 
  调用
  复制
   protoc --go_out=. --go_opt=paths=source_relative
      --go-grpc_out=. --go-grpc_opt=paths=source_relative
      test.proto
  1.
  2.
  3.
 
 
  生成代码之后编写服务端就非常简单了,只需要实现生成的接口即可。
 
  复制
  func (o *Order) Create(ctx context.Context, in *v1.OrderApiCreate) (*v1.Order, error) {
   // 获取 metadata
   md, ok := metadata.FromIncomingContext(ctx)
   if !ok {
    return nil, status.Errorf(codes.DataLoss, "failed to get metadata")
   }
   fmt.Println(md)
   fmt.Println(in.OrderId)
   return &v1.Order{
    OrderId: in.OrderId,
    Reason:  nil,
   }, nil
  }
  1.
  2.
  3.
  4.
  5.
  6.
  7.
  8.
  9.
  10.
  11.
  12.
  13.
 
 
  客户端也非常简单,只需要依赖服务端代码,创建一个 connection 然后就和调用本地方法一样了。
 
  这是经典的 unary(一元)调用,类似于 http 的请求响应模式,一个请求对应一次响应。
 
 
 
  Server stream
  gRPC 除了常规的 unary 调用之外还支持服务端推送,在一些特定场景下还是很有用的。
 
 
 
  复制
  func (o *Order) ServerStream(in *v1.OrderApiCreate, rs v1.OrderService_ServerStreamServer) error {
   for i := 0; i < 5; i++ {
    rs.Send(&v1.Order{
     OrderId: in.OrderId,
     Reason:  nil,
    })
   }
   return nil
  }
  1.
  2.
  3.
  4.
  5.
  6.
  7.
  8.
  9.
  服务端的推送如上所示,调用 Send 函数便可向客户端推送。
 
  复制
   for {
    msg, err := rpc.RecvMsg()
    if err == io.EOF {
     marshalIndent, _ := json.MarshalIndent(msgs, "", "t")
     fmt.Println(msg)
     return
    }
   }
  1.
  2.
  3.
  4.
  5.
  6.
  7.
  8.
  客户端则通过一个循环判断当前接收到的数据包是否已经截止来获取服务端消息。
 
  为了能更直观的展示这个过程,优化了之前开发的一个 gRPC 客户端,可以直观的调试 stream 调用。

(编辑:濮阳站长网)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读