gRPC库介绍

gRPC是一个高性能、通用的开源RPC框架,其由Google主要面向移动应用开发并基于HTTP/2协议标准而设计,基于ProtoBuf(Protocol Buffers)序列化协议开发,且支持众多开发语言。
gRPC提供了一种简单的方法来精确地定义服务和为iOS、Android和后台支持服务自动生成可靠性很强的客户端功能库。
客户端充分利用高级流和链接功能,从而有助于节省带宽、降低的TCP链接次数、节省CPU使用、和电池寿命。

gRPC具有以下重要特征:

  1. 强大的IDL特性
    RPC使用ProtoBuf来定义服务,ProtoBuf是由Google开发的一种数据序列化协议,性能出众,得到了广泛的应用。
  2. 支持多种语言
    支持C++、Java、Go、Python、Ruby、C#、Node.js、Android Java、Objective-C、PHP等编程语言。
  3. 基于HTTP/2标准设计

gRPC介绍 - 图1

gRPC已经应用在Google的云服务和对外提供的API中。

我们以 gRPC-go 为例介绍一下gRPC的开发。

首先下载相应的库:

  1. go get google.golang.org/grpc
  2. go get -u github.com/golang/protobuf/{proto,protoc-gen-go}

同时保证按照Protocol Buffers v3 编译器到你的开发环境中(protoc)。

定义你的protobuf文件 (helloworld.proto):

  1. syntax = "proto3";
  2. option java_package = "com.colobu.rpctest";
  3. package greeter;
  4. // The greeting service definition.
  5. service Greeter {
  6. // Sends a greeting
  7. rpc SayHello (HelloRequest) returns (HelloReply) {}
  8. }
  9. // The request message containing the user's name.
  10. message HelloRequest {
  11. string name = 1;
  12. }
  13. // The response message containing the greetings
  14. message HelloReply {
  15. string message = 1;
  16. }

这个文件定义了一个Greeter服务,它有一个SayHello方法,这个方法接收一个Request,返回一个Response。

然后我们可以编译这个文件,生成服务器和客户端的stub:

  1. protoc -I protos protos/helloworld.proto --go_out=plugins=grpc:src/greeter

因为上面我们安装了protoprotoc-gen-go,所以protoc可以生成响应的Go代码。

然后我们就可以利用这个生成的代码创建服务器代码和客户端代码了。

服务器端的代码如下:

  1. package main
  2. import (
  3. "log"
  4. "net"
  5. pb "greeter"
  6. "golang.org/x/net/context"
  7. "google.golang.org/grpc"
  8. )
  9. const (
  10. port = ":50051"
  11. )
  12. type server struct{}
  13. // SayHello implements helloworld.GreeterServer
  14. func (s *server) SayHello(ctx context.Context, in *pb.HelloRequest) (*pb.HelloReply, error) {
  15. return &pb.HelloReply{Message: "Hello " + in.Name}, nil
  16. }
  17. func main() {
  18. lis, err := net.Listen("tcp", port)
  19. if err != nil {
  20. log.Fatalf("failed to listen: %v", err)
  21. }
  22. s := grpc.NewServer()
  23. pb.RegisterGreeterServer(s, &server{})
  24. s.Serve(lis)
  25. }

客户端的测试代码如下:

  1. package main
  2. import (
  3. "fmt"
  4. "log"
  5. "os"
  6. "strconv"
  7. "sync"
  8. "time"
  9. pb "greeter"
  10. "golang.org/x/net/context"
  11. "google.golang.org/grpc"
  12. )
  13. const (
  14. address = "localhost:50051"
  15. defaultName = "world"
  16. )
  17. func invoke(c pb.GreeterClient, name string) {
  18. r, err := c.SayHello(context.Background(), &pb.HelloRequest{Name: name})
  19. if err != nil {
  20. log.Fatalf("could not greet: %v", err)
  21. }
  22. _ = r
  23. }
  24. func syncTest(c pb.GreeterClient, name string) {
  25. i := 10000
  26. t := time.Now().UnixNano()
  27. for ; i>0; i-- {
  28. invoke(c, name)
  29. }
  30. fmt.Println("took", (time.Now().UnixNano() - t) / 1000000, "ms")
  31. }
  32. func asyncTest(c [20]pb.GreeterClient, name string) {
  33. var wg sync.WaitGroup
  34. wg.Add(10000)
  35. i := 10000
  36. t := time.Now().UnixNano()
  37. for ; i>0; i-- {
  38. go func() {invoke(c[i % 20], name);wg.Done()}()
  39. }
  40. wg.Wait()
  41. fmt.Println("took", (time.Now().UnixNano() - t) / 1000000, "ms")
  42. }
  43. func main() {
  44. // Set up a connection to the server.
  45. conn, err := grpc.Dial(address)
  46. if err != nil {
  47. log.Fatalf("did not connect: %v", err)
  48. }
  49. defer conn.Close()
  50. var c [20]pb.GreeterClient
  51. // Contact the server and print out its response.
  52. name := defaultName
  53. sync := true
  54. if len(os.Args) > 1 {
  55. sync, err = strconv.ParseBool(os.Args[1])
  56. }
  57. //warm up
  58. i := 0
  59. for ; i < 20; i++ {
  60. c[i] = pb.NewGreeterClient(conn)
  61. invoke(c[i], name)
  62. }
  63. if sync {
  64. syncTest(c[0], name)
  65. } else {
  66. asyncTest(c, name)
  67. }
  68. }

参考文档

  1. http://www.grpc.io/docs/quickstart/go.html
  2. http://www.infoq.com/cn/news/2015/03/grpc-google-http2-protobuf
  3. https://github.com/smallnest/RPC-TEST