About gRPC the example explanation

What is gRPC

What gRPC that? Sentence can be summarized official website: A High-Performance, Open-Source Universal the RPC Framework.

The so-called RPC (remote procedure call remote procedure call) is actually the framework provides a mechanism, so that the application can communicate, but also to comply server / client model. Use when the client calls the server-side interfaces are provided as function calls as local. As shown below is a typical RPC configuration of FIG.


gRPC vs Restful API

GRPC and restful API provides a communication mechanism for the server / client model of the communication, and they are used as the underlying transport protocol http (strictly speaking, GRPC used http2.0, but not necessarily restful api). But gRPC still some unique advantages, as follows:

gRPC interfaces can be defined by protobuf, so there may be more stringent interface constraints. About protobuf can be found in the next issue Protobuf simple tutorial, in addition, data can be modeled as a binary coding sequence by protobuf, which will significantly reduce the amount of data to be transmitted, thereby boosting performance.

gRPC can easily support streaming communication (theory by http2.0 can use streaming mode, but usually web services restful api seem so rarely used, usually streaming data applications such as streaming video, usually using a special protocol such as HLS, RTMP, etc., which is not our usual web services, but to a dedicated server application.)


scenes to be used

  • Circumstances require strict constraints on the interface, such as we provide a public service, a lot of people, even people outside the company can also access this service, then we want to have an interface for a more stringent constraints, we do not want clients to we pass any of the data, especially considering the safety factors, we often need to interface more stringent constraints. Then gRPC can provide rigorous interface constraints by protobuf.

  • Respect to the higher performance requirements. Sometimes our services need to pass a lot of data, but do not want to affect our performance, this time can also be considered gRPC service, because by protobuf we can compress data encoded into binary format, usually much smaller amount of data transfer and by http2 we can achieve asynchronous request, thus greatly improving the communication efficiency.

However, we usually do not go alone gRPC, but will gRPC as a component for use, because in the case of a production environment, we are faced with a large concurrent need to use distributed processing systems come and go, but did not gRPC provide some of the necessary components of a distributed system. Moreover, the real need to provide online services, including load balancing, current-limiting fuse, alarm monitoring, service registration and discovery, and so the necessary components. However, this does not belong to the subject of this article discussed, and we continue to look at how to use gRPC.


gRPC DEMO example explanation

  • Interfaces and data types defined by protobuf

  • Write gRPC server-side code

  • GRPC client-side code written
    herein used to achieve golang demo, and wherein protobuf grpc installation is skipped extensions.

New userrpc.proto

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" >

小结

Api实现起来比较繁琐,给开发带来难度。总的来说gRPC是一个不错的跨语言rpc解决方案,当然每个人都自己的看法或见解。针对不同的业务场景采用不同的解决方案,最终都是运行效率和开发效率的相互妥协的结果。


睿江云官网链接:https://www.eflycloud.com/home?from=RJ0035


Guess you like

Origin blog.51cto.com/13475644/2477576