hevi
hevi

Reputation: 2726

What is the best practice for opening channels on GRPC?

There are services calling service A (10 replicas) via GRpc (100+ req/sec), java generated stubs. We don't have load balancers but I am curios what is the best practice in both cases.

Should clients build the channel on each call to service A or Should I create the managedChannel once until the app shutsdown?

  1. If I create one for each request, calls distributes along 10 replicas but if I create only on application starts all calls goes to the same service A replica.

  2. On the other hand if I create on each call wouldn't there be thousands of connections open until they get idle (which is 30mins by defeault)?

ManagedChannel managedChannel = ManagedChannelBuilder
                    .forAddress(host, port)
                    .usePlaintext()
                    .build()
ServiceA.newBlockingStub(managedChannel)).fooBar(...)

Upvotes: 6

Views: 3001

Answers (1)

Eric Anderson
Eric Anderson

Reputation: 26464

ManagedChannels should be created seldom and reused heavily. When a ManagedChannel will no longer be used, shutting it down is essential. Otherwise it will leak.

This is a load balancing question and the answer depends on your load balancing architecture. Based on your description, you are likely using one of two structures:

  1. All backends are exposed in DNS. The client connects directly to the backend. I'll call this "exposed"

  2. There is a TCP load balancer that the client creates a connection to and the balancer extends that connection to a backend. I'll call this "hidden"

For both approaches, having backends set nettyServerBuilder.maxConnectionAge(...) is generally necessary for clients to start using new backends.

In the exposed architecture, you simply need to configure load balancing in the ManagedChannel. This is probably as simple as using managedChannelBuilder.defaultLoadBalancingPolicy("round_robin"). The round_robin policy will make a connection to each IP address returned by DNS and distribute RPCs across the addresses. When a backend disconnects due to maxConnectionAge the client will re-resolve DNS and make a new connection.

In the hidden architecture, if you have many clients where each client is "small" compared to each backend, then maxConnectionAge is sufficient. When a backend disconnects due to maxConnectionAge the client will make a new connection to the load balancer which can choose a new backend.

In the hidden architecture, if you have "big" clients that generate more load than a single backend can handle, then things are harder; the client has no visibility into the number of backends and their state, yet the backends can't manage the load themselves. The easiest thing to do here is to create multiple channels and round-robin over them. In Java you can implement this as a Channel so it is hidden from the majority of your code. When a backend disconnects due to maxConnectionAge that one channel will make a new connection to the load balancer which can choose a new backend. The difficulty with this approach is knowing how many channels to make. The hidden architecture with larger clients benefits a lot from using HTTP load balancing instead of TCP load balancing. Even with HTTP load balancing it may be necessary to use multiple managed channels, in order to balance the load balancer's load.

Upvotes: 4

Related Questions