@@ -42,11 +42,9 @@ import (
4242	"k8s.io/klog/v2" 
4343
4444	roundrobin "google.golang.org/grpc/balancer/roundrobin"  // named import (not blank) 
45- 	_ "google.golang.org/grpc/balancer/weightedroundrobin"  
45+ 	_ "google.golang.org/grpc/health"                          // Register health checking service 
4646	"google.golang.org/grpc/resolver" 
4747	dnsresolver "google.golang.org/grpc/resolver/dns"  // named import 
48- 	_ "google.golang.org/grpc/xds" 
49- 	_ "google.golang.org/grpc/xds/googledirectpath"  // Register xDS Google DirectPath components 
5048
5149	"k8s.io/apimachinery/pkg/runtime" 
5250	utilnet "k8s.io/apimachinery/pkg/util/net" 
@@ -103,12 +101,6 @@ func init() {
103101	resolver .Register (dnsresolver .NewBuilder ())
104102	resolver .SetDefaultScheme ("dns" )
105103	_  =  roundrobin .Name 
106- 
107- 	// Enable outlier detection support in gRPC 
108- 	// This is required for outlier_detection load balancing policy to work 
109- 	if  os .Getenv ("GRPC_EXPERIMENTAL_ENABLE_OUTLIER_DETECTION" ) ==  ""  {
110- 		os .Setenv ("GRPC_EXPERIMENTAL_ENABLE_OUTLIER_DETECTION" , "true" )
111- 	}
112104}
113105
114106// etcdClientDebugLevel translates ETCD_CLIENT_DEBUG into zap log level. 
@@ -338,22 +330,16 @@ var newETCD3Client = func(c storagebackend.TransportConfig) (*kubernetes.Client,
338330		// which seems to be what we want as the metrics will be collected on each attempt (retry) 
339331		grpc .WithChainUnaryInterceptor (grpcprom .UnaryClientInterceptor ),
340332		grpc .WithChainStreamInterceptor (grpcprom .StreamClientInterceptor ),
333+ 		// Use round-robin load balancing with health checking across all etcd endpoints. 
334+ 		// The DNS resolver will resolve the service name to individual etcd member IPs, 
335+ 		// and round-robin will distribute requests across them. gRPC health checking 
336+ 		// will proactively detect soft failures (slow responses, high error rates) in 
337+ 		// addition to hard failures detected by TCP keepalives. 
341338		grpc .WithDefaultServiceConfig (`{ 
342-   "loadBalancingConfig": [{ 
343-     "outlier_detection_experimental": { 
344-       "interval": "10s", 
345-       "base_ejection_time": "30s", 
346-       "max_ejection_time": "300s", 
347-       "max_ejection_percent": 50, 
348-       "failure_percentage_ejection": { 
349-         "threshold": 20, 
350-         "enforcement_percentage": 100, 
351-         "minimum_hosts": 3, 
352-         "request_volume": 5 
353-       }, 
354-       "child_policy": [{"round_robin": {}}] 
355-     } 
356-   }] 
339+   "loadBalancingConfig": [{"round_robin": {}}], 
340+   "healthCheckConfig": { 
341+     "serviceName": "" 
342+   } 
357343}` ),
358344	}
359345	if  utilfeature .DefaultFeatureGate .Enabled (genericfeatures .APIServerTracing ) &&  c .TracerProvider  !=  nil  {
@@ -367,10 +353,10 @@ var newETCD3Client = func(c storagebackend.TransportConfig) (*kubernetes.Client,
367353		dialOptions  =  append (dialOptions ,
368354			grpc .WithStatsHandler (otelgrpc .NewClientHandler (tracingOpts ... )))
369355	}
370- 	// Configure endpoints for cross-member outlier detection : 
371- 	// Assume the endpoint is a DNS name (e.g., "dns:///etcd.namespace.svc:2379" or just "etcd.namespace.svc:2379").  
372- 	// gRPC's DNS resolver will resolve all  IPs for the service and create subchannels to each,  
373- 	// enabling outlier detection to monitor and eject unhealthy members across the etcd cluster . 
356+ 	// Configure endpoints for DNS-based load balancing : 
357+ 	// Use DNS resolution to discover all etcd members. The DNS resolver will resolve the service  
358+ 	// name to individual etcd member  IPs, and round-robin load balancing will distribute requests  
359+ 	// across them. etcd's built-in health checking handles failure detection . 
374360	endpoints  :=  c .ServerList 
375361	useDNSResolver  :=  false 
376362
@@ -390,9 +376,9 @@ var newETCD3Client = func(c storagebackend.TransportConfig) (*kubernetes.Client,
390376	}
391377
392378	// IMPORTANT: Custom dialers bypass gRPC's resolver system. When using DNS-based resolution 
393- 	// for cross-member outlier detection , we must NOT use a custom dialer because it would 
394- 	// prevent the DNS  resolver from resolving the service name to individual etcd member IPs. 
395- 	// The custom dialer  is only needed for direct endpoint connections (non-DNS). 
379+ 	// for load balancing , we must NOT use a custom dialer because it would prevent the DNS  
380+ 	// resolver from resolving the service name to individual etcd member IPs. The custom dialer  
381+ 	// is only needed for direct endpoint connections (non-DNS). 
396382	klog .Infof ("if egressDialer != nil && !useDNSResolver" )
397383	if  egressDialer  !=  nil  &&  ! useDNSResolver  {
398384		dialer  :=  func (ctx  context.Context , addr  string ) (net.Conn , error ) {
@@ -408,7 +394,7 @@ var newETCD3Client = func(c storagebackend.TransportConfig) (*kubernetes.Client,
408394		}
409395		dialOptions  =  append (dialOptions , grpc .WithContextDialer (dialer ))
410396	} else  if  egressDialer  !=  nil  &&  useDNSResolver  {
411- 		klog .Warningf ("Egress dialer is configured but will be skipped for DNS-based outlier detection  to allow gRPC DNS resolver to function properly" )
397+ 		klog .Warningf ("Egress dialer is configured but will be skipped for DNS-based load balancing  to allow gRPC DNS resolver to function properly" )
412398	}
413399
414400	klog .Infof ("----------------Creating clientv3.Config with endpoints: %v" , endpoints )
0 commit comments