Golang grpc.server: Understanding notions of server, and services

1.6k views Asked by At

I am trying to understand the notions of Listener, Server and Services in the context of gRPC, Protobuf.

Let's use example on https://grpc.io/docs/languages/go/basics/ as a reference. Here we have

  1. Listener: lis
  2. gRPC Server: grpcServer := grpc.NewServer()
  3. Service: RouteGuide service

It appears we can also have more than one service registered to the same server.

That is, besides RouteGuide Service, we can have say SomeOther Service, SomeOtherOther Service.

And we can register all the three and expect the server to be able to serve methods belong to this three services (RouteGuide, SomeOther, SomeOtherOther).

Let's say RouteGuide, SomeOther, SomeOtherOther each have their own proto files specific to them. And all of the protos are in the same namespace (package value).

grpcServer := grpc.NewServer(opts...)

newRouteGuideService := pb.NewRouteGuideServer()
pb.RegisterRouteGuideServer(grpcServer, newRouteGuideService)

someOtherService := pb.NewSomeOtherServer()
pb.RegisterSomeOtherServer(grpcServer, someOtherService)

someOtherOtherService := pb.NewSomeOtherOtherServer()
pb.RegisterSomeOtherOtherService(grpcServer, someOtherOtherService)

 lis, err := net.Listen("tcp", fmt.Sprintf("localhost:%d", 80))
grpcServer.Serve(lis)

It appears the term Server is, so to speak, overloaded here. Not only grpcServer, but also RouteGuide, SomeOther, and SomeOtherOther are also referred to as Servers.

I am trying to figure out how to model or understand the notions.

Can we say, the server gRPCServer through listener lis listens on port 80 and can serve the three services RouteGuide, SomeOther, SomeOtherOther which are registered with it (gRPCServer)? Is having one server service multiple services error prone? What are the caveats to keep in mind when using one server with multiple services?

3

There are 3 answers

2
Burak Serdar On

The listener listens for connections on a given port, and when a client connects, it creates a new goroutine to handle that particular session. The listener continues listening on the port for new incoming connections while the goroutine handles that particular client connection.

The session simply listens for the requests from the connected client and dispatches them to one of the registered services. The incoming request includes the name of the service, the function to call, and the arguments to that function. When the service handles the request, the response is sent back to the client.

So, as you say, the server listens on a port and can serve all the registered services through that port. This is not error-prone, and not that different from having one registered service defining all those functions.

0
Parcival On

Remember that Golang is Compositional. So if you lay this out in a stripped down pseudo manner:

// Simplified Example
//The interfaces would be made by your proto definition
type Service1 interface { 
   // does service 1 stuff
   ServiceHandler1()
   ServiceHandler2()
}

type S1 struct{}
func(*S1) ServiceHandler1() {
  //do svc1 stuff
}

type S2 struct{}
func(*S2) ServiceHandler2() {
  //do svc2 stuff
}

type S3 struct{
  // compose s1, s2
  S1
  S2
}

The server is the top level of the GRPC that has a listener, then you register the services that satisfy the interface required by your GRPC proto definition.

So in the case above, I could have ServiceHandler1 and ServiceHander2 defined in proto rpc. Registering S1 wouldn't satisfy it, registering S2 wouldn't, but registering S3 would.

Similarly you can break up the rpc proto into two services, one for method 1 and one for method 2 and treat them independently. In this case you could register, S1 for service 1, S2 for service 2, and S3 as either of them.

When a request comes in: Request --> Listener --> GRPC Server --> Multiplexed to Handler --> Spawns goroutine to Handle Request

TLDR; doesn't matter where the things come from as long as they satisfy the Service Interface. Registrations can even be changed at runtime dynamically.

0
rubens21 On

Can we say, the server gRPCServer through listener lis listens on port 80 and can serve the three services RouteGuide, SomeOther, SomeOtherOther which are registered with it (gRPCServer)?

Yes. I could not describe better.

Is having one server service multiple services error prone?

No, no problem at all. You will eventually need to have a server serving multiple services, specially if you need side services (e.g. health checker, metrics, caching, etc.). So your clients do not have to know all methods from the main service.

What are the caveats to keep in mind when using one server with multiple services?

(opinion) I have nothing in mind at this moment, but of course you need to wisely choose which services will be served together because you do not want to overload your server or mix logic.