grpc学习笔记

RPC简介

  • 远程过程调用(Remote Procedure Call,RPC)是一个计算机通信协议。该协议允许运行于一台计算机的程序调用另一台计算机的子程序,而程序员无需额外地为这个交互作用编程。

RPC的优点

  • 提高开发效率,编程时将精力集中在具体接口的实现,不必考虑数据的底层传输
  • Client端和Server端遵循统一的接口规范,大多数RPC框架提供跨语言的调用
  • 使用了HTTP/2,继而提供了连接多路复用、Body 和 Header 压缩等机制。可以节省带宽、降低TCP链接次数、节省CPU使用和延长电池寿命等。,
  • 使用了protocol buffer ,序列化和反序列化的效率较高

RPC的缺点

  • RPC比较适合微服务,不适合复杂的多模块交互。
  • 性能开销较大,网络出现问题的时候不容易debug
  • 异常处理困难。
    • 同步调用发生长时间阻塞
    • 异步调用超时该如何处理
    • 调用失败是否可以重试

gPRC

  • gPRC 简介

    • GRPC是一个高性能、开源和通用的RPC框架。基于HTTP/2协议标准,使用 Proto Buffers 作为接口描述语言(interface description language,IDL),并提供诸如认证、全双工流和流控制,阻塞和非阻塞绑定,取消和超时等功能。并为多种语言生成跨平台的客服端和服务端绑定。比较适合移动端。

    • 目前支持 C++ JAVA Python Go Ruby c+ PHP Node.js Android Java Objective-C

  • Procotol Buffer

    • Protocol Buffer 是google的一种数据交换的格式,它独立于语言,独立于平台。google提供了多种语言的实现。和XML类似,但它是一种二进制的格式,比使用 xml 进行数据交换快许多。你可以一次定义好数据结构后生成各种语言所需的源代码。

##gPRC 的使用

  1. 准备工作
    1. go 版本
      • go version
      • gRPC 需要Go 1.5及更高的版本 (安装指导
    2. 安装gRPC
      • 使用命令: go get google.golang.org/grpc
    3. 安装Protocol Buffers v3
      • https://github.com/google/protobuf/releases下载对应平台和版本的编译好的二进制文件
      • 下载后解压文件,将对应的protoc 可执行文件所在路径添加到环境变量PATH中
      • 接下来安装protoc 插件 使用命令:
        • go get -u github.com/golang/protobuf/proto // golang protobuf 库
        • go get -u github.com/golang/protobuf/protoc-gen-go //protoc –go_out 工具
      • 编译插件protoc-gen-go 会被默认安装在$GOPATH/bin目录下,需要将$GOPATH/bin添加到环境变量PATH中去
      • 如果需要支持其他语言,需要安装相应的插件
      • 官方推荐Protocol Buffer 3 以及以上的版本
  2. 定义.proto文件

    helloworld.proto

    // 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 greetings
    message HelloReply {
      string message = 1;
    }
    

    此处定义了一个服务Greeter,其中有API SayHello 。接受HelloRequest请求返回HelloReply。

    * rpc GetFeature(Point) returns (Feature) {}                          
    // 类似普通的函数调用,客户端发送请求Point到服务器,服务器返回相应Feature.
    
    * rpc ListFeatures(Rectangle) returns (stream Feature) {}                            
    // 客户端发起一次请求,服务器端返回一个流式数据,比如一个数组中的逐个元素
    
    * rpc RecordRoute(stream Point) returns (RouteSummary) {}                          
    // 客户端发起的请求是一个流式的数据,比如数组中的逐个元素,服务器返回一个相应
    
    * rpc RouteChat(stream RouteNote) returns (stream RouteNote) {}                                
    // 客户端发起的请求是一个流式数据,比如数组中的逐个元素,二服务器返回的也是一个                                        
    // 类似的数据结构后面三种可以参考官方的route_guide示例。
    
    后面三种可以参考官方的[route_guide](https://github.com/grpc/grpc-go/tree/master/examples/route_guide)示例
    
  3. 生成gRPC代码 protoc -I helloworld/ helloworld/helloworld.proto –go_out=plugins=grpc:helloworld

    其中 plugins选项提供对grpc的支持,否则不会生成Service的接口

    执行上述命令之后,会自动生成文件 helloworld.pb.go。其中定义了两个接口GreeterServer和GreeterClient,

    // Client API for Greeter service
    
    type GreeterClient interface {
        // Sends a greeting
        SayHello(ctx context.Context, in *HelloRequest, opts ...grpc.CallOption) (*HelloReply, error)
    }
    // Server API for Greeter service
    
    type GreeterServer interface {
        // Sends a greeting
        SayHello(context.Context, *HelloRequest) (*HelloReply, error)
    }
    
  4. 实现服务端和客户端

    • 服务端的实现

      package main
      
      import (
          "log"
          "net"
      
          pb "your_path_to_gen_pb_dir/helloworld"
          "golang.org/x/net/context"
          "google.golang.org/grpc"
      )
      
      const (
          port = ":50051"
      )
      
      // server is used to implement helloworld.GreeterServer.
      type server struct{}
      
      // SayHello implements helloworld.GreeterServer
      func (s *server) SayHello(ctx context.Context, in *pb.HelloRequest) (*pb.HelloReply, error) {
          return &pb.HelloReply{Message: "Hello " + in.Name}, nil
      }
      
      func main() {
          lis, err := net.Listen("tcp", port)
          if err != nil {
              log.Fatalf("failed to listen: %v", err)
          }
          s := grpc.NewServer()
          pb.RegisterGreeterServer(s, &server{})
          s.Serve(lis)
      }
      
    • 客户端的实现

      package main
      
      import (
          "log"
          "os"
      
          "golang.org/x/net/context"
          "google.golang.org/grpc"
          pb "google.golang.org/grpc/examples/helloworld/helloworld"
      )
      
      const (
          address     = "localhost:50051"
          defaultName = "world"
      )
      
      func main() {
          // Set up a connection to the server.
          conn, err := grpc.Dial(address, grpc.WithInsecure())
          if err != nil {
              log.Fatalf("did not connect: %v", err)
          }
          defer conn.Close()
          c := pb.NewGreeterClient(conn)
      
          // Contact the server and print out its response.
          name := defaultName
          if len(os.Args) > 1 {
              name = os.Args[1]
          }
          r, err := c.SayHello(context.Background(), &pb.HelloRequest{Name: name})
          if err != nil {
              log.Fatalf("could not greet: %v", err)
          }
          log.Printf("Greeting: %s", r.Message)
      }
      

      其中服务端定义server实现了GreeterServer接口,客户端调用相应的接口

      ./server & ./client

      2017/02/14 17:49:56 Greeting: Hello world

如果你觉得本文对你有帮助,欢迎打赏!