Golang / GoLang System Architecture and Testing Interview Questions
How does service discovery and client-side load balancing work in a Go microservice system?
When service B needs to call service A, it must discover A's current addresses (since pods restart and scale). Go gRPC has built-in pluggable load balancing and name resolution for integrating with Consul, etcd, or Kubernetes DNS.
// Option 1: Kubernetes DNS + round-robin (simplest) // k8s headless service: userservice.default.svc.cluster.local // â resolves to ALL pod IPs, not just one VIP conn, err := grpc.NewClient( "dns:///userservice.default.svc.cluster.local:9090", grpc.WithDefaultServiceConfig(`{"loadBalancingPolicy":"round_robin"}`), grpc.WithTransportCredentials(insecure.NewCredentials()), ) // Option 2: consul service discovery import resolverv2 "github.com/mbobrovskyi/grpc-consul-resolver" resolverv2.RegisterDefault( resolverv2.NewResolver( "consul://localhost:8500/user-service", resolverv2.WithHealthCheck(true), ), ) // Option 3: manual custom resolver for testing / dev type staticResolver struct{} func (staticResolver) Build(target resolver.Target, cc resolver.ClientConn, opts resolver.BuildOptions) (resolver.Resolver, error) { addrs := []resolver.Address{ {Addr: "localhost:9090"}, {Addr: "localhost:9091"}, } cc.UpdateState(resolver.State{Addresses: addrs}) return &staticRes{cc: cc, addrs: addrs}, nil } // Load balancing policies in gRPC: // round_robin: cycle through all addresses // pick_first: always use first healthy address (default) // grpclb: server-side load balancing (deprecated) // rls: routing lookup service
Service mesh alternative: tools like Istio, Linkerd, and Cilium implement load balancing, circuit breaking, retries, and mTLS in a sidecar proxy — removing these concerns from application code entirely. The Go service makes plain gRPC calls; the mesh handles distribution transparently.
More Related questions...