您的位置:

GRPC使用详解

一、GRPC使用JS

通过`grpc`的`@grpc/proto-loader`包,我们可以方便地将`.proto`文件生成的`service`数据结构转换为`service`的构造函数。并且可以使用`@grpc/grpc-js`包直接连接`grpc`服务并调用服务方法,使用起来非常便捷。

下面是一个简单的使用示例:


// 定义message和service
syntax = "proto3";
package proto;
message HelloRequest {
  string name = 1;
}
message HelloResponse {
  string message = 1;
}
service Greeter {
  rpc SayHello (HelloRequest) returns (HelloResponse);
}
// 加载proto文件
const PROTO_PATH = path.join(__dirname, '../proto/helloworld.proto');
const packageDefinition = protoLoader.loadSync(PROTO_PATH, {
  keepCase: true,
  longs: String,
  enums: String,
  defaults: true,
  oneofs: true
});
const hello_proto = grpc.loadPackageDefinition(packageDefinition).helloworld;
// 创建客户端连接
const client = new hello_proto.Greeter('localhost:50051', grpc.credentials.createInsecure());
// 调用服务方法
client.SayHello({name: 'world'}, (err, response) => {
  console.log(response);
});

二、GRPC使用Msgpack

默认情况下,`grpc`使用`Protobuf`作为序列化/反序列化协议,但是用户可以通过实现自定义`serializer`替换默认的`serializer`。

这里我们介绍使用`msgpack`替代`protobuf`的示例:


const grpc = require('@grpc/grpc-js');
const protoLoader = require('@grpc/proto-loader');
const msgpack = require('msgpack5')();
// 定义序列化、反序列化函数
const serialize = (value) => {
  return msgpack.encode(value).toString('binary');
};
const deserialize = (bytes) => {
  return msgpack.decode(bytes);
};
// 加载proto文件
const protoDef = protoLoader.loadSync('example.proto');
const protoPackage = grpc.loadPackageDefinition(protoDef);
// 替换默认的protobuf serializer/deserializer
const options = {
  binaryAsBase64: false,
  serialize: serialize,
  deserialize: deserialize
};
const client = new protoPackage.example.ExampleService('localhost:8888', grpc.credentials.createInsecure(), options);
// 调用服务方法
client.exampleMethod({}, (err, response) => {
  console.log(response);
});

三、GRPC使用C++

使用`grpc`的C++实现非常方便简单,只需要安装`grpc`的C++依赖库,然后使用C++代码即可调用服务方法。

下面是一个简单的使用示例:


void RunService() {
  echo::EchoImpl service;
  ServerBuilder builder;
  builder.AddListeningPort("0.0.0.0:50051", grpc::InsecureServerCredentials());
  builder.RegisterService(&service);
  std::unique_ptr<Server> server(builder.BuildAndStart());
  std::cout << "Server listening on " << server_address << std::endl;
  server->Wait();
}

int main(int argc, char* argv[]) {
  grpc::EnableDefaultHealthCheckService(true);
  grpc::reflection::InitProtoReflectionServerBuilderPlugin();
  RunService();
  return 0;
}

四、GRPC使用什么协议

`grpc`默认使用`protobuf`作为序列化/反序列化协议,但是用户可以通过自定义`serializer`替换默认的协议。

五、GRPC使用域名

可以通过域名进行`grpc`服务的调用,只需要在客户端的`new Client`语句中指定域名即可。


const client = new helloworld.Greeter('localhost:50051', grpc.credentials.createInsecure());

六、GRPC使用教程

推荐阅读grpc的官方文档https://grpc.io/docs/languages/js/basics/

七、GRPC使用场景

`grpc`适合分布式系统、微服务架构以及数据通信频繁的场景。`grpc`优势在于使用`protobuf`进行序列化和反序列化,效率非常高。

八、GRPC使用案例

实时在线教育

在线教育需要考虑实时性,`grpc`可以通过双向流式RPC解决请求间数据传输的实时性问题,并且使用高效的`protobuf`序列化协议,可以优化数据传输效率。

金融数据传输

金融行业数据量大、传输频繁、高效稳定的通信方式,非常适合使用`grpc`。

九、GO使用GRPC

Go语言作为Google开发的语言,支持grpc,非常适合使用grpc进行分布式服务的开发。

下面是一个简单的示例,在Go中调用`grpc`服务:


package main

import (
    "context"
    "fmt"
    "google.golang.org/grpc"
    "net"
    pb "path/to/proto"
)

type server struct{}

func (s *server) Hello(ctx context.Context, in *pb.HelloRequest) (*pb.HelloResponse, error) {
    return &pb.HelloResponse{Message: "Hello " + in.Name}, nil
}

func main() {
    lis, err := net.Listen("tcp", "localhost:50051")
    if err != nil {
        fmt.Printf("failed to listen: %v", err)
    }
    s := grpc.NewServer()
    pb.RegisterGreeterServer(s, &server{})
    if err := s.Serve(lis); err != nil {
        fmt.Printf("failed to serve: %v", err)
    }
}