-
Notifications
You must be signed in to change notification settings - Fork 16
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
performance: minimize Update
calls
#1194
base: main
Are you sure you want to change the base?
Conversation
[APPROVALNOTIFIER] This PR is APPROVED This pull-request has been approved by: Tal-or The full list of commands accepted by this bot can be found here. The pull request process is described here
Needs approval from an approver in each of these files:
Approvers can indicate their approval by writing |
Update
calls
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Impressive PR. My only concern is to depend on external defaulter package we need to cut and paste here. Can we avoid it with smarter merge functions?
@@ -0,0 +1,310 @@ | |||
package setdefault |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
missing copyright boilerplate (hack/boilerplate.go.txt
)
what is the canonical name of the same functionality in other projects in the kube ecosystem? defaulter
maybe? Do we have a canonical name at all?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The functions are located as part of the API declaration package:
/~https://github.com/kubernetes/kubernetes/blob/e5976909c6fb129228a67515e0f86336a53884f0/pkg/apis/core/v1/zz_generated.defaults.go
// Merge the desired object with what actually exists | ||
merged, err := objState.Merge(objState.Existing, objState.Desired) | ||
merged, err := objState.Merge(objState.Existing, desiredWithDefault) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
another option could be to make our merge functions smarter. We should only copy the desired fields in the existing object. This allows us to avoid defaults (and the need to depend on defaulter) and was the original intent of the merge
package, which was however lost in the initial implementation.
We can take the chance to rethink the Compare
step. Can we do Merge+Compare
in one single go? Can the merging step infer if a field we care about changed during the merge?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Defining a list of fields we care about using a black/white list is possible however it has its own cons:
- We need to define the fields we care about which is not that easy because we don't know what will happen in case that a field "we didn't care about" is misconfigured, could it break anything?
- We need to write a custom compare/merge functions that will be smart enough to skip and focus on the fields according to our needs, which is basically similar to setting the defaults and goes through everything.
- What should we do if user is tampering with fields we didn't care about and messing things up? we'll never be able to fix it automatically, a manual intervention will be needed.
some historical context. I'm not against using |
Signed-off-by: Talor Itzhak <titzhak@redhat.com>
Many of the `Update` calls done by the operator are changing nothing. This is happening because the API server defaults some of the fields while our code leave them empty. This result in a diff in the comparison function and leads to redundant calls. This package purpose it to set the default values in our objects similar to what the API server is doing. The code is based on upstream code that is not in staging so we can't import it unfortunately. Signed-off-by: Talor Itzhak <titzhak@redhat.com>
d299325
to
f23a5b5
Compare
A script to automate the generation of default functions. In order to use, call: `make defaults` Signed-off-by: Talor Itzhak <titzhak@redhat.com>
call `make defaults` Signed-off-by: Talor Itzhak <titzhak@redhat.com>
Use the generated functions instead the one that we copy/pasted manually. This should make the maintenace and track of changes much easier. Signed-off-by: Talor Itzhak <titzhak@redhat.com>
The status is a subresource which is managed by other controllers and which we don't care about during the comparison for `Update`. So we suggest to merge the status fields from the existing object, (for objects that has status) to avoid diff during comparison. Signed-off-by: Talor Itzhak <titzhak@redhat.com>
add default function to the objectstate struct that will be called during the ApplyObject process. Signed-off-by: Talor Itzhak <titzhak@redhat.com>
use the default object created per each resource managed by the operator in the ObjectState struct. Signed-off-by: Talor Itzhak <titzhak@redhat.com>
Merge the IP configuration from the existing object, since those fields are being controlled by external operator. Signed-off-by: Talor Itzhak <titzhak@redhat.com>
Set defaults for initial object. Signed-off-by: Talor Itzhak <titzhak@redhat.com>
f23a5b5
to
eaafb55
Compare
Many of the
Update
calls done by the operatorare changing nothing.
This is happening because the API server defaults some of the fields
while our code leave them empty.
This result in a diff in the comparison function and leads to redundant calls.
This package purpose it to set the default values in our objects similar to what
the API server is doing.
The code is based on upstream code that is
not in staging so we can't import it unfortunately.
Instead we are pulling all the relevant files,
preforming some manipulations on them and generating using the code-generator,
similar to how k8s is doing it.
Then we are coping the generated files and calling them generated function from our code.
Below benchmarks shows the benefit of those changes:
Simple patch against
numaresources
CR (before change):Simple patch against
numaresources
CR (after change):Realistic benchmark against serial suite (before change):
Realistic benchmark against serial suite (after change):
NOTE: we must add a CI lane that tracks the amount of update call and failed if we're exceeding a certain threshold.
This is needed because atm we don't have a better way to track changes in the set-default logic of the API server.