gRPC的简介与实例详解
什么是gRPC
gRPC是什么?可以用官网的一句话来概括:A high-performance, open-source universal RPC framework。
gRPC vs Restful API
gRPC和restful API都提供了一套通信机制,用于server/client模型通信,而且它们都使用http作为底层的传输协议(严格地说,gRPC使用的http2.0,而restful api则不一定)。不过gRPC还是有些特有的优势,如下:
gRPC可以通过protobuf来定义接口,从而可以有更加严格的接口约束条件。关于protobuf可以参见下期Protobuf简明教程,另外,通过protobuf可以将数据序列化为二进制编码,这会大幅减少需要传输的数据量,从而大幅提高性能。
gRPC可以方便地支持流式通信(理论上通过http2.0就可以使用streaming模式, 但是通常web服务的restful api似乎很少这么用,通常的流式数据应用如视频流,一般都会使用专门的协议如HLS,RTMP等,这些就不是我们通常web服务了,而是有专门的服务器应用。)
使用场景
需要对接口进行严格约束的情况,比如我们提供了一个公共的服务,很多人,甚至公司外部的人也可以访问这个服务,这时对于接口我们希望有更加严格的约束,我们不希望客户端给我们传递任意的数据,尤其是考虑到安全性的因素,我们通常需要对接口进行更加严格的约束。这时gRPC就可以通过protobuf来提供严格的接口约束。
对于性能有更高的要求时。有时我们的服务需要传递大量的数据,而又希望不影响我们的性能,这个时候也可以考虑gRPC服务,因为通过protobuf我们可以将数据压缩编码转化为二进制格式,通常传递的数据量要小得多,而且通过http2我们可以实现异步的请求,从而大大提高了通信效率。
gRPC DEMO实例详解
通过protobuf来定义接口和数据类型
编写gRPC server端代码
编写gRPC client端代码
本文使用golang去实现demo,其中protobuf和grpc扩展的安装就跳过了。
syntax = "proto3";
package user;
option go_package = "./grpc/user";
// The User service definition.
service User {
// Get all Users with id - A server-to-client streaming RPC.
rpc GetUsers(UserFilter) returns (stream UserRequest) {}
// Create a new User - A simple RPC
rpc CreateUser (UserRequest) returns (UserResponse) {}
}
// Request message for creating a new user
message UserRequest {
int32 id = 1; // Unique ID number for a User.
string name = 2;
string email = 3;
string phone= 4;
message Address {
string province = 1;
string city = 2;
}
repeated Address addresses = 5;
}
message UserResponse {
int32 id = 1;
bool success = 2;
}
message UserFilter {
int32 id = 1;
}
编译 .proto 文件
protoc --go_out=plugins=grpc:. userrpc.proto
新建服务端server.go
package main
import (
"log"
"net"
"golang.org/x/net/context"
"google.golang.org/grpc"
pb "userrpc/grpc/user"
)
const (
port = ":50051"
)
// server is used to implement user.UserServer.
type server struct {
savedUsers []*pb.UserRequest
}
// CreateUser creates a new User
func (s *server) CreateUser(ctx context.Context, in *pb.UserRequest) (*pb.UserResponse, error) {
s.savedUsers = append(s.savedUsers, in)
return &pb.UserResponse{Id: in.Id, Success: true}, nil
}
// GetUsers returns all users by given id
func (s *server) GetUsers(filter *pb.UserFilter, stream pb.User_GetUsersServer) error {
for _, user := range s.savedUsers {
if filter.Id == 0 {
continue
}
if err := stream.Send(user); err != nil {
return err
}
}
return nil
}
func main() {
lis, err := net.Listen("tcp", port)
if err != nil {
log.Fatalf("failed to listen: %v", err)
}
// Creates a new gRPC server
s := grpc.NewServer()
pb.RegisterUserServer(s, &server{})
s.Serve(lis)
}
客户端client.go
package main
import (
"io"
"log"
"golang.org/x/net/context"
"google.golang.org/grpc"
pb "userrpc/grpc/user"
)
const (
address = "localhost:50051"
)
// createUser calls the RPC method CreateUser of UserServer
func createUser(client pb.UserClient, user *pb.UserRequest) {
resp, err := client.CreateUser(context.Background(), user)
if err != nil {
log.Fatalf("Could not create User: %v", err)
}
if resp.Success {
log.Printf("A new User has been added with id: %d", resp.Id)
}
}
// getUsers calls the RPC method GetUsers of UserServer
func getUsers(client pb.UserClient, id *pb.UserFilter) {
// calling the streaming API
stream, err := client.GetUsers(context.Background(), id)
if err != nil {
log.Fatalf("Error on get users: %v", err)
}
for {
user, err := stream.Recv()
if err == io.EOF {
break
}
if err != nil {
log.Fatalf("%v.GetUsers(_) = _, %v", client, err)
}
log.Printf("User: %v", user)
}
}
func main() {
// Set up a connection to the gRPC server.
conn, err := grpc.Dial(address, grpc.WithInsecure())
if err != nil {
log.Fatalf("did not connect: %v", err)
}
defer conn.Close()
// Creates a new UserClient
client := pb.NewUserClient(conn)
user := &pb.UserRequest{
Id: 1,
Name: "test",
Email: "[email protected]",
Phone: "132222222",
Addresses: []*pb.UserRequest_Address{
&pb.UserRequest_Address{
Province: "hebei",
City: "shijiazhuang",
},
},
}
// Create a new user
createUser(client, user)
// Filter with an id
filter := &pb.UserFilter{Id: 1}
getUsers(client, filter)
}
启动server.go
go run server.go
新打开一个窗口,启动client.go
go run client.go
2019/07/04 17:01:16 A new User has been added with id: 1
2019/07/04 17:01:16 User: id:1 name:"test" email:"[email protected]" phone:"132222222" addresses:<province:"hebei" city:"shijiazhuang" >
小结
更多精彩推荐:
云计算开发工程师
大数据开发工程师
Web前端开发工程师
PHP开发工程师
测试开发工程师
运维开发工程师
2、五险一金:按规定为员工办理五项社会保险及住房公积金。
3、节日福利丰富,定期旅游,各项体育竞赛。
4、公司为员工提供免费住宿,员工可享受免费工作午餐。
5、年假、法定节假日按国家规定休息。
6、不定期大餐,丰盛的下午茶。
我们是一群有专业技术知识和远大理想抱负的年轻人,这里的每一个人都有着鲜明的个性,IT宅男、技术宅、活力、热情、激情是这里的符号。我们一直在做自己喜欢的事情,每个人都希望能用自己擅长的技术做出成功的产品来体现个人价值,团队价值。在这里,你有无限的职业发展空间。
We want you, just you !
还不快来投简历!
研发部邮箱:[email protected]