RPC(Remote Procedure Call)远程过程调用,关注笔者的同窗应该知道以前笔者出过关于Thrift对应的问题,此次主要来讲的是Google开源的Grpc,和Thrift有很大的区别Grpc是基于HTTP2.0而且依赖protobuf,为何又推出关于grpc的文章呢?请你们继续往下看。php
附上:html
喵了个咪的博客:w-blog.cnjava
博文实例demo:GitHub - sunmi-OS/grpc-php-to-golang-demogit
grpc官网:grpc / grpc.iogithub
protobuf代码仓库:Releases · protocolbuffers/protobuf · GitHubgolang
一个高性能、通用的开源RPC框架,其由Google主要面向移动应用开发并基于HTTP/2协议标准而设计,基于ProtoBuf(Protocol Buffers)序列化协议开发,且支持众多开发语言。 gRPC基于HTTP/2标准设计,带来诸如双向流控、头部压缩、单TCP链接上的多复用请求等特性。这些特性使得其在移动设备上表现更好,更省电和节省空间占用。vim
性能 Grpc PK Thrift 借鉴:开源RPC(gRPC/Thrift)框架性能评测 - 沧海一滴 - 博客园框架
PS:笔者也作了对应的性能测试,后面的文章会附上详细步骤,经过这个现有的结果一个简单的结论tcp
从压测的结果商米咱们能够获得如下重要结论:ide
这里主要要回答的一个问题是既然已经用thrift而且性能仍是grpc的2倍为何还要用grpc呢?
这里主要要说到两个Go的微服务框架,go-kit和istio
主要的致使这个问题的缘由在于thrift的传输方式是经过TCP的方式传输,对于这些框架想在传输过程当中加入些链路的ID是没法实现的,istio连对于thrift的请求次数感知都作不到,对于grpc由于是基于http2在harder头上能够作不少补充参数,对于这类微服务框架很是友好。
安装protobuf为了生成对应语言的文件必须须要protoc的命名,protoc是c语言的protobuf的命名,有两种访问一个是本身编译:
wget https://github.com/protocolbuffers/protobuf/releases/download/v3.6.1/protobuf-cpp-3.6.1.tar.gz > tar -zxvf protobuf-cpp-3.6.1.tar.gz > cd protobuf-3.6.1 > ./configure > make > make install > protoc --version libprotoc 3.6.1
或者根据更具系统直接使用编译好的bin文件运行protoc(这里使用的是MAC OSX系统)
wget https://github.com/protocolbuffers/protobuf/releases/download/v3.6.1/protoc-3.6.1-osx-x86_64.zip > tar -zxvf protoc-3.6.1-osx-x86_64.zip > cd protoc-3.6.1-osx-x86_6/bin > ./protoc --version > libprotoc 3.6.1
安装好了咱们就要来运行下测试程序了
不得不说Go是Google的亲儿子,天然Grpc的支持不会差依赖只须要一个命令就能够(这里使用的是go 1.11版本):
> go get google.golang.org/grpc
若是你们报错,缘由是这个代码已经转移到github上面了,可是代码里面的包依赖仍是没有修改,仍是google.golang.org这种,因此有的不能使用go get的方式安装,可使用如下安装方式:
> git clone https://github.com/grpc/grpc-go.git $GOPATH/src/google.golang.org/grpc > git clone https://github.com/golang/net.git $GOPATH/src/golang.org/x/net > git clone https://github.com/golang/text.git $GOPATH/src/golang.org/x/text > git clone https://github.com/golang/sys.git $GOPATH/src/golang.org/x/sys > go get -u github.com/golang/protobuf/{proto,protoc-gen-go} > git clone https://github.com/google/go-genproto.git $GOPATH/src/google.golang.org/genproto > cd $GOPATH/src/ > go install google.golang.org/grpc
先使用笔者的准备好的:
> cd $GOPATH/src > mkdir -p grpc-php-to-golang-demo/protobuf > cd grpc-php-to-golang-demo/protobuf > vim helloworld.proto
文件内容以下:
syntax = "proto3"; option java_multiple_files = true; option java_package = "io.grpc.examples.helloworld"; 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 greetings message HelloReply { string message = 1; }
生成对应的文件:
> mkdir -p go-server/helloworld > protoc --go_out=plugins=grpc:./go-server/helloworld ./helloworld.proto > cd go-server/helloworld/ > ll total 16 drwxr-xr-x 3 wenzhenxi staff 96 2 15 14:24 ./ drwxr-xr-x 3 wenzhenxi staff 96 2 15 14:23 ../ -rw-r--r-- 1 wenzhenxi staff 6915 2 15 14:24 helloworld.pb.go
编写服务端和客户端Go程序:
> cd $GOPATH/src/grpc-php-to-golang-demo > mkdir -p golang/holleworld > cd golang/holleworld
服务端:
> vim server.go package main import ( "log" "net" pb "grpc-php-to-golang-demo/protobuf/go-server/helloworld" "google.golang.org/grpc" "golang.org/x/net/context" "google.golang.org/grpc/reflection" ) 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{}) // Register reflection service on gRPC server. reflection.Register(s) if err := s.Serve(lis); err != nil { log.Fatalf("failed to serve: %v", err) } }
客户端:
> vim client.go package main import ( "log" "os" "time" pb "grpc-php-to-golang-demo/protobuf/go-server/helloworld" "google.golang.org/grpc" "golang.org/x/net/context" ) 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] } go func() { 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) }() time.Sleep(10 * time.Second) }
运行测试:
> go build server.go > go build client.go ./server ./client 2019/02/15 14:35:35 Greeting: Hello world
此时在go to go的场景就调用通了
最终产物能够参考demoGitHub - sunmi-OS/grpc-php-to-golang-demo