grpc的反射机制
版权声明 本站原创文章 由 萌叔 发表
转载请注明 萌叔 | https://vearne.cc
1. 前言
读者们可能使用过 fullstorydev/grpcurl 来对grpc服务进行调用调试。
假定有一个简单的grpc的服务
main.go
package main
import (
"context"
"log"
"net"
"google.golang.org/grpc"
pb "google.golang.org/grpc/examples/helloworld/helloworld"
"google.golang.org/grpc/reflection"
)
const (
port = ":50051"
)
// server is used to implement helloworld.GreeterServer.
type server struct {
pb.UnimplementedGreeterServer
}
// SayHello implements helloworld.GreeterServer
func (s *server) SayHello(ctx context.Context, in *pb.HelloRequest) (*pb.HelloReply, error) {
log.Printf("Received: %v", in.GetName())
return &pb.HelloReply{Message: "Hello " + in.GetName()}, nil
}
func main() {
lis, err := net.Listen("tcp", port)
if err != nil {
log.Fatalf("failed to listen: %v", err)
}
s := grpc.NewServer()
helloService := &server{}
pb.RegisterGreeterServer(s, helloService)
// 注册反射服务
// Register reflection service on gRPC server.
reflection.Register(s)
if err := s.Serve(lis); err != nil {
log.Fatalf("failed to serve: %v", err)
}
}
使用grpcurl来请求grpc服务
grpcurl --plaintext -d '{"name":"vearne"}' 127.0.0.1:50051 helloworld.Greeter/SayHello|jq
output:
{
"message": "Hello vearne"
}
jq
命令用于解析JSON字符串
读者可能会好奇,grpc服务GreeterServer明明使用的protobuf进行编码。而我们却能用JSON格式与它进行交互?
2. 解决疑惑
事实是,grpc协议提供了反射机制使得grpcurl
可以知道GreeterServer的service
定义,包含方法定义、请求参数、返回响应等等
2.1 输出方法定义
grpcurl --plaintext 127.0.0.1:50051 describe helloworld.Greeter.SayHello
output:
helloworld.Greeter.SayHello is a method:
rpc SayHello ( .helloworld.HelloRequest ) returns ( .helloworld.HelloReply );
2.2 获得方法的Request定义
grpcurl --plaintext 127.0.0.1:50051 describe .helloworld.HelloRequest
output:
helloworld.HelloRequest is a message:
message HelloRequest {
string name = 1;
}
2.3 获得方法的Response定义
grpcurl --plaintext 127.0.0.1:50051 describe .helloworld.HelloReply
output:
helloworld.HelloReply is a message:
message HelloReply {
string message = 1;
}
如果读者有心的话,可能会发现
grpcurl --plaintext 127.0.0.1:50051 list
output:
grpc.reflection.v1alpha.ServerReflection // 反射服务
helloworld.Greeter // 正常的业务服务
没错,其实在监听在50051端口的有2个grpc服务。
进一步
grpcurl --plaintext 127.0.0.1:50051 describe grpc.reflection.v1alpha.ServerReflection
output:
grpc.reflection.v1alpha.ServerReflection is a service:
service ServerReflection {
rpc ServerReflectionInfo ( stream .grpc.reflection.v1alpha.ServerReflectionRequest ) returns ( stream .grpc.reflection.v1alpha.ServerReflectionResponse );
}
ServerReflection服务可以供client查询其它grpc服务的定义。
这个服务的proto定义在参考资料2中,可以留意到它是双向流。具体可以参见参考资料2