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
-
- Protocol Buffer 是google的一种数据交换的格式,它独立于语言,独立于平台。google提供了多种语言的实现。和XML类似,但它是一种二进制的格式,比使用 xml 进行数据交换快许多。你可以一次定义好数据结构后生成各种语言所需的源代码。
##gPRC 的使用
- 准备工作
- go 版本
- go version
- gRPC 需要Go 1.5及更高的版本 (安装指导)
- 安装gRPC
- 使用命令: go get google.golang.org/grpc
- 安装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 以及以上的版本
- go 版本
定义.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)示例
生成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) }
实现服务端和客户端
服务端的实现
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