漫谈grpc 3:从实践到原理,带你参透 gRPC (5)

步骤一:Service API interface

// search.pb.go type SearchServiceServer interface {  Search(context.Context, *SearchRequest) (*SearchResponse, error) } func RegisterSearchServiceServer(s *grpc.Server, srv SearchServiceServer) {  s.RegisterService(&_SearchService_serviceDesc, srv) }

漫谈grpc 3:从实践到原理,带你参透 gRPC

还记得我们平时编写的 Protobuf 吗?在生成出来的 .pb.go 文件中,会定义出 Service APIs interface 的具体实现约束。而我们在 gRPC Server 进行注册时,会传入应用 Service 的功能接口实现,此时生成的 RegisterServer 方法就会保证两者之间的一致性。

步骤二:Service API IDL

你想乱传糊弄一下?不可能的,请乖乖定义与 Protobuf 一致的接口方法。但是那个 &_SearchService_serviceDesc 又有什么作用呢?代码如下:

// search.pb.go var _SearchService_serviceDesc = grpc.ServiceDesc{  ServiceName: "proto.SearchService",  HandlerType: (*SearchServiceServer)(nil),  Methods: []grpc.MethodDesc{   {    MethodName: "Search",    Handler:    _SearchService_Search_Handler,   },  },  Streams:  []grpc.StreamDesc{},  Metadata: "search.proto", }

漫谈grpc 3:从实践到原理,带你参透 gRPC

这看上去像服务的描述代码,用来向内部表述 “我” 都有什么。涉及如下:

ServiceName:服务名称

HandlerType:服务接口,用于检查用户提供的实现是否满足接口要求

Methods:一元方法集,注意结构内的 Handler 方法,其对应最终的 RPC 处理方法,在执行 RPC 方法的阶段会使用。

Streams:流式方法集

Metadata:元数据,是一个描述数据属性的东西。在这里主要是描述 SearchServiceServer 服务

步骤三:Register Service

func (s *Server) register(sd *ServiceDesc, ss interface{}) {     ...  srv := &service{   server: ss,   md:     make(map[string]*MethodDesc),   sd:     make(map[string]*StreamDesc),   mdata:  sd.Metadata,  }  for i := range sd.Methods {   d := &sd.Methods[i]   srv.md[d.MethodName] = d  }  for i := range sd.Streams {   ...  }  s.m[sd.ServiceName] = srv }

漫谈grpc 3:从实践到原理,带你参透 gRPC

在最后一步中,我们会将先前的服务接口信息、服务描述信息给注册到内部 service 去,以便于后续实际调用的使用。涉及如下:

server:服务的接口信息

md:一元服务的 RPC 方法集

sd:流式服务的 RPC 方法集

mdata:metadata,元数据

小结

在这一章节中,主要介绍的是 gRPC Server 在启动前的整理和注册行为,看上去很简单,但其实一切都是为了后续的实际运行的预先准备。因此我们整理一下思路,将其串联起来看看,如下:

图片

漫谈grpc 3:从实践到原理,带你参透 gRPC

三、监听

接下来到了整个流程中,最重要也是大家最关注的监听/处理阶段,核心代码如下:

func (s *Server) Serve(lis net.Listener) error {  ...  var tempDelay time.Duration  for {   rawConn, err := lis.Accept()   if err != nil {    if ne, ok := err.(interface {     Temporary() bool    }); ok && ne.Temporary() {     if tempDelay == 0 {      tempDelay = 5 * time.Millisecond     } else {      tempDelay *= 2     }     if max := 1 * time.Second; tempDelay > max {      tempDelay = max     }     ...     timer := time.NewTimer(tempDelay)     select {     case <-timer.C:     case <-s.quit:      timer.Stop()      return nil     }     continue    }    ...    return err   }   tempDelay = 0   s.serveWG.Add(1)   go func() {    s.handleRawConn(rawConn)    s.serveWG.Done()   }()  } }

漫谈grpc 3:从实践到原理,带你参透 gRPC

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/zgffdj.html