Implementing Service Discovery

1. Using DNS-Based Discovery

TargetUse
dns:///host:portStandard DNS A/AAAA
SRV recordsOptional service+port discovery
Kubernetes headless svcReturns all pod IPs

2. Implementing Custom Resolver

InterfaceMethod
resolver.BuilderBuild, Scheme
resolver.ResolverResolveNow, Close
cc.UpdateStatePush address list to balancer

3. Registering Custom Resolver

Example: Register at init

func init() { resolver.Register(&consulBuilder{client: consulCli}) }
// dial: grpc.NewClient("consul:///user-service")

4. Using Consul for Discovery

StepDetail
Register serviceAgent HTTP API on startup
Health checkgRPC health endpoint
QueryHealth.Service(name, "", passingOnly, q)
WatchLong-poll with WaitIndex

5. Using etcd for Discovery

MechanismDetail
Put key with lease/services/user/<id> → ip:port
Keep-alive leaseAuto-deregister on crash
Watch prefixStream membership changes

6. Using Kubernetes Service Discovery

ApproachDetail
ClusterIP svcSingle VIP; L4 LB — defeats client-side LB
Headless svcDNS returns all pod IPs — enables round_robin
xDS / IstioControl plane pushes endpoints

7. Implementing Static Resolution

Example: Manual resolver with static list

r := manual.NewBuilderWithScheme("static")
r.InitialState(resolver.State{Addresses: []resolver.Address{
    {Addr: "10.0.0.1:50051"}, {Addr: "10.0.0.2:50051"},
}})
conn, _ := grpc.NewClient("static:///user-service",
    grpc.WithResolvers(r),
    grpc.WithDefaultServiceConfig(`{"loadBalancingConfig":[{"round_robin":{}}]}`),
)

8. Updating Resolver State

Example: Push new addresses

r.UpdateState(resolver.State{Addresses: latestAddrs})

9. Handling Service Updates

ConcernDetail
Graceful addBalancer connects new subchannel before using
Graceful removeDrain in-flight on removed subchannel
FlappingApply hysteresis in resolver

10. Testing Service Discovery

TestDetail
Manual resolverDrive state changes in unit tests
Failure injectionMark subchannels TRANSIENT_FAILURE
IntegrationSpin up Consul/etcd in docker