1

Will a bidirectional RPC call ever open multiple http2 connections?

I'm writing a GRPC client that's talking to a GRPC server I don't own/control. I'm using the @grpc/grpc-js package. I've been asked whether this library will open multiple HTTP2 connections to the grpc endpoint and I'm not familiar enough with the source code to answer this question. My code for making a call and opening a stream looks like this

const protoLoader = require('@grpc/proto-loader')

const packageDefinition = protoLoader.loadSync(
  __dirname + '/path/to/v1.proto',
  {keepCase: true,
    longs: String,
    enums: String,
    defaults: true,
    oneofs: true
  })

const packageDefinition = grpc.loadPackageDefinition(packageDefinition).com.foo.bar.v1
const client = new packageDefinition.IngestService(
  'server.url.here.com:443',
  grpc.credentials.createSsl()
)

const stream = client.doTheThing(metadata)        

I've started to look into this myself and I see that it's the Subchannel objects that initiate the http2 connections, so it seems like it's one http2 connection per sub-channel. However, the relationship between the call, the http2call stream, the main channel, the sub-channel(s?), load balancers, and filter stacks is unclear to me, and I can't reason about when (if at all) a second HTTP2 connection would ever be opened.

Ideally, if someone can answer the question Will a Bidirection RPC Call Open Multiple http2 Connections? that would great. If that's too complicated an answer I'd settle for a theory of operation on what the relationship between those various objects is intended to be so I can reason about this myself, or anything else you might think would help.

Alana Storm
  • 164,128
  • 91
  • 395
  • 599

1 Answers1

3

No matter what streaming type the request is, gRPC will use each single connection to open multiple streams. This is one major reason HTTP/2 was chosen as the underlying protocol for gRPC: multiplexing streams onto connections is already part of that protocol.

Of the classes you mentioned, the Channel is the API-level abstraction over connections. A Channel represents any number of connections to backends referred to by the target string. It will automatically establish connections as needed to handle any requests that are initiated.

The Resolver, which you didn't mention, determines what backend addresses are associated with the target string. For example, the DnsResolver will look up DNS records.

A LoadBalancer determines what specific connections to establish and how to distribute requests among those connections. The default load balancing policy, "pick first" just sends all requests to whichever connection is successfully established first. There is also the "round robin" load balancing policy, which tries to establish connections to multiple backends and then cycles through them when starting calls.

A Subchannel represents a connection to a single backend, that can be reestablished if it drops.

The filter stack applies some transformations to requests between when they are initiated at the top-level API and when they are sent out on the network.

murgatroid99
  • 19,007
  • 10
  • 60
  • 95