mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-09-21 18:11:22 +00:00
Skip updating Endpoints and EndpointSlice if no relevant fields change
When comparing EndpointSubsets and Endpoints, we ignore the difference in ResourceVersion of Pod to avoid unnecessary updates caused by Pod updates that we don't care, e.g. annotation update. Otherwise periodic Service resync would intensively update Endpoints or EndpointSlice whose Pods have irrelevant change between two resyncs, leading to delay in processing newly created Services. In a scale cluster with thousands of such Endpoints, we observed 2 minutes of delay when the resync happens.
This commit is contained in:
@@ -490,8 +490,10 @@ func (e *Controller) syncService(ctx context.Context, key string) error {
|
||||
if _, ok := currentEndpoints.Labels[v1.IsHeadlessService]; ok {
|
||||
compareLabels = utillabels.CloneAndRemoveLabel(currentEndpoints.Labels, v1.IsHeadlessService)
|
||||
}
|
||||
// When comparing the subsets, we ignore the difference in ResourceVersion of Pod to avoid unnecessary Endpoints
|
||||
// updates caused by Pod updates that we don't care, e.g. annotation update.
|
||||
if !createEndpoints &&
|
||||
apiequality.Semantic.DeepEqual(currentEndpoints.Subsets, subsets) &&
|
||||
endpointutil.EndpointSubsetsEqualIgnoreResourceVersion(currentEndpoints.Subsets, subsets) &&
|
||||
apiequality.Semantic.DeepEqual(compareLabels, service.Labels) &&
|
||||
capacityAnnotationSetCorrectly(currentEndpoints.Annotations, currentEndpoints.Subsets) {
|
||||
klog.V(5).Infof("endpoints are equal for %s/%s, skipping update", service.Namespace, service.Name)
|
||||
|
@@ -319,6 +319,52 @@ func TestSyncEndpointsExistingEmptySubsets(t *testing.T) {
|
||||
endpointsHandler.ValidateRequestCount(t, 0)
|
||||
}
|
||||
|
||||
func TestSyncEndpointsWithPodResourceVersionUpdateOnly(t *testing.T) {
|
||||
ns := metav1.NamespaceDefault
|
||||
testServer, endpointsHandler := makeTestServer(t, ns)
|
||||
defer testServer.Close()
|
||||
pod0 := testPod(ns, 0, 1, true, ipv4only)
|
||||
pod1 := testPod(ns, 1, 1, false, ipv4only)
|
||||
endpoints := newController(testServer.URL, 0*time.Second)
|
||||
endpoints.endpointsStore.Add(&v1.Endpoints{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "foo",
|
||||
Namespace: ns,
|
||||
ResourceVersion: "1",
|
||||
},
|
||||
Subsets: []v1.EndpointSubset{{
|
||||
Addresses: []v1.EndpointAddress{
|
||||
{
|
||||
IP: pod0.Status.PodIPs[0].IP,
|
||||
NodeName: &emptyNodeName,
|
||||
TargetRef: &v1.ObjectReference{Kind: "Pod", Name: pod0.Name, Namespace: ns, ResourceVersion: "1"},
|
||||
},
|
||||
},
|
||||
NotReadyAddresses: []v1.EndpointAddress{
|
||||
{
|
||||
IP: pod1.Status.PodIPs[0].IP,
|
||||
NodeName: &emptyNodeName,
|
||||
TargetRef: &v1.ObjectReference{Kind: "Pod", Name: pod1.Name, Namespace: ns, ResourceVersion: "2"},
|
||||
},
|
||||
},
|
||||
Ports: []v1.EndpointPort{{Port: 8080, Protocol: "TCP"}},
|
||||
}},
|
||||
})
|
||||
endpoints.serviceStore.Add(&v1.Service{
|
||||
ObjectMeta: metav1.ObjectMeta{Name: "foo", Namespace: ns},
|
||||
Spec: v1.ServiceSpec{
|
||||
Selector: map[string]string{"foo": "bar"},
|
||||
Ports: []v1.ServicePort{{Port: 80, Protocol: "TCP", TargetPort: intstr.FromInt(8080)}},
|
||||
},
|
||||
})
|
||||
pod0.ResourceVersion = "3"
|
||||
pod1.ResourceVersion = "4"
|
||||
endpoints.podStore.Add(pod0)
|
||||
endpoints.podStore.Add(pod1)
|
||||
endpoints.syncService(context.TODO(), ns+"/foo")
|
||||
endpointsHandler.ValidateRequestCount(t, 0)
|
||||
}
|
||||
|
||||
func TestSyncEndpointsNewNoSubsets(t *testing.T) {
|
||||
ns := metav1.NamespaceDefault
|
||||
testServer, endpointsHandler := makeTestServer(t, ns)
|
||||
|
Reference in New Issue
Block a user