I'm curious how much thought has been put into SPIs for this. We haven't yet made the switch to GRPC at Square, but we do have service discovery integration and client-side load balancing in our current protobuf-based RPC system. And they're provided via a set of interfaces that an SPI can implement (we have three implementations internally: one for statically defining service endpoints in config files, one for discovering endpoints via DNS SRV records, and then our most sophisticated one that uses Zookeeper to store service information and traffic shaping policies.)
I've dug through the GRPC APIs for Java a good bit and have been looking at how to layer in APIs that are similar to what we already have here at Square (at least "the good parts"). I figured they'd make a reasonable strawman proposal for this.
I've started scratching this out in a Gist and was curious to either to get input or see if this is useful for Googlers or other GRPC contributors that might already be looking into this:
https://gist.github.com/jhump/ddb565e2db61ac219857. I personally mainly work in Java, but at Square we have an interest in this sort of support for Go and Ruby, too.
The current approach in the gist favors simple, general types (map-like APIs with typed keys for endpoint metadata, simple strings for service names) over generic types and type parameters. But that's a detail that I've been flip-flopping about. Instead of these "weak" types, the SPI interfaces could be parameterized, so implementations can plug in their own structured types to represent things like names (or, more generally, service discovery queries) and endpoint metadata.
(Feel free to ignore the stuff at the bottom of the gist. It was mostly riffing on ideas for layering in other things like reconnection and retry policies. These are concerns that are currently tightly coupled in the core of our internal RPC client implementation that would need to be feathered into a GRPC client differently, like via interceptors.)