mirror of
				https://github.com/k3s-io/kubernetes.git
				synced 2025-10-31 05:40:42 +00:00 
			
		
		
		
	Merge pull request #102330 from tnqn/replicaset-optimization
Add controllerUID index to improve ReplicaSetController performance
This commit is contained in:
		| @@ -71,6 +71,10 @@ const ( | |||||||
|  |  | ||||||
| 	// The number of times we retry updating a ReplicaSet's status. | 	// The number of times we retry updating a ReplicaSet's status. | ||||||
| 	statusUpdateRetries = 1 | 	statusUpdateRetries = 1 | ||||||
|  |  | ||||||
|  | 	// controllerUIDIndex is the name for the ReplicaSet store's index function, | ||||||
|  | 	// which is to index by ReplicaSet's controllerUID. | ||||||
|  | 	controllerUIDIndex = "controllerUID" | ||||||
| ) | ) | ||||||
|  |  | ||||||
| // ReplicaSetController is responsible for synchronizing ReplicaSet objects stored | // ReplicaSetController is responsible for synchronizing ReplicaSet objects stored | ||||||
| @@ -98,6 +102,7 @@ type ReplicaSetController struct { | |||||||
| 	// rsListerSynced returns true if the pod store has been synced at least once. | 	// rsListerSynced returns true if the pod store has been synced at least once. | ||||||
| 	// Added as a member to the struct to allow injection for testing. | 	// Added as a member to the struct to allow injection for testing. | ||||||
| 	rsListerSynced cache.InformerSynced | 	rsListerSynced cache.InformerSynced | ||||||
|  | 	rsIndexer      cache.Indexer | ||||||
|  |  | ||||||
| 	// A store of pods, populated by the shared informer passed to NewReplicaSetController | 	// A store of pods, populated by the shared informer passed to NewReplicaSetController | ||||||
| 	podLister corelisters.PodLister | 	podLister corelisters.PodLister | ||||||
| @@ -150,6 +155,20 @@ func NewBaseController(rsInformer appsinformers.ReplicaSetInformer, podInformer | |||||||
| 		UpdateFunc: rsc.updateRS, | 		UpdateFunc: rsc.updateRS, | ||||||
| 		DeleteFunc: rsc.deleteRS, | 		DeleteFunc: rsc.deleteRS, | ||||||
| 	}) | 	}) | ||||||
|  | 	rsInformer.Informer().AddIndexers(cache.Indexers{ | ||||||
|  | 		controllerUIDIndex: func(obj interface{}) ([]string, error) { | ||||||
|  | 			rs, ok := obj.(*apps.ReplicaSet) | ||||||
|  | 			if !ok { | ||||||
|  | 				return []string{}, nil | ||||||
|  | 			} | ||||||
|  | 			controllerRef := metav1.GetControllerOf(rs) | ||||||
|  | 			if controllerRef == nil { | ||||||
|  | 				return []string{}, nil | ||||||
|  | 			} | ||||||
|  | 			return []string{string(controllerRef.UID)}, nil | ||||||
|  | 		}, | ||||||
|  | 	}) | ||||||
|  | 	rsc.rsIndexer = rsInformer.Informer().GetIndexer() | ||||||
| 	rsc.rsLister = rsInformer.Lister() | 	rsc.rsLister = rsInformer.Lister() | ||||||
| 	rsc.rsListerSynced = rsInformer.Informer().HasSynced | 	rsc.rsListerSynced = rsInformer.Informer().HasSynced | ||||||
|  |  | ||||||
| @@ -206,17 +225,14 @@ func (rsc *ReplicaSetController) getReplicaSetsWithSameController(rs *apps.Repli | |||||||
| 		return nil | 		return nil | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	allRSs, err := rsc.rsLister.ReplicaSets(rs.Namespace).List(labels.Everything()) | 	objects, err := rsc.rsIndexer.ByIndex(controllerUIDIndex, string(controllerRef.UID)) | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		utilruntime.HandleError(err) | 		utilruntime.HandleError(err) | ||||||
| 		return nil | 		return nil | ||||||
| 	} | 	} | ||||||
|  | 	relatedRSs := make([]*apps.ReplicaSet, 0, len(objects)) | ||||||
| 	var relatedRSs []*apps.ReplicaSet | 	for _, obj := range objects { | ||||||
| 	for _, r := range allRSs { | 		relatedRSs = append(relatedRSs, obj.(*apps.ReplicaSet)) | ||||||
| 		if ref := metav1.GetControllerOf(r); ref != nil && ref.UID == controllerRef.UID { |  | ||||||
| 			relatedRSs = append(relatedRSs, r) |  | ||||||
| 		} |  | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	// The if check is used to avoid the overhead for the KObjs call, see | 	// The if check is used to avoid the overhead for the KObjs call, see | ||||||
|   | |||||||
| @@ -36,6 +36,7 @@ import ( | |||||||
| 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" | 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" | ||||||
| 	"k8s.io/apimachinery/pkg/runtime" | 	"k8s.io/apimachinery/pkg/runtime" | ||||||
| 	"k8s.io/apimachinery/pkg/runtime/schema" | 	"k8s.io/apimachinery/pkg/runtime/schema" | ||||||
|  | 	"k8s.io/apimachinery/pkg/types" | ||||||
| 	"k8s.io/apimachinery/pkg/util/sets" | 	"k8s.io/apimachinery/pkg/util/sets" | ||||||
| 	"k8s.io/apimachinery/pkg/util/uuid" | 	"k8s.io/apimachinery/pkg/util/uuid" | ||||||
| 	"k8s.io/apimachinery/pkg/util/wait" | 	"k8s.io/apimachinery/pkg/util/wait" | ||||||
| @@ -438,6 +439,36 @@ func TestGetReplicaSetsWithSameController(t *testing.T) { | |||||||
| 	} | 	} | ||||||
| } | } | ||||||
|  |  | ||||||
|  | func BenchmarkGetReplicaSetsWithSameController(b *testing.B) { | ||||||
|  | 	stopCh := make(chan struct{}) | ||||||
|  | 	defer close(stopCh) | ||||||
|  | 	controller, informers := testNewReplicaSetControllerFromClient(clientset.NewForConfigOrDie(&restclient.Config{Host: "", ContentConfig: restclient.ContentConfig{GroupVersion: &schema.GroupVersion{Group: "", Version: "v1"}}}), stopCh, BurstReplicas) | ||||||
|  |  | ||||||
|  | 	targetRS := newReplicaSet(1, map[string]string{"foo": "bar"}) | ||||||
|  | 	targetRS.Name = "rs1" | ||||||
|  | 	targetRS.ObjectMeta.OwnerReferences[0].UID = "123456" | ||||||
|  | 	informers.Apps().V1().ReplicaSets().Informer().GetIndexer().Add(targetRS) | ||||||
|  | 	relatedRS := newReplicaSet(1, map[string]string{"foo": "bar"}) | ||||||
|  | 	relatedRS.Name = "rs2" | ||||||
|  | 	relatedRS.ObjectMeta.OwnerReferences[0].UID = "123456" | ||||||
|  | 	informers.Apps().V1().ReplicaSets().Informer().GetIndexer().Add(relatedRS) | ||||||
|  | 	for i := 0; i < 100; i++ { | ||||||
|  | 		unrelatedRS := newReplicaSet(1, map[string]string{"foo": fmt.Sprintf("baz-%d", i)}) | ||||||
|  | 		unrelatedRS.Name = fmt.Sprintf("rs-%d", i) | ||||||
|  | 		unrelatedRS.ObjectMeta.OwnerReferences[0].UID = types.UID(fmt.Sprintf("%d", i)) | ||||||
|  | 		informers.Apps().V1().ReplicaSets().Informer().GetIndexer().Add(unrelatedRS) | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	b.ReportAllocs() | ||||||
|  | 	b.ResetTimer() | ||||||
|  | 	for n := 0; n < b.N; n++ { | ||||||
|  | 		gotRSs := controller.getReplicaSetsWithSameController(targetRS) | ||||||
|  | 		if len(gotRSs) != 2 { | ||||||
|  | 			b.Errorf("Incorrect ReplicaSets number, expected 2, got: %d", len(gotRSs)) | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  |  | ||||||
| func TestPodControllerLookup(t *testing.T) { | func TestPodControllerLookup(t *testing.T) { | ||||||
| 	stopCh := make(chan struct{}) | 	stopCh := make(chan struct{}) | ||||||
| 	defer close(stopCh) | 	defer close(stopCh) | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user